分片为应对高吞吐量与大数据量提供了方法。使用分片减少了每个分片需要处理的请求数,因此,通过水平扩展,集群可以提高自己的存储容量和吞吐量。
MongoDB内置了非常棒的分片与副本集机制以及无结构文档的特性,并迅速崛起为最受欢迎的Nosql数据库(db ranking),尤其是它的分片机制非常值得学习(MongoDB官方文档)。
MongoDB Shard分片:
mongodb分片可以非常方便的实现大规模存储集群并易于扩展。
mongo的分片集群架构设计:
(1)mongos :前端路由,客户端由此接入,且让整个集群看上去像单一数据库,前端应用可以透明使用。
(2)config server:mongod实例,存储了整个 ClusterMetadata,其中包括 chunk信息。
(3)shard:用于存储实际的数据块,实际生产环境中一个shard server角色可由几台机器组个一个replica set承担,防止主机单点故障。
同库内分片表与非分片表共存 :
根据分片键值 划分为 多个块区间,块内数据超过指定大小后单块区间会裂变为多个块区间:(MongoDB在超出配置的块大小时会拆分块。插入和更新都可以触发块拆分。)
块划分到不同分片,默认规则为每个分片保持相同的块数:(需要多地域机房部署,建议分片键前缀稳定的地域字段,这样可以使数据存储和请求发送到对应地域的分片中)
分片数据不均匀时,均衡器负责在分片间移动块,并修改分片块配置。(均衡器一次只迁移一个块,但依然可能会对性能有一定影响)
MongoDB Replica副本集:
可以非常方便的实现主从复制和故障自动切换。
mongo副本集特性:
(1)N 个节点的集群
(2)任何节点可作为主节点
(3)所有写入操作都在主节点上
(4)自动故障转移
(5)自动恢复
mongo副本集节点包含以下三类角色:
(1)主节点(Primary):是 Replica Set 中唯一接收写请求的节点,并将写入指令记录到 oplog 上。副本节点通过复制 oplog 的写入指令同步主节点的数据。Secondary。一个 Replica Set 有且只有Primary 节点,当Primar挂掉后,其他 Secondary 或者 Arbiter 节点会重新选举出来一个主节点。应用程序的默认读取请求也是发到 Primary节点处理的。
(2)副本节点(Secondary):通过复制主节点 oplog 中的指令与主节点保持同样的数据集,当主节点挂掉的时候,参与主节点选举。需要注意副本节点不建议用于读写分离,同步延迟时会有数据不一致的情况,建议只用于HA故障快速切换、数据备份、非时效性数据分析等。读写分离问题通过shard分散压力解决。
(3)仲裁者(Arbiter):不存储实际应用数据。与其他members保持心跳连接,持有一个投票配额(在members为偶数时增加arbiter节点为奇数可以加快primary多少派意见达成),只投票参与选取主节点,但不会被选举成为主节点。
副本集的最小的部署单位可以为“primary + secondary + arbiter”,或者为“primary + 2*secondaries”,已经基本可以满足HA的需要。建议3个meembers即可,如确实需要更多,需要尽可能保证members个数为奇数,且至少有2个member保存数据。一个复制集集群内最多支持50个members,但是最多只能有7个可以投票。
典型的“Primary主 + Secondary从+ Arbiter辅助投票”:
一、下载mongodb
mkdir -p /home/work/mongodb/bin/
cd /home/work/mongodb/bin/
wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.2.22.tgz
tar zxvf mongodb-linux-x86_64-3.2.22.tgz
二、mongodb集群配置
测试集群拓扑结构:
server0作为route入口;后置server1/server2/server3为数据存储及仲裁服务器,各3个分片,互为主从。
3台shard分片服务器配置:
mkdir -p /home/work/mongodb/conf
mkdir -p /home/work/mongodb/log
mkdir -p /home/work/mongodb/data/shard1
mkdir -p /home/work/mongodb/data/shard2
mkdir -p /home/work/mongodb/data/shard3
vim /home/work/mongodb/conf/shard1.conf
#shard1 server conf
shardsvr=true # 声明这是一个集群的分片
replSet=shard1 # 设置副本集的名字
port=10001 # 端口号
dbpath=/home/work/mongodb/data/shard1 # 数据库路径
logpath=/home/work/mongodb/log/shard1.log # 日志输出文件
logappend=true # 使用追加的方式写日志
directoryperdb=true # 每个数据库保存为单独目录
storageEngine=wiredTiger # 指定存储引擎
wiredTigerCacheSizeGB=2 # 控制WiredTiger存储引擎所占用的内存大小(默认为系统内存的额50%)
syncdelay=30 # 设置从内存同步到硬盘的时间间隔(默认为60秒,设置小点在mongodb故障时,丢失的日志会少一些)
wiredTigerCollectionBlockCompressor=zlib #设定压缩策略
oplogSize=2048 # 设置oplog的大小(MB)
journal=false # 启用日志选项后MongoDB的数据操作将会写入到journal文件夹的文件里
slowms=200 # 设置慢查询时间(默认100ms)
fork=true # 以守护进程的方式运行,创建服务器进程
rest=true # 开启简单的rest API
httpinterface=true # 开启http端口(默认为port+1000)
vim /home/work/mongodb/conf/shard2.conf
#shard2 server conf
shardsvr=true # 声明这是一个集群的分片
replSet=shard2 # 设置副本集的名字
port=10002 # 端口号
dbpath=/home/work/mongodb/data/shard2 # 数据库路径
logpath=/home/work/mongodb/log/shard2.log # 日志输出文件
logappend=true # 使用追加的方式写日志
directoryperdb=true # 每个数据库保存为单独目录
storageEngine=wiredTiger # 指定存储引擎
wiredTigerCacheSizeGB=2 # 控制WiredTiger存储引擎所占用的内存大小(默认为系统内存的额50%)
syncdelay=30 # 设置从内存同步到硬盘的时间间隔(默认为60秒,设置小点在mongodb故障时,丢失的日志会少一些)
wiredTigerCollectionBlockCompressor=zlib #设定压缩策略
oplogSize=2048 # 设置oplog的大小(MB)
journal=false # 启用日志选项后MongoDB的数据操作将会写入到journal文件夹的文件里
slowms=200 # 设置慢查询时间(默认100ms)
fork=true # 以守护进程的方式运行,创建服务器进程
rest=true # 开启简单的rest API
httpinterface=true # 开启http端口(默认为port+1000)
vim /home/work/mongodb/conf/shard3.conf
#shard3 server conf
shardsvr=true # 声明这是一个集群的分片
replSet=shard3 # 设置副本集的名字
port=10003 # 端口号
dbpath=/home/work/mongodb/data/shard3 # 数据库路径
logpath=/home/work/mongodb/log/shard3.log # 日志输出文件
logappend=true # 使用追加的方式写日志
directoryperdb=true # 每个数据库保存为单独目录
storageEngine=wiredTiger # 指定存储引擎
wiredTigerCacheSizeGB=2 # 控制WiredTiger存储引擎所占用的内存大小(默认为系统内存的额50%)
syncdelay=30 # 设置从内存同步到硬盘的时间间隔(默认为60秒,设置小点在mongodb故障时,丢失的日志会少一些)
wiredTigerCollectionBlockCompressor=zlib #设定压缩策略
oplogSize=2048 # 设置oplog的大小(MB)
journal=false # 启用日志选项后MongoDB的数据操作将会写入到journal文件夹的文件里
slowms=200 # 设置慢查询时间(默认100ms)
fork=true # 以守护进程的方式运行,创建服务器进程
rest=true # 开启简单的rest API
httpinterface=true # 开启http端口(默认为port+1000)
3台config服务器配置:
mkdir /home/work/mongodb/data/config
vim /home/work/mongodb/conf/config.conf
#config server conf
configsvr=true # 声明这是一个集群的config服务
replSet=config # 设置副本集名称
port=20000 # 端口号
dbpath=/home/work/mongodb/data/config # 指定数据库路径
logpath=/home/work/mongodb/log/config.log # 指定日志文件
directoryperdb=true # 设置每个数据库将被保存在一个单独的目录
logappend=true # 使用追加的方式写日志
storageEngine=wiredTiger # 指定存储引擎
profile=1 # 档案参数 0=off 1=slow, 2=all
slowms=200 # 设置慢查询时间(默认100ms)
fork=true # 以守护进程的方式运行服务器进程
maxConns=20000 # 最大同时连接数
1台mongos路由服务器配置:
vim /home/work/mongodb/conf/mongos.conf
#mongos route server conf
configdb=config/10.100.67.77:20000,10.100.40.195:20000,10.101.114.131:20000 #设置各config服务器端口
port=40000 # 端口号
logpath=/home/work/mongodb/log/mongos.log # 指定日志文件
logappend=true # 使用追加的方式写日志
maxConns=20000 # 最大同时连接数
fork=true # 以守护进程的方式运行
*配置文件下载:mongodb_shard_conf.tar
三、mongodb集群启动/初始化
# 1.在每台服务器上安装依赖 yum -y install net-snmp-libs # 2.启动集群 *注:可将以下命令添加到开机启动文件/etc/rc.d/rc.local中 # 2.1在3台服务器上同时启动shard/config server # shard server /home/work/mongodb/bin/mongod -f /home/work/mongodb/conf/shard1.conf /home/work/mongodb/bin/mongod -f /home/work/mongodb/conf/shard2.conf /home/work/mongodb/bin/mongod -f /home/work/mongodb/conf/shard3.conf # config server /home/work/mongodb/bin/mongod -f /home/work/mongodb/conf/config.conf # 2.2测试shard/config server 是否正常work # test server 1 /home/work/mongodb/bin/mongo 10.100.67.77:10001 /home/work/mongodb/bin/mongo 10.100.67.77:10002 /home/work/mongodb/bin/mongo 10.100.67.77:10003 /home/work/mongodb/bin/mongo 10.100.67.77:20000 # test server 2 /home/work/mongodb/bin/mongo 10.100.40.195:10001 /home/work/mongodb/bin/mongo 10.100.40.195:10002 /home/work/mongodb/bin/mongo 10.100.40.195:10003 /home/work/mongodb/bin/mongo 10.100.40.195:20000 # test server 3 /home/work/mongodb/bin/mongo 10.101.114.131:10001 /home/work/mongodb/bin/mongo 10.101.114.131:10002 /home/work/mongodb/bin/mongo 10.101.114.131:10003 /home/work/mongodb/bin/mongo 10.101.114.131:20000 # 2.3初始化config server集群 *注: 在任意一台config server执行即可,会自动相互同步。 /home/work/mongodb/bin/mongo 10.100.67.77:20000 rs.initiate({ _id: "config", configsvr: true, members: [ { _id: 0, host: "10.100.67.77:20000" }, { _id: 1, host: "10.100.40.195:20000" }, { _id: 3, host: "10.101.114.131:20000" } ] }); #添加config server: rs.add("10.101.114.131:20000"); *注,想重置rs.initiate()时可以使用rs.reconfig({xxxxx},{force:true}); # 检查config集群是否设置成功
rs.status() #正常应该是一个PRIMARY,两个SECONDARY。 # 2.4初始化各分片的主从副本 *注: 在任意一台server执行即可,副本成员会自动相互同步。 # shard1副本配置 /home/work/mongodb/bin/mongo 10.100.67.77:10001 rs.initiate({"_id" : "shard1","version" : 1, "members" : [ {"_id" : 0,"host" : "10.100.67.77:10001",priority:2}, {"_id" : 1,"host" : "10.100.40.195:10001",priority:1}, {"_id" : 2,"host" : "10.101.114.131:10001",arbiterOnly:true} ] }); # 或继续添加副本(只能在primary上操作) rs.add("10.101.114.131:10001"); # 或添加仲裁(只能在primary上操作) rs.addArb("10.101.114.131:10001") *注,想重置rs.initiate()时可以使用rs.reconfig({"_id" : "shard1","version" : 1, "members" : [{"_id" : 0,"host" : "10.100.67.77:10001",priority:2},{"_id" : 1,"host" : "10.100.40.195:10001",priority:1},{"_id" : 2,"host" : "10.101.114.131:10001",arbiterOnly:true}] },{force:true}); # 检查shard1副本是否设置成功 shard1:PRIMARY> rs.status() #可以看到当前副本已经被自动选为了shard1的primary节点 { "set" : "shard1", "date" : ISODate("2019-07-29T04:28:14.190Z"), "myState" : 1, "term" : NumberLong(1), "heartbeatIntervalMillis" : NumberLong(2000), "members" : [ { "_id" : 0, "name" : "10.100.67.77:10001", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", #主节点:被仲裁节点选中为主节点,唯一接收写请求的节点。 "uptime" : 854298, "optime" : { "ts" : Timestamp(1564371874, 84), "t" : NumberLong(1) }, "optimeDate" : ISODate("2019-07-29T03:44:34Z"), "electionTime" : Timestamp(1563524640, 1), "electionDate" : ISODate("2019-07-19T08:24:00Z"), "configVersion" : 98543, "self" : true }, { "_id" : 1, "name" : "10.100.40.195:10001", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", #从(副本)节点:通过复制主节点 oplog 中的指令与主节点保持同样的数据集,当主节点挂掉的时候,参与主节点选举。 "uptime" : 849863, "optime" : { "ts" : Timestamp(1564371874, 84), "t" : NumberLong(1) }, "optimeDate" : ISODate("2019-07-29T03:44:34Z"), "lastHeartbeat" : ISODate("2019-07-29T04:28:12.726Z"), "lastHeartbeatRecv" : ISODate("2019-07-29T04:28:12.734Z"), "pingMs" : NumberLong(0), "syncingTo" : "10.100.67.77:10001", "configVersion" : 98543 }, { "_id" : 2, "name" : "10.101.114.131:10001", "health" : 1, "state" : 7, "stateStr" : "ARBITER", #仲裁节点:不存储实际应用数据,只投票参与选取主节点,但不会被选举成为主节点。 "uptime" : 15, "lastHeartbeat" : ISODate("2019-07-29T04:28:12.730Z"), "lastHeartbeatRecv" : ISODate("2019-07-29T04:28:13.753Z"), "pingMs" : NumberLong(1), "configVersion" : 98543 } ], "ok" : 1 } # shard2副本配置(除端口外其他同shard1) /home/work/mongodb/bin/mongo 10.100.67.77:10002 rs.initiate({"_id" : "shard2", "version" : 1, "members" : [ {"_id" : 0,"host" : "10.100.67.77:10002",arbiterOnly:true}, {"_id" : 1,"host" : "10.100.40.195:10002",priority:2}, {"_id" : 2,"host" : "10.101.114.131:10002",priority:1} ] }); #检查shard2副本是否设置成功 rs.status() # shard3副本配置(除端口外其他同shard1) /home/work/mongodb/bin/mongo 10.100.67.77:10003 rs.initiate({"_id" : "shard3", "version" : 1, "members" : [ {"_id" : 0,"host" : "10.100.67.77:10003",priority:1}, {"_id" : 1,"host" : "10.100.40.195:10003",arbiterOnly:true}, {"_id" : 2,"host" : "10.101.114.131:10003",priority:2} ] }); #检查shard3副本是否设置成功 rs.status() # 2.5在server0上启动mongos route server(机器不够用,拿server1当server0模拟) # route server /home/work/mongodb/bin/mongos -f /home/work/mongodb/conf/mongos.conf # 2.6测试mongos route server是否正常work # test route server /home/work/mongodb/bin/mongo 10.100.67.77:40000 *注:以后对集群的操作只要用mongo命令连上route server的40000端口后即是对集群进行操作。 3.在mongos集群中注册shard分片和副本 /home/work/mongodb/bin/mongo 10.100.67.77:40000 mongos> sh.addShard("shard1/10.100.67.77:10001,10.100.40.195:10001,10.101.114.131:10001") mongos> sh.addShard("shard2/10.100.67.77:10002,10.100.40.195:10002,10.101.114.131:10002") mongos> sh.addShard("shard3/10.100.67.77:10003,10.100.40.195:10003,10.101.114.131:10003") # 给已有的分片添加副本 mongos> use config mongos> db.shards.find() { "_id" : "shard1", "host" : "shard1/10.100.40.195:10001,10.100.67.77:10001,10.101.114.131:10001" } { "_id" : "shard2", "host" : "shard2/10.100.40.195:10002,10.100.67.77:10002,10.101.114.131:10002" } { "_id" : "shard3", "host" : "shard3/10.100.40.195:10003,10.100.67.77:10003,10.101.114.131:10003" } mongos> db.shards.update({ "_id" : "shard1"},{$set:{"host" : "shard1/10.100.40.195:10001,10.100.67.77:10001,10.101.114.131:10001"}})
四、启用分片
# 0.mongs登入
/home/work/mongodb/bin/mongo 10.100.67.77:40000
# 1.准备要分片的库表
mongos> use test
mongos> db.createCollection("log") #表必须存在
mongos> db.log.createIndex({"_id":1,"time":1}) #分片字段上必须有索引
# 2.db开启分片
mongos> sh.enableSharding("test")
# 3.单集合(表)开启分片
mongos> sh.shardCollection("test.log", {"_id": 1})
*注:没有直接取消表分片的功能,如要取消,需备份数据后drop表并从第1步重新开始。
# 4.查看集群分片配置
mongos> sh.status()
或
use config
db.databases.find();
db.shards.find();
# 5.测试分片
# 修改分片块大小为1M(仅为方便在小数据集上观察到均匀的分片效果,正式环境别瞎改)
mongos> use config
mongos> db.settings.find()
{ "_id" : "chunksize", "value" : NumberLong(64) }
mongos> db.settings.update({"_id" : "chunksize"},{$set:{"value" : NumberLong(1)}})
mongos> db.settings.find()
{ "_id" : "chunksize", "value" : NumberLong(1) }
# 插入测试数据
mongos> for(var i=0;i<100000;i++){ db.log.insert({'_id':i,'val':'Just to make the dataSize larger'}); }
mongos> db.log.find()
{ "_id" : 0, "time" : 'Just to make the dataSize larger' }
{ "_id" : 1, "time" : 1 }
{ "_id" : 2, "time" : 2 }
{ "_id" : 3, "time" : 3 }
...
# 查看插入的数据在各分片的分布情况
mongos> db.stats()
{
"raw" : {
"shard1/10.100.40.195:10001,10.100.67.77:10001" : {
"db" : "test",
"collections" : 1,
"objects" : 38562,
"avgObjSize" : 60,
"dataSize" : 2313720,
"storageSize" : 245760,
"numExtents" : 0,
"indexes" : 2,
"indexSize" : 937984,
"ok" : 1,
"$gleStats" : {
"lastOpTime" : Timestamp(0, 0),
"electionId" : ObjectId("7fffffff0000000000000003")
}
},
"shard2/10.100.40.195:10002,10.100.67.77:10002" : {
"db" : "test",
"collections" : 1,
"objects" : 23824,
"avgObjSize" : 60,
"dataSize" : 1429440,
"storageSize" : 126976,
"numExtents" : 0,
"indexes" : 2,
"indexSize" : 532480,
"ok" : 1,
"$gleStats" : {
"lastOpTime" : Timestamp(0, 0),
"electionId" : ObjectId("7fffffff0000000000000003")
}
},
"shard3/10.100.40.195:10003,10.100.67.77:10003" : {
"db" : "test",
"collections" : 1,
"objects" : 37614,
"avgObjSize" : 60,
"dataSize" : 2256840,
"storageSize" : 208896,
"numExtents" : 0,
"indexes" : 2,
"indexSize" : 1007616,
"ok" : 1,
"$gleStats" : {
"lastOpTime" : Timestamp(0, 0),
"electionId" : ObjectId("7fffffff0000000000000002")
}
}
},
"objects" : 100000,
"avgObjSize" : 60,
"dataSize" : 6000000,
"storageSize" : 581632,
"numExtents" : 0,
"indexes" : 6,
"indexSize" : 2478080,
"fileSize" : 0,
"extentFreeList" : {
"num" : 0,
"totalSize" : 0
},
"ok" : 1
}
*注:可以看到各分片的数据分布还是相对均匀的。
# 查看分片键的区间分块/分片情况
mongos> sh.status()
--- Sharding Status ---
sharding version: {
"_id" : 1,
"minCompatibleVersion" : 5,
"currentVersion" : 6,
"clusterId" : ObjectId("5d317b2b1de86b805c3359f5")
}
shards:
{ "_id" : "shard1", "host" : "shard1/10.100.40.195:10001,10.100.67.77:10001" }
{ "_id" : "shard2", "host" : "shard2/10.100.40.195:10002,10.100.67.77:10002" }
{ "_id" : "shard3", "host" : "shard3/10.100.40.195:10003,10.100.67.77:10003" }
active mongoses:
"3.2.3" : 1
balancer:
Currently enabled: yes
Currently running: no
Failed balancer rounds in last 5 attempts: 0
Migration Results for the last 24 hours:
9 : Success
1 : Failed with error 'aborted', from shard2 to shard3
1 : Failed with error 'aborted', from shard3 to shard1
databases:
{ "_id" : "test", "primary" : "shard3", "partitioned" : true }
test.log
shard key: { "_id" : 1 }
unique: false
balancing: true
chunks:
shard1 5
shard2 4
shard3 4
{ "_id" : { "$minKey" : 1 } } -->> { "_id" : 1 } on : shard1 Timestamp(8, 1)
{ "_id" : 1 } -->> { "_id" : 33 } on : shard2 Timestamp(6, 1)
{ "_id" : 33 } -->> { "_id" : 8771 } on : shard3 Timestamp(7, 1)
{ "_id" : 8771 } -->> { "_id" : 18760 } on : shard3 Timestamp(3, 3)
{ "_id" : 18760 } -->> { "_id" : 27498 } on : shard1 Timestamp(4, 2)
{ "_id" : 27498 } -->> { "_id" : 38425 } on : shard1 Timestamp(4, 3)
{ "_id" : 38425 } -->> { "_id" : 47163 } on : shard2 Timestamp(5, 2)
{ "_id" : 47163 } -->> { "_id" : 57078 } on : shard2 Timestamp(5, 3)
{ "_id" : 57078 } -->> { "_id" : 65816 } on : shard3 Timestamp(6, 2)
{ "_id" : 65816 } -->> { "_id" : 75965 } on : shard3 Timestamp(6, 3)
{ "_id" : 75965 } -->> { "_id" : 84703 } on : shard1 Timestamp(7, 2)
{ "_id" : 84703 } -->> { "_id" : 94861 } on : shard1 Timestamp(7, 3)
{ "_id" : 94861 } -->> { "_id" : { "$maxKey" : 1 } } on : shard2 Timestamp(8, 0)
*注:可以看到片键的区间分块情况
五、副本集容灾测试
1.查看shard1分片的PRIMARY节点
/home/work/mongodb/bin/mongo 10.100.67.77:10001
shard1:PRIMARY> rs.status() #可以看到server1就是PRIMARY
2.kill掉shard1的PRIMARY节点进程
ps aux |grep mongo|grep shard1 |grep -v grep| cut -c 9-15 | xargs kill -9
3.检查shard1的当前PRIMARY
/home/work/mongodb/bin/mongo 10.100.40.195:10001
shard1:PRIMARY> rs.status()
{
"set" : "shard1",
"date" : ISODate("2019-07-29T06:06:12.707Z"),
"myState" : 1,
"term" : NumberLong(4),
"heartbeatIntervalMillis" : NumberLong(2000),
"members" : [
{
"_id" : 0,
"name" : "10.100.67.77:10001",
"health" : 0,
"state" : 8,
"stateStr" : "(not reachable/healthy)", #server1副本连接不上了
"uptime" : 0,
"optime" : {
"ts" : Timestamp(0, 0),
"t" : NumberLong(-1)
},
"optimeDate" : ISODate("1970-01-01T00:00:00Z"),
"lastHeartbeat" : ISODate("2019-07-29T06:06:12.450Z"),
"lastHeartbeatRecv" : ISODate("2019-07-29T06:05:04.012Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "Connection refused",
"configVersion" : -1
},
{
"_id" : 1,
"name" : "10.100.40.195:10001",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY", #server2被自动选择为新的PRIMARY
"uptime" : 857145,
"optime" : {
"ts" : Timestamp(1564380314, 2),
"t" : NumberLong(4)
},
"optimeDate" : ISODate("2019-07-29T06:05:14Z"),
"infoMessage" : "could not find member to sync from",
"electionTime" : Timestamp(1564380314, 1),
"electionDate" : ISODate("2019-07-29T06:05:14Z"),
"configVersion" : 98543,
"self" : true
},
{
"_id" : 2,
"name" : "10.101.114.131:10001",
"health" : 1,
"state" : 7,
"stateStr" : "ARBITER",
"uptime" : 5893,
"lastHeartbeat" : ISODate("2019-07-29T06:06:12.449Z"),
"lastHeartbeatRecv" : ISODate("2019-07-29T06:06:11.595Z"),
"pingMs" : NumberLong(1),
"configVersion" : 98543
}
],
"ok" : 1
}
4.集群仍可正常work
/home/work/mongodb/bin/mongo 10.100.67.77:40000
mongos> db.log.insert({_id:-1,val:'test'})
WriteResult({ "nInserted" : 1 })
5.恢复server1的shard1副本
/home/work/mongodb/bin/mongod -f /home/work/mongodb/conf/shard1.conf
6.查看server1的shard1副本是否恢复
/home/work/mongodb/bin/mongo 10.100.67.77:10001
shard1:SECONDARY> rs.status()
{
"set" : "shard1",
"date" : ISODate("2019-07-29T06:12:07.831Z"),
"myState" : 1,
"term" : NumberLong(5),
"heartbeatIntervalMillis" : NumberLong(2000),
"members" : [
{
"_id" : 0,
"name" : "10.100.67.77:10001",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY", #由于server1的priority更高,故障恢复自动同步数据后又自动被选为PRIMARY
"uptime" : 62,
"optime" : {
"ts" : Timestamp(1564380676, 1),
"t" : NumberLong(5)
},
"optimeDate" : ISODate("2019-07-29T06:11:16Z"),
"electionTime" : Timestamp(1564380675, 1),
"electionDate" : ISODate("2019-07-29T06:11:15Z"),
"configVersion" : 98543,
"self" : true
},
{
"_id" : 1,
"name" : "10.100.40.195:10001",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 62,
"optime" : {
"ts" : Timestamp(1564380676, 1),
"t" : NumberLong(5)
},
"optimeDate" : ISODate("2019-07-29T06:11:16Z"),
"lastHeartbeat" : ISODate("2019-07-29T06:12:07.828Z"),
"lastHeartbeatRecv" : ISODate("2019-07-29T06:12:05.897Z"),
"pingMs" : NumberLong(1),
"syncingTo" : "10.100.67.77:10001",
"configVersion" : 98543
},
{
"_id" : 2,
"name" : "10.101.114.131:10001",
"health" : 1,
"state" : 7,
"stateStr" : "ARBITER",
"uptime" : 62,
"lastHeartbeat" : ISODate("2019-07-29T06:12:05.836Z"),
"lastHeartbeatRecv" : ISODate("2019-07-29T06:12:06.857Z"),
"pingMs" : NumberLong(1),
"configVersion" : 98543
}
],
"ok" : 1
}
7.检查故障期间插入的数据是否正常
shard1:PRIMARY> db.log.find({"_id":-1})
{ "_id" : -1, "val" : "test" }
*注:可以看到副本集的数据同步和自动故障恢复还是挺简单方便的。
笔者参与的项目曾搭建了一个35台服务器的存储集群,存储了30亿+的各类数据,峰值qps5w+。
如果你有超大规模数据的存储需求、非常高的并发读写请求、数据的schema需要比较灵活,可以考虑以下mongodb。当然喜欢mysql的朋友TiDB也是个不错的选择。