MongoDB 高可用相关记录
服务高可用的常用三种工作方式:
- 主从方式 (非对称方式)
工作原理:主机工作,备机处于监控准备状况;当主机宕机时,备机接管主机的一切工作,待主机恢复正常后,按使用者的设定以自动或手动方式将服务切换到主机上运行,数据的一致性通过共享存储系统解决。
- 双机双工方式(互备互援)
工作原理:两台主机同时运行各自的服务工作且相互监测情况,当任一台主机宕机时,另一台主机立即接管它的一切工作,保证工作实时,应用服务系统的关键数据存放在共享存储系统中。
- 集群工作方式(多服务器互备方式)
工作原理:多台主机一起工作,各自运行一个或几个服务,各为服务定义一个或多个备用主机,当某个主机故障时,运行在其上的服务就可以被其它主机接管
MongoDB 的高可用方案采用的是「集群工作方式」,MongoDB集群目前共有三种部署方式:Master-Slave、Relica Set、Sharding。
# 主从架构(Master-Slave)
# 架构说明
Mater-Slaves 主从架构一般用于备份或者做读写分离,不算一种高可用架构。
角色:
- 主(Master) 可读可写,当数据有修改的时候,会将oplog同步到所有连接的salve上去。
- 从(Slave) 只读不可写,自动从Master同步数据。不支持链式链接,只能直连master节点。
Master 宕机后,不能自动恢复。
不推荐使用,官方文档已基本无介绍了。
# 搭建命令
1>. 启动Master
mongod --port 2000 --master --dbpath masterdb/
2>. 启动Slave
mongod --port 2001 --slave --source 127.0.0.1:2000 --dbpath slavedb/
3>. 给Master里面导入数据,查看Master和Slave的数据。你会发现导入Master的数据同时也会在Slave中出现。
mongoimport --port 2000 -d test -c dataset dataset.json
mongo --port 2000 test
db.dataset.count()
> 25359
mongo --port 2001 test
db.dataset.count()
> 25359
2
3
4
5
6
7
8
9
4>. 试一下Master和Slave的写操作。你会发现,只有Master才可以对数据进行修改,Slave修改时候会报错。
mongo --port 2001 test
db.dataset.drop()
> Error: drop failed: { "note" : "from execCommand", "ok" : 0, "errmsg" : "not master" }
mongoimport --port 2001 -d test -c dataset dataset.json
> Failed: error checking connected node type: no reachable servers
2
3
4
5
# 副本集架构(Replica Set)
# 架构说明
Replica Set 副本集群可防止单点故障,数据有副本可恢复,也可满足读写分离。
角色:
- 主节点(Primary)读写,主节点主动将数据变更同步到所有Secondary节点。
- 副本节点(Secondary)可读(默认读主节点,修改客户端链接配置读副本节点),与主节点保持同样的数据集。当主节点挂掉的时候,参与选主。
- 仲裁者(Arbiter)不保有数据,不参与选主,只进行选主投票。使用Arbiter可以减轻数据存储的硬件需求,Arbiter跑起来几乎没什么大的硬件资源需求,但重要的一点是,在生产环境下它和其他数据节点不要部署在同一台机器上。
一个Replica Set只能有一个Primary节点,当Primary挂掉后,其他Secondary或者Arbiter节点会重新选举出来一个主节点。
默认读请求也是发到Primary节点处理的,需要转发到Secondary需要客户端修改一下连接配置。
副本集群至少2个节点(一主一从),官方建议最大3个节点。
Primary节点下发副本策略,节点之间通过心跳机制进行监控检测,默认的副本数为可用节点数量之和(还Primary节点)。
其中Secondary宕机,不受影响,若Primary宕机,会进行重新选主,自动Failover。
- 副本集群的一些局限性:
- 单个副本集限制在12个节点。
- 当请求量巨大时,可能出现内存不足的情况;
- 随着数据量的增大,节点磁盘可能不足;
# 应用客户端
客户端连接单个mongod和副本集的操作是相同,只需要配置好连接选项即可,比如下面是node.js连接Replica Set的方式:
mongoose.connect('mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]' [, options]);
# 搭建命令
3个节点的集群搭建为例:
1> 启动3个数据节点,--relSet指定同一个副本集的名字
mongod --port 2001 --dbpath rs0-1 --replSet rs0
mongod --port 2002 --dbpath rs0-2 --replSet rs0
mongod --port 2003 --dbpath rs0-3 --replSet rs0
2
3
2> 连接到其中一个,配置Replica Set,同时正在执行rs.add的节点被选为Primary。开发环境中hostname
指的是机器名,生产环境下就是机器的IP。
mongo --port 2001
rs.initiate()
rs.add("<hostname>:2002")
rs.add("<hostname>:2003")
rs.conf()
2
3
4
5
6
3> 连接Primary节点,导入数据成功。
mongoimport --port 2001 -d test -c dataset dataset.json
mongo --port 2001 test
db.dataset.count()
> 25359
2
3
4
5
4> 默认情况下,Secondary不能读和写。
mongo --port 2003 test
db.dataset.count()
> Error: count failed: { "note" : "from execCommand", "ok" : 0, "errmsg" : "not master" }
2
3
4
使用Arbiter搭建Replica Set:
偶数个数据节点,加一个Arbiter构成的Replica Set,下面演示精典的2个数据节点加一个仲裁者的搭建过程。
Arbiter节点,需要修改一下配置:
journal.enabled = false
smallFiles = true
2
1> 启动两个数据节点和一个Arbiter节点
mongod --port 2001 --dbpath rs0-1 --replSet rs0
mongod --port 2002 --dbpath rs0-2 --replSet rs0
mongod --port 2003 --dbpath arb --replSet rs0
2
3
4
2> 连接到其中一个,添加Secondary和Arbiter。当仅需要添加Aribiter的时候,只需连接当前Replica Set的Primary,然后执行rs.addArb。
mongo --port 2001
rs.initiate()
rs.add("<hostname>:2002")
rs.addArb("<hostname>:2003")
rs.conf()
2
3
4
5
6
# 数据分片架构(Sharding)
Sharding 分片架构往往通过将数据分片运行在不同机器,从而解决随着数据量增大的CPU、内存和IO的单机压力问题。Mongodb 的分片集群架构如下:
# 架构说明
角色:
- 数据分片 (Shards) 保存数据,保证数据的高可用性和一致性。可以是一个单独的mongod实例,也可以是一个副本集。
- 查询路由(Query Routers)
mongos
的实例,客户端直接连接mongos
,由mongos
把读写请求路由到指定的Shard
上去。一个Sharding
集群,可以有一个mongos
,也可以有多mongos
以减轻客户端请求的压力。 - 配置服务器(Config servers)保存集群的元数据(metadata),包含各个Shard的路由规则,chunk信息等。
在生产环境下Shard是一个Replica Set,以防止该数据片的单点故障。
一个数据库,可分为分片collection和未分片collection,未分片的collection 只能保存在主(Primary)分配上。
# 搭建命令
1> 启动两个数据分片节点。在此仅演示单个mongod的方式,Replica Set类似。
mongod --port 2001 --shardsvr --dbpath shard1/
mongod --port 2002 --shardsvr --dbpath shard2/
2
2> 启动配置服务器
mongod --port 3001 --dbpath cfg1/
mongod --port 3002 --dbpath cfg2/
mongod --port 3003 --dbpath cfg3/
2
3
3> 启动查询路由mongos服务器
mongos --port 5000 --configdb 127.0.0.1:3001,127.0.0.1:3002,127.0.0.1:3003
4> 连接mongos,为集群添加数据分片节点。
mongo --port 5000 amdmin
sh.addShard("127.0.0.1:2001")
sh.addShard("127.0.0.1:2002")
2
3
4
如果Shard是Replica Set,添加Shard的命令:
sh.addShard("rsname/host1:port,host2:port,...")
# rsname - 副本集的名字
2
3
5> 可以连接mongos进行数据操作了。
mongo --port 5000 test
mongoimport.exe --port 5000 -d test dataset.json
> 25359
2
3
4
# 分片架构优势
读写负载
MongoDB 将读写工作负载分布在分片集群中的各个分片上,从而允许每个分片处理集群操作的子集。通过添加更多分配,可以在集群中水平扩展读写工作负载。对于包含分片键或符合分片键的前缀查询,mongos可以将查询定位到特定的分配或一组分片。这些目前操作通常比广播到机器中的每个分片更有效率。从Mongodb4.4开始,mongos可以支持对冲读取(hedged reads 指 mongos 实例路由读取请求时会同时发给两个符合条件的副本集节点,然后那个先返回结果就返回这个结果给客户端)已最大程度的减少延迟。
存储容量
通过分片技术将数据分片到分片集群的各个分片中,每个分片只需存储数据集中的部分子集。随着数据集的增长,通过增加分片的数量即可增加整个集群的容量。
高可用性
将配置服务器和分配作为副本集进行部署可提高可用性。技术一个或多个分配副本集变得完全不可用,分片集群也可以继续提供部分的读取或写入服务。也就是说,虽然停机期间无法访问不可用分配中的数据子集,但是针对可用分配执行读取或写入操作仍然可以成功。
# 数据的备份和恢复
MongodDB的备份有多种方式,这里只简单介绍一下mongodump和mongorestore的用法。
1> 备份和恢复所有db
mongodump -h IP --port PORT -o BACKUPPATH
mongorestore -h IP --port PORT BACKUPPATH
2
3
2> 备份和恢复指定db
mongodump -h IP --port PORT -d DBNAME -o BACKUPPATH
mongorestore -h IP --port PORT -d DBNAME BACKUPPATH
mongorestore -h IP --port PORT --drop -d DBNAME BACKUPPATH
2
3
4
3> 备份和恢复指定collection
mongodump -h IP --port PORT -d DBNAME -c COLLECTION -o xxx.bson
mongorestore -h IP --port PORT -d DBNAME -c COLLECTION xxx.bson
mongorestore -h IP --port PORT --drop -d DBNAME -c COLLECTION xxx.bson
2
3
4
# 小结
MongoDB的集群能力还是很强的,搭建还算是简单。最关键的是要明白上面提到的3种架构的原理,才能用的得心应手。当然不限于MongoDB,或许其他数据库也多多少少支持类似的架构。