小猪手把手教你搭建MongoDB分片+副本集群

分片为应对高吞吐量与大数据量提供了方法。使用分片减少了每个分片需要处理的请求数,因此,通过水平扩展,集群可以提高自己的存储容量和吞吐量。

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辅助投票

典型的“Primary主 + 2*Secondary从”故障转移:
下边主要讲解一下实际搭建mongodb分片+副本集集群的具体过程。

一、下载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也是个不错的选择。

yan 18.3.5
参考:

发表评论

电子邮件地址不会被公开。