发布时间:2021-11-14作者:laosun阅读(1469)
想从网络上查阅一些docker-compose搭建mongo分片的教程不少,可是发现完整的太少了,多机版的更是少之又少,所以出一片文章供大家参考。
MongoDB副本集和分片 各个服务
mongos层:请求的入口,是router的角色,相当于监听,负责将请求分发到对应的存储数据的shard上,多副本冗余 config server层:记录了mongos中使用到的元数据,自动向mongos同步最新的集群配置,多副本冗余 shard主节点层:将数据分片,数据库拆分,并将其分散在不同的机器上,原理是将整个数据集合切块块分散到各个shard中,每个shard只负责总数据的一部分,通过一个均衡器来对各个shard均衡,多副本冗余 shard副本层:是shard的备份,多副本冗余 shard仲裁层:用于仲裁,不存储数据,使用最小的资源,需要基数个仲裁角色,且不能放在同一设备上
为了更清晰方便的操作,这里提前准备好三台机器
192.168.0.121 虚拟机 192.168.0.122 虚拟机 192.168.0.123 虚拟机
三台机器的操作目录均为:/usr/local/docker/mongosvr 下
在三台机器上分别创建目录文件夹
mkdir data mongos shard1 shard2 shard3
MongoDB使用keyfile认证,副本集中的每个mongod实例使用keyfile内容作为认证其他成员的共享密码。mongod实例只有拥有正确的keyfile才可以加入副本集。
keyFile的内容必须是6到1024个字符的长度,且副本集所有成员的keyFile内容必须相同。
有一点要注意是的:在UNIX系统中,keyFile必须没有组权限或完全权限(也就是权限要设置成X00的形式)。Windows系统中,keyFile权限没有被检查。
可以使用任意方法生成keyFile。例如,如下操作使用openssl生成复杂的随机的1024个字符串。然后使用chmod修改文件权限,只给文件拥有者提供读权限。
# 400权限是要保证安全性,否则mongod启动会报错 # 存放目录随意,只要对应yaml文件中的地址即可。 openssl rand -base64 756 > key.file chmod 400 key.file
编写docker-compose.yaml文件,如下
version: '3.9' networks: mongo-network: external: false services: # 配置服务器configsvr rs_config_server: image: mongo:latest networks: - mongo-network container_name: rs_config_server restart: always ports: - 27019:27019 command: --configsvr --replSet "rs_config_server" --bind_ip_all volumes: - ${PWD}/data/db:/data/db - ${PWD}/data/configdb:/data/configdb - ${PWD}/key.file:/data/mongodb/key.file # shard分片1 rs_shard_server_01: image: mongo:latest networks: - mongo-network container_name: rs_shard_server_01 restart: always ports: - 27118:27018 command: --shardsvr --replSet "rs_shard_server_01" --bind_ip_all volumes: - ${PWD}/shard1/db:/data/db - ${PWD}/shard1/configdb:/data/configdb - ${PWD}/key.file:/data/mongodb/key.file # shard分片2 rs_shard_server_02: image: mongo:latest networks: - mongo-network container_name: rs_shard_server_02 restart: always ports: - 27218:27018 command: --shardsvr --replSet "rs_shard_server_02" --bind_ip_all volumes: - ${PWD}/shard2/db:/data/db - ${PWD}/shard2/configdb:/data/configdb - ${PWD}/key.file:/data/mongodb/key.file # shard分片3 rs_shard_server_03: image: mongo:latest networks: - mongo-network container_name: rs_shard_server_03 restart: always ports: - 27318:27018 command: --shardsvr --replSet "rs_shard_server_03" --bind_ip_all volumes: - ${PWD}/shard3/db:/data/db - ${PWD}/shard3/configdb:/data/configdb - ${PWD}/key.file:/data/mongodb/key.file # 配置路由 mongos rs_mongos_server: image: mongo:latest networks: - mongo-network container_name: rs_mongos_server restart: always ports: - 27017:27017 # 这里的 rs_config_server 是 配置的 --replSet "rs_config_server" # 将三台机器的configsvr都写在这个位置 command: mongos --configdb rs-config-server/192.168.0.121:27019,192.168.0.122:27019,192.168.0.123:27019 --bind_ip_all volumes: - ${PWD}/mongos/db:/data/db - ${PWD}/mongos/configdb:/data/configdb - ${PWD}/key.file:/data/mongodb/key.file
目录目录如下图所示:
以上操作在三台机器上均操作一遍,保持目录结构一模一样,无需改动任何地方。
三台机器均需要启动,启动方式如下:
# 目录结构依旧在/usr/local/docker/mongosvr目录下 cd /usr/local/docker/mongosvr # 启动指令 docker-compose -f docker-compose.yaml up -d (这里yaml文件名定义成了docker-compose.yaml,所以启动时无需指定-f) docker-compose up -d # 停止指令 docker-compose -f docker-compose.yaml (这里yaml文件名定义成了docker-compose.yaml,所以启动时无需指定-f) # docker-compose down
启动方式如下所示:
都启动成功后,我们现在来进行初始化配置,进行副本集、分片、路由的关联和初始化。
首先我们选择任意一台机器,我这里选择了192.168.0.121第一台机器进行操作(只在一台机器操作,不可三台机器都操作)
初始化配置服务器
# 进入rs_config_server容器 docker exec -it rs_config_server bash # 登录mongo,这里的端口号不用解释了吧,docker-compose.yaml文件和使用docker ps 都能查看到 mongo --host 192.168.0.121 --port 27019 # 执行初始化语句,配置 mongo config rs.initiate({ _id: "rs_config_server", configsvr: true, members: [ { _id : 0, host : "192.168.0.121:27019" }, { _id : 1, host : "192.168.0.122:27019" }, { _id : 2, host : "192.168.0.123:27019" }, ] }); # 设置完成后,可以使用以下指令查看状态 rs.status()
执行方式如下图所示:
我们可以看到三台config已经出现了变化。
以下标红的地方注意,别写错。执行 rs.initiate 后,可以观察一会,让系统自动选出primary节点。
初始化分片1
# 进入 rs_shard_server_01 容器 docker exec -it rs_shard_server_01 bash # 登录mongo mongo --host 192.168.0.121 --port 27118 # 执行初始化语句,配置 mongo 分片1 # 也是可以设置裁决节点的,只需要在任意一个节点后增加arbiterOnly:true即可。 # 比如:{ _id : 2, host : "192.168.0.123:27118", arbiterOnly:true } rs.initiate({ _id: "rs_shard_server_01", members: [ { _id : 0, host : "192.168.0.121:27118" }, { _id : 1, host : "192.168.0.122:27118" }, { _id : 2, host : "192.168.0.123:27118" }, ] }); # 分片设置完成后,可以使用以下指令查看状态 rs.status()
初始化分片2
# 进入 rs_shard_server_01 容器 docker exec -it rs_shard_server_02 bash # 登录mongo mongo --host 192.168.0.121 --port 27218 # 执行初始化语句,配置 mongo 分片2 # 也是可以设置裁决节点的,只需要在任意一个节点后增加arbiterOnly:true即可。 # 比如:{ _id : 2, host : "192.168.0.123:27218", arbiterOnly:true } rs.initiate({ _id: "rs_shard_server_02", members: [ { _id : 0, host : "192.168.0.121:27218" }, { _id : 1, host : "192.168.0.122:27218" }, { _id : 2, host : "192.168.0.123:27218" }, ] }); # 分片设置完成后,可以使用以下指令查看状态 rs.status()
初始化分片3
# 进入 rs_shard_server_01 容器 docker exec -it rs_shard_server_03 bash # 登录mongo mongo --host 192.168.0.121 --port 27318 # 执行初始化语句,配置 mongo 分片3 # 也是可以设置裁决节点的,只需要在任意一个节点后增加arbiterOnly:true即可。 # 比如:{ _id : 2, host : "192.168.0.123:27318", arbiterOnly:true } # 指定设置主副节点,使用priority,设置优先级,值大的优先设置主节点 # 比如:{ _id : 0, host : "192.168.0.121:27318", priority:5 }, rs.initiate({ _id: "rs_shard_server_03", members: [ { _id : 0, host : "192.168.0.121:27318" }, { _id : 1, host : "192.168.0.122:27318" }, { _id : 2, host : "192.168.0.123:27318" }, ] }); # 分片设置完成后,可以使用以下指令查看状态 rs.status()
我们使用 rs.status()来查看一下 rs_shard_server_01 的状态吧,简单看一下。
{ "set" : "rs_shard_server_01", "date" : ISODate("2021-11-03T05:20:57.821Z"), "myState" : 1, "term" : NumberLong(1), "syncSourceHost" : "", "syncSourceId" : -1, "heartbeatIntervalMillis" : NumberLong(2000), "majorityVoteCount" : 2, "writeMajorityCount" : 2, "votingMembersCount" : 3, "writableVotingMembersCount" : 3, "optimes" : { "lastCommittedOpTime" : { "ts" : Timestamp(1635916848, 1), "t" : NumberLong(1) }, "lastCommittedWallTime" : ISODate("2021-11-03T05:20:48.424Z"), "readConcernMajorityOpTime" : { "ts" : Timestamp(1635916848, 1), "t" : NumberLong(1) }, "appliedOpTime" : { "ts" : Timestamp(1635916848, 1), "t" : NumberLong(1) }, "durableOpTime" : { "ts" : Timestamp(1635916848, 1), "t" : NumberLong(1) }, "lastAppliedWallTime" : ISODate("2021-11-03T05:20:48.424Z"), "lastDurableWallTime" : ISODate("2021-11-03T05:20:48.424Z") }, "lastStableRecoveryTimestamp" : Timestamp(1635916798, 1), "electionCandidateMetrics" : { "lastElectionReason" : "electionTimeout", "lastElectionDate" : ISODate("2021-11-03T05:12:58.325Z"), "electionTerm" : NumberLong(1), "lastCommittedOpTimeAtElection" : { "ts" : Timestamp(0, 0), "t" : NumberLong(-1) }, "lastSeenOpTimeAtElection" : { "ts" : Timestamp(1635916368, 1), "t" : NumberLong(-1) }, "numVotesNeeded" : 2, "priorityAtElection" : 1, "electionTimeoutMillis" : NumberLong(10000), "numCatchUpOps" : NumberLong(0), "newTermStartDate" : ISODate("2021-11-03T05:12:58.338Z"), "wMajorityWriteAvailabilityDate" : ISODate("2021-11-03T05:12:59.766Z") }, "members" : [ { "_id" : 0, "name" : "192.168.0.121:27118", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 1151, "optime" : { "ts" : Timestamp(1635916848, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2021-11-03T05:20:48Z"), "syncSourceHost" : "", "syncSourceId" : -1, "infoMessage" : "", "electionTime" : Timestamp(1635916378, 1), "electionDate" : ISODate("2021-11-03T05:12:58Z"), "configVersion" : 1, "configTerm" : 1, "self" : true, "lastHeartbeatMessage" : "" }, { "_id" : 1, "name" : "192.168.0.122:27118", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 489, "optime" : { "ts" : Timestamp(1635916848, 1), "t" : NumberLong(1) }, "optimeDurable" : { "ts" : Timestamp(1635916848, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2021-11-03T05:20:48Z"), "optimeDurableDate" : ISODate("2021-11-03T05:20:48Z"), "lastHeartbeat" : ISODate("2021-11-03T05:20:56.963Z"), "lastHeartbeatRecv" : ISODate("2021-11-03T05:20:56.228Z"), "pingMs" : NumberLong(0), "lastHeartbeatMessage" : "", "syncSourceHost" : "192.168.0.121:27118", "syncSourceId" : 0, "infoMessage" : "", "configVersion" : 1, "configTerm" : 1 }, { "_id" : 2, "name" : "192.168.0.123:27118", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 489, "optime" : { "ts" : Timestamp(1635916848, 1), "t" : NumberLong(1) }, "optimeDurable" : { "ts" : Timestamp(1635916848, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2021-11-03T05:20:48Z"), "optimeDurableDate" : ISODate("2021-11-03T05:20:48Z"), "lastHeartbeat" : ISODate("2021-11-03T05:20:56.963Z"), "lastHeartbeatRecv" : ISODate("2021-11-03T05:20:56.228Z"), "pingMs" : NumberLong(0), "lastHeartbeatMessage" : "", "syncSourceHost" : "192.168.0.121:27118", "syncSourceId" : 0, "infoMessage" : "", "configVersion" : 1, "configTerm" : 1 } ], "ok" : 1, "$clusterTime" : { "clusterTime" : Timestamp(1635916848, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } }, "operationTime" : Timestamp(1635916848, 1) }
# 题外话 # 如果是SECONDARY节点,用slaveOk命令允许查询操作。 rs_shard_server_03:SECONDARY> rs.slaveOk() rs_shard_server_03:SECONDARY> rs.status()
# 进入 rs_mongos_server 容器 docker exec -it rs_mongos_server bash # 登录mongo mongo --host 192.168.0.121 --port 27017 # 执行初始化语句,配置 mongo router 路由信息 sh.addShard("rs_shard_server_01/192.168.0.121:27118,192.168.0.122:27118,192.168.0.123:27118"); sh.addShard("rs_shard_server_02/192.168.0.121:27218,192.168.0.122:27218,192.168.0.123:27218"); sh.addShard("rs_shard_server_03/192.168.0.121:27318,192.168.0.122:27318,192.168.0.123:27318"); # 执行成功后会显示如下打印信息 mongos> sh.addShard("rs_shard_server_03/192.168.0.121:27318,192.168.0.122:27318,192.168.0.123:27318"); { "shardAdded" : "rs_shard_server_03", "ok" : 1, "$clusterTime" : { "clusterTime" : Timestamp(1635917549, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } }, "operationTime" : Timestamp(1635917548, 3) } mongos> # 路由设置完成后,可以使用以下指令查看状态 mongos> sh.status() --- Sharding Status --- sharding version: { "_id" : 1, "minCompatibleVersion" : 5, "currentVersion" : 6, "clusterId" : ObjectId("61821955f12d632a3b31b26e") } shards: { "_id" : "rs_shard_server_01", "host" : "rs_shard_server_01/192.168.0.121:27118,192.168.0.122:27118,192.168.0.123:27118", "state" : 1, "topologyTime" : Timestamp(1635917525, 2) } { "_id" : "rs_shard_server_02", "host" : "rs_shard_server_02/192.168.0.121:27218,192.168.0.122:27218,192.168.0.123:27218", "state" : 1, "topologyTime" : Timestamp(1635917544, 1) } { "_id" : "rs_shard_server_03", "host" : "rs_shard_server_03/192.168.0.121:27318,192.168.0.122:27318,192.168.0.123:27318", "state" : 1, "topologyTime" : Timestamp(1635917548, 1) } active mongoses: "5.0.3" : 3 autosplit: Currently enabled: yes balancer: Currently enabled: yes Currently running: no Failed balancer rounds in last 5 attempts: 0 Migration results for the last 24 hours: No recent migrations databases: { "_id" : "config", "primary" : "config", "partitioned" : true }
截止到目前为止,MongoDB的副本集和分片高可用已经配置完成。
# 任意一节点操作 # 进入mongos 容器中 docker exec -it rs_mongos_server bash # 连接mongos mongo --host 192.168.0.121 --port 27017 use admin # 使用testdb1库 # 循环插入数据到testdb1库的tab1集合中的键id中 # 该库对应的该集合对应的该键被设置成了分片 # 查看分片情况 # testdb1开启分片功能 db.runCommand( { enablesharding : "testdb1"}); db.runCommand( { shardcollection : "testdb1.tab1",key : {id: 1} } ) # 添加数据 use testdb1; for(var i=1;i<=20000;i++) db.tab1.save({id:i,"test1":"testval1"}); db.tab1.stats(); exit
分别在三个主机上操作配置库、插入测试数据、查看测试数据
验证了副本同步,最后的显示结果看到 “sharded” : true 表示分片也是成功的
# 在任意mongos节点操作 # 进入mongos 容器中 docker exec -it rs_mongos_server bash # 连接mongos mongo --host 192.168.0.121 --port 27017 mongos> use admin switched to db admin mongos> show tables # 添加两个管理员账号,一个系统管理员:system 一个数据库管理员:administrator # 先添加系统管理员账号,用来管理用户 db.createUser({user:"root",pwd:"root",roles:[{role:"root",db:"admin"}]}) # 添加数据库管理员,用来管理所有数据库 db.createUser({user:'administrator', pwd:'administrator', roles:[{role:"userAdminAnyDatabase",db:"admin"}]}) # 添加管理员用户认证,认证之后才能管理所有数据库 db.auth('administrator','administrator') # 退出,用刚才创建的账号进行登录(两个都测试一下) mongo 192.168.0.121:27017 -u root -proot --authenticationDatabase admin mongo 192.168.0.121:27017 -u administrator -padministrator --authenticationDatabase admin
常用命令列表
# 数据库 命令 db.serverStatus().connections; //连接数查看 show collections //查看表信息 db.test_shard.find().count() //查看table1数据长度 db.test_shard.remove({}) //删除数据表 db.stats() //查看所有的分片服务器状态 db.adminCommand( { listShards: 1 } ) //分片列表 db.test_shard.find({ age: 36 }).explain() //精确查询 db.test_shard.find({ age: { $gte : 36 ,$lt : 73 } }).explain() //范围查询 # 分片 操作命令 sh.enableSharding('testdb') //开启数据库testdb分片 sh.shardCollection('testdb.users',{uid:1}) //按testdb.users的uid字段分片 sh.shardCollection("testdb.test_shard",{"age": 1}) //按ranged分片 sh.shardCollection("testdb.test_shard2",{"age": "hashed"}) //按hash分片 sh.status() //查看分片节点 sh.addShard() //向集群中添加一个 shard sh.getBalancerState() //查看平衡器 sh.disableBalancing() //禁用平衡器 sh.enableBalancing() //启用平衡器 db.runCommand( { removeShard: "mongodb0" } ) //删除分片mongodb0,迁移数据查看命令 db.runCommand( { movePrimary: "test", to: "mongodb1" }) //将数据库test未分片mongodb0的数据,迁移到mongodb1主分片。 db.adminCommand("flushRouterConfig") //处理分片后,刷新路由数据。 use config db.databases.find() //查看所有数据库使用分片 db.settings.save({_id:"chunksize",value:1}) //将 chunk 的大小调整为 1MB db.serverStatus().sharding # 副本集 操作命令 rs.status() //查看成员的运行状态等信息 rs.config() //查看配置信息 rs.slaveOk() //允许在SECONDARY节点上进行查询操作,默认从节点不具有查询功能 rs.isMaster() //查询该节点是否是主节点 rs.add({}) //添加新的节点到该副本集中 rs.remove() //从副本集中删除节点 rs.stepDown //降级节点 db.printSlaveReplicationInfo() //查看同步情况 rs.addArb("172.20.0.16:27038") //添加仲裁节点 rs.add({_id : 2, host : "192.168.1.22:26003", arbiterOnly:true}) //添加仲裁节点 # 强制加入仲裁节点: config=rs.conf() config.members=[config.members[0],config.members[1],{_id:5,host:"127.0.0.1:27023",priority:5,arbiterOnly:"true"}] rs.reconfig(config,{force:true}) # 强制主节点: cfg = rs.conf() cfg.members[0].priority = 0.5 cfg.members[1].priority = 0.5 cfg.members[2].priority = 1 rs.reconfig(cfg) # 备份/恢复 mongodump -h 127.0.0.1:27017 -d test -o /data/backup/ mongorestore -h 127.0.0.1:27017 -d test --dir /data/db/test
版权属于: 技术客
原文地址: https://www.sunjs.com/article/detail/3fa4f35574f14b86b06f1939187ea995.html
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
关键字: 数据库 mongodb docker docker-compose