Sharding分片环境部署(详述)
前言:
Sharding是一种可以将数据分发到不同主机上的方法,主要是用于解决MongoDB巨大数据量和高吞吐量的问题。我们一开始使用单机,但是为了安全和一些读写分离改为副本集,但是业务增长快速的情况下,可能遇到很多性能上的问题;例如巨大的查询频率可能会耗尽所有CPU资源,高吞吐量可能使得I/O成为瓶颈。对于这些问题其实我们有两种方案:垂直扩展 和 水平扩展
- 垂直扩展:说白了就是增加单台机器的资源,用更多CPU,更大内存,使用SSD硬盘;但是硬件技术上的局限性可能导致最后还是无法满足你的业务需求
- 水平扩展:通过分离数据集和多服务器负载来实现,按需添加额外服务器可以更好的解决大数据量和大吞吐量的问题;
而分片就是为了实现水平扩展而生的集群架构
架构
Sharding分片架构一般由3部分组成:
- mongos server:路由节点,作为一个查询路由而存在,承接client端与分片服务器之前的数据传输(或者叫分发)
- config server: 配置节点,存储集群的配置信息,以及各个分片数据的元数据信息,3.2以后必须以replica set形式部署(简称
CSRS
) - shard server:分片节点,实际存储数据的服务器,每个分片节点根据片键的选择只持有集合的一部分数据。
官方架构图:
部署架构:
config server:
- 10.67.37.45:38001 (primary)
- 10.67.37.46:38001 (secondary)
- 10.67.37.47:38001 (secondary)
mongos server:
- 10.67.37.45:37000
- 10.67.37.46:37000
- 10.67.37.47:37000
shard1:
- 10.67.37.45:37001(primary)
- 10.67.37.46:37001 (secondary)
- 10.67.37.47:37001 (secondary)
shard2:
- 10.67.37.45:37002 (secondary)
- 10.67.37.46:37002 (primary)
- 10.67.37.47:37002 (secondary)
shard3:
- 10.67.37.45:37003 (secondary)
- 10.67.37.46:37003 (secondary)
10.67.37.47:37003 (primary)
部署步骤:
信息:
- OS: Redhat 7.6
- MongoDB version: mongod 4.0
- CPU: 8
- RAM: 48G
注:由于是测试环境,机器数量受限,所以上述15个节点服务均部署在3台服务器上,生产环境的话可以根据自己情况部署;
另:因为本教程部署的是开启认证模式的cluster sharding架构,所以要求cluster中的所有成员必须使用一致的内部认证机制和设定;
1.部署配置服务节点config server复制集
1.1 创建相应目录
(在10.67.37.45上执行下述操作)
[mongo@wqdcsrv090 shard]$ cd /data/johnny/shard
[mongo@wqdcsrv091 shard]$ mkdir cfg --配置文件存放目录
[mongo@wqdcsrv090 shard]$ mkdir -p configsvr/dbdata/ --数据目录
[mongo@wqdcsrv090 shard]$ mkdir -p configsvr/logs/ --日志目录
[mongo@wqdcsrv090 shard]$ mkdir -p configsvr/keyfile/ --keyfile文件目录
[mongo@wqdcsrv090 shard]$ mkdir -p configsvr/pid/ --进程id存放目录
1.2 配置启动文件
编辑config server的配置文件/data/johnny/shard/cfg/config.cnf
,内容如下
除了参数bindIp
需要根据不同服务器IP地址修改,其他不变。
storage:
dbPath: /data/johnny/shard/configsvr/dbdata
journal:
enabled: true
commitIntervalMs: 50
directoryPerDB: true
engine: wiredTiger
wiredTiger:
engineConfig:
directoryForIndexes: true
systemLog:
quiet: false
path: /data/johnny/shard/configsvr/logs/configsvr.log
destination: file
logAppend: true
logRotate: rename
processManagement:
fork: true
pidFilePath: /data/johnny/shard/configsvr/pid/configsvr.pid
net:
port: 38001
maxIncomingConnections: 1000
wireObjectCheck: true
bindIp: localhost,10.67.37.45 #注意此参数需要根据不同的服务器IP进行修改
security:
keyFile: /data/johnny/shard/configsvr/keyfile/security
replication:
oplogSizeMB: 3072
replSetName: configsvr
sharding:
clusterRole: configsvr
注:
如果不太清楚上述参数的意义,请参考官方文档启动参数说明
1.3 创建keyfile文件
[mongo@wqdcsrv090 keyfile]$ pwd
/data/johnny/shard/configsvr/keyfile
[mongo@wqdcsrv090 keyfile]$ openssl rand -base64 756 > security
[mongo@wqdcsrv090 keyfile]$ chmod 400 security
[mongo@wqdcsrv090 keyfile]$ ls -l
total 4
-r-------- 1 mongo mongo 1024 Sep 25 15:53 security
注:
分片架构中所有的节点必须使用相同内容的security文件,3.6版本后文件权限注意是400,之前版本是600;
1.4 启动config server进程
[mongo@wqdcsrv090 shard]$ /apps/mongodb4.0/bin/mongod -f /data/johnny/shard/cfg/config.cnf
about to fork child process, waiting until server is ready for connections.
forked process: 5652
child process started successfully, parent exiting
出现上述信息表示启动成功。
1.5 部署其他config server
请根据上述1.1 ~ 1.4步骤部署其他两个config server的节点(10.67.37.46:38001, 10.67.37.47:38001),务必注意security文件就不需要重新创建了直接copy到其他服务器即可;
1.6 初始化config server复制集
待上述3个config server节点都启动成功后,进行复制集初始化操作,请使用localhost接口登录任意一台38001端口实例(因为已经开启了keyfile内部认证,所以在没有创建任何管理员用户之前只能通过localhost接口特性来登录)
[mongo@wqdcsrv090 shard]$ /apps/mongodb4.0/bin/mongo localhost:38001/admin
MongoDB shell version v4.0.10
connecting to: mongodb://localhost:38001/admin?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("6ed4375b-a95c-47e6-8a03-f0ae04328b31") }
MongoDB server version: 4.0.10
> rs.initiate(
{
_id: "configsvr",
configsvr: true,
members: [
{ _id : 0, host : "10.67.37.45:38001",priority:2 },
{ _id : 1, host : "10.67.37.46:38001" },
{ _id : 2, host : "10.67.37.47:38001" }
]
}
)
configsvr:PRIMARY>
待10秒钟之后,将会选举出primary节点,此时config server的复制集部署完毕,可以通过命令rs.status()查看集群状态
2.部署分片服务节点shard
部署分片shard1
(在10.67.37.45上执行下述操作)
2.1 创建shard1文件目录
[mongo@wqdcsrv090 shard]$ cd /data/johnny/shard
[mongo@wqdcsrv090 shard]$ mkdir -p shard1/dbdata
[mongo@wqdcsrv090 shard]$ mkdir -p shard1/logs
[mongo@wqdcsrv090 shard]$ mkdir -p shard1/keyfile
[mongo@wqdcsrv090 shard]$ mkdir -p shard1/pid
2.2 shard1配置文件
配置shard2,shard3时注意修改文件目录名称,以及端口号
storage:
dbPath: /data/johnny/shard/shard1/dbdata
journal:
enabled: true
commitIntervalMs: 50
directoryPerDB: true
engine: wiredTiger
wiredTiger:
engineConfig:
cacheSizeGB: 2
directoryForIndexes: true
systemLog:
quiet: false
path: /data/johnny/shard/shard1/logs/shard1.log
destination: file
logAppend: true
logRotate: rename
processManagement:
fork: true
pidFilePath: /data/johnny/shard/shard1/pid/shard1.pid
net:
port: 37001
maxIncomingConnections: 1000
wireObjectCheck: true
bindIp: localhost,10.67.37.45
security:
keyFile: /data/johnny/shard/shard1/keyfile/security
replication:
oplogSizeMB: 3072
replSetName: shard1
sharding:
clusterRole: shardsvr
2.3 启动shard1的mongod进程
[mongo@wqdcsrv090 shard]$ /apps/mongodb4.0/bin/mongod -f /data/johnny/shard/cfg/shard1.cnf
2.4 启动分片shard1的其他节点:
请根据上述2.1 ~ 2.3步骤部署shard1分片的其他两个节点(10.67.37.46:37001, 10.67.37.47:37001),务必注意security文件就不需要重新创建了直接copy到其他服务器即可;
2.5 初始化分片shard1的复制集
待上述shard1分片的3个server节点都启动成功后,进行shard1分片复制集的初始化操作
登录10.67.37.45上的37001实例
[mongo@wqdcsrv090 shard]$ /apps/mongodb4.0/bin/mongo localhost:37001/admin
MongoDB shell version v4.0.10
connecting to: mongodb://localhost:37001/admin?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("3f0b2538-c52a-4a1c-a601-92c44fb7a902") }
MongoDB server version: 4.0.10
> rs.initiate(
... {
... _id: "shard1",
... members: [
... { _id : 0, host : "10.67.37.45:37001",priority:2 },
... { _id : 1, host : "10.67.37.46:37001" },
... { _id : 2, host : "10.67.37.47:37001" }
... ]
... }
... )
{ "ok" : 1 }
shard1:PRIMARY>
可以通过命令rs.status
查看复制集各个成员状态, 这里我们使用priority:2将10.67.37.45:37001节点优先指定为primary角色;
2.6 创建分片shard1的本地管理员
登录到主节点的admin库,利用localhost exception特性即 使用mongo -h localhost37001
登录数据库:,创建第一个用户(此用户至少包含userAdminAnyDatabase权限),此用户是为了对于以后单独维护分片复制集而用,请不要使用此用户单独登录某个分片进行数据的DML操作;
shard1:PRIMARY> db.createUser({
user:"dba",
pwd:"admin123",
roles:[{role:"root",db:"admin"}]
})
2.7 部署其他分片shard2,shard3
请根据步骤2.1 ~ 2.6, 部署分片shard2,shard3,注意在部署时修改对应复制集名称、目录名称等。
对于其他两个分片复制集,建议根据如下初始化方案:
shard2:
rs.initiate(
{
_id: "shard2",
members: [
{ _id : 0, host : "10.67.37.45:37002" },
{ _id : 1, host : "10.67.37.46:37002",priority:2 },
{ _id : 2, host : "10.67.37.47:37002" }
]
}
)
shard3:
rs.initiate(
{
_id: "shard3",
members: [
{ _id : 0, host : "10.67.37.45:37003" },
{ _id : 1, host : "10.67.37.46:37003" },
{ _id : 2, host : "10.67.37.47:37003",priority:2 }
]
}
)
- shard2: 10.67.37.46:37002(primary)
- shard3: 10.67.37.47:37003(primary)
注:
不同分片初始化时,请注意修改_id的名称,否则会报错;
3. 部署路由服务节点mongos
3.1 创建目录
mongos服务都是单独运行的,不需要也不能配置成复制集形式,但是为了路由节点的高可用性,最好建立多个mongos节点
如下操作在10.67.37.45上操作
[mongo@wqdcsrv090 shard]$ cd /data/johnny/shard
[mongo@wqdcsrv090 shard]$ mkdir -p mongos/logs
[mongo@wqdcsrv090 shard]$ mkdir -p mongos/keyfile
[mongo@wqdcsrv090 shard]$ mkdir -p mongos/pid
注:
因为mongos服务不需要存储数据,所以我们不需要创建dbdata数据目录
3.2 mongos路由服务的配置文件
systemLog:
quiet: false
path: /data/johnny/shard/mongos/logs/mongos.log
destination: file
logAppend: true
logRotate: rename
processManagement:
fork: true
pidFilePath: /data/johnny/shard/mongos/pid/mongos.pid
net:
port: 37000
maxIncomingConnections: 3000
wireObjectCheck: true
bindIp: localhost,10.67.37.45
security:
keyFile: /data/johnny/shard/mongos/keyfile/security
sharding:
configDB: configsvr/10.67.37.45:38001,10.67.37.46:38001,10.67.37.47:38001
注:
configDB参数这里填写的是config server复制集的信息,configsvr是复制集名称;
因为mongos不存放数据,所以不需要storage的相关参数。
3.3 启动mongos进程
[mongo@wqdcsrv090 cfg]$ /apps/mongodb4.0/bin/mongos -f /data/johnny/shard/cfg/mongos.cnf
about to fork child process, waiting until server is ready for connections.
forked process: 25980
child process started successfully, parent exiting
注:
路由服务进程启动时,使用的是mongos程序,而不是mongod,这里一定要注意;如果这里无法启动,请注意观看log日志文件;
3.4 部署其他mongos节点
请使用步骤3.1 ~ 3.3在其他两个服务器(10.67.37.46,10.67.37.47)上部署mongos进程,以提供路由的HA高可用;
3.5 创建cluster集群的管理员账号
注意,这次创建的管理员与上面创建的分片local账号dba不一样,下面要创建的账号是会存放到config server上,而并非在各个分片上;此账号是用来管理整个cluster集群的。
[mongo@wqdcsrv090 cfg]$ /apps/mongodb4.0/bin/mongo localhost:37000/admin
MongoDB shell version v4.0.10
connecting to: mongodb://localhost:37000/admin?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("2182380b-d614-42a0-8f9f-b1f760f2cc1e") }
MongoDB server version: 4.0.10
mongos> db.createUser({
... user:"root",
... pwd:"admin123",
... roles:[{role:"root",db:"admin"}]
... })
mongos>
4. 添加分片
虽然上述我们部署好了shard1,shard2,shard3的复制集架构,但是其实并没有加入到cluster集群中,我们需要通过mongos将各个分片节点加入到集群中;使用刚才创建的集群管理账号root,登录到mongos的实例(37000端口)
[mongo@wqdcsrv090 cfg]$ /apps/mongodb4.0/bin/mongo localhost:37000/admin -uroot -padmin123
MongoDB shell version v4.0.10
connecting to: mongodb://localhost:37000/admin?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("a2d6d30d-c0e3-4d18-be1f-22bdd9f118a6") }
MongoDB server version: 4.0.10
mongos> sh.addShard("shard1/10.67.37.45:37001,10.67.37.46:37001,10.67.37.47:37001") //添加分片shard1
{
"shardAdded" : "shard1",
"ok" : 1, //表示添加分片成功
"operationTime" : Timestamp(1569479300, 8),
"$clusterTime" : {
"clusterTime" : Timestamp(1569479300, 8),
"signature" : {
"hash" : BinData(0,"soCeJXEgzeQlO8J7nJjGM3CjGcM="),
"keyId" : NumberLong("6740522498976120853")
}
}
}
mongos> sh.addShard("shard2/10.67.37.45:37002,10.67.37.46:37002,10.67.37.47:37002") //添加分片shard2
mongos> sh.addShard("shard3/10.67.37.45:37003,10.67.37.46:37003,10.67.37.47:37003") //添加分片shard3
当你完成添加分片后可以通过命令sh.status()
查看集群状态
mongos> sh.status()
--- Sharding Status ---
sharding version: { //cluster配置的基本信息
"_id" : 1,
"minCompatibleVersion" : 5,
"currentVersion" : 6, //当前config server的版本
"clusterId" : ObjectId("5d8b2580cb888b1fa65f6ad6") //整个cluster集群的一个标识符id
}
shards: //当前各个分片的成员,state:1表示此分片可以被识别,否则为0
{ "_id" : "shard1", "host" : "shard1/10.67.37.45:37001,10.67.37.46:37001,10.67.37.47:37001", "state" : 1 }
{ "_id" : "shard2", "host" : "shard2/10.67.37.45:37002,10.67.37.46:37002,10.67.37.47:37002", "state" : 1 }
{ "_id" : "shard3", "host" : "shard3/10.67.37.45:37003,10.67.37.46:37003,10.67.37.47:37003", "state" : 1 }
active mongoses:
"4.0.10" : 3 //表示当前活跃的mongos数量(最近60秒内ping的结果)
autosplit: //自动分裂是否开启
Currently enabled: yes
balancer: //平衡器相关状态信息
Currently enabled: yes //是否开启
Currently running: no //当前是否在运行
Failed balancer rounds in last 5 attempts: 0 //最近5分钟chunk迁移失败的次数
Migration Results for the last 24 hours: //最近24小时的迁移结果信息
No recent migrations
databases: //当前启动分片的库信息
{ "_id" : "config", "primary" : "config", "partitioned" : true }
config.system.sessions
shard key: { "_id" : 1 }
unique: false
balancing: true
chunks:
shard1 1
{ "_id" : { "$minKey" : 1 } } -->> { "_id" : { "$maxKey" : 1 } } on : shard1 Timestamp(1, 0)
5. 如何对表进行分片
上述所有操作都完成,我们的分片架构就算是部署完成了,但是如果想要使用上分片特性,我们需要对某个表进行开启分片的动作;
mongos> sh.enableSharding("testdb") //需要首先对库进行分片功能启动
mongos> sh.shardCollection("testdb.t1",{age:1}) //对库下的某个表进行分片,片键选择是age:1,代表的是范围分片
当你对testdb.t1表进行insert操作时,会根据age值而被路由插入到不同的分片节点上,可以使用如下脚本简单循环插入一批数据
mongos> for(var i=2;i<100000;i++){var a = Math.floor((Math.random()*100)+1);db.t1.insert({_id:i,age:a,name:"johnny"});}
注:
因为分片架构是以chunk为一个单元进行迁移的,默认chunkSize是64M,也就是说只有一个chunk块达到64M后才会进行分裂,而当不同分片间的chunk数量差达到2以上时才会引起balancer进行自动迁移;
参考官网地址:
Deploy a Sharding
Deploy a Sharding with Access Control