MongoDB复制、副本集、分片集群

Posted by YaPi on April 12, 2018

主从复制

  • mongodb的复制至少需要两个节点。其中一个是主节点,负责处理客户端请求,其余的都是从节点,负责复制主节点上的数据。
  • mongodb各个节点常见的搭配方式为:一主一从、一主多从。
  • 主节点记录在其上的所有操作oplog,从节点定期轮询主节点获取这些操作,然后对自己的数据副本执行这些操作,从而保证从节点的数据与主节点一致。

原理

在主从结构中,主节点的操作记录成为oplog(operationlog)。oplog存储在一个系统数据库local的集合oplog.$main中,这个集合的每个文档都代表主节点上执行的一个操作。从服务器会定期从主服务器中获取oplog记录,然后在本机上执行!对于存储oplog的集合,MongoDB采用的是固定集合,也就是说随着操作过多,新的操作会覆盖旧的操作!

主从复制的其他设置项
--only             从节点指定复制某个数据库,默认是复制全部数据库
--slavedelay       从节点设置主数据库同步数据的延迟(单位是秒)
--fastsync         从节点以主数据库的节点快照为节点启动从数据库
--autoresync       从节点如果不同步则从新同步数据库(即选择当通过热添加了一台从服务器之后,从服务器选择是否更新主服务器之间的数据)
--oplogSize        主节点设置oplog的大小(主节点操作记录存储到local的oplog中)

副本集

mongodb 不推荐主从复制,推荐建立副本集(Replica Set)。主从复制其实就是一个单副本的应用,没有很好的扩展性和容错性。副本集解决了”主节点挂掉后,整个集群内会自动切换”的问题。副本集比传统的Master-Slave主从复制有改进的地方就是它可以进行故障的自动转移,若主节点故障,其余从节点会自动推选出一个节点作为主节点。

副本的三种节点

1)主节点负责处理客户端请求,读、写数据, 记录在其上所有操作的 oplog;
2)从节点定期轮询主节点获取这些操作,然后对自己的数据副本执行这些操作,从而保证从节点的数据与主节点一致。默认情况下,从节点不支持外部读取,但可以设置;副本集的机制在于主节点出现故障的时候,余下的节点会选举出一个新的主节点,从而保证系统可以正常运行。
3)仲裁节点不复制数据,仅参与投票。由于它没有访问的压力,比较空闲,因此不容易出故障。由于副本集出现故障的时候,存活的节点必须大于副本集节点总数的一半,否则无法选举主节点,或者主节点会自动降级为从节点,整个副本集变为只读。因此,增加一个不容易出故障的仲裁节点,可以增加有效选票,降低整个副本集不可用的风险。仲裁节点可多于一个。也就是说只参与投票,不接收复制的数据,也不能成为活跃节点。

Replica Set 使用的是n个mongod节点,构建具备自动的容错功能(auto-failover),自动恢复的(auto-recovery)的高可用方案。使用Replica Set 来实现读写分离。默认读操作是在主节点进行的,但是可以指定读取首选项参数来指定读操作到副本节点,通过在连接时指定或者在主库指定slaveOk ,由Secondary来分担读的压力,Primary只承担写操作。对于 Replica Set中的secondary 节点默认是不可读的。

在一些场景,可以使用副本集来扩展读性能,客户端有能力发送读写操作给不同的服务器。也可以在不同的数据中心获取不同的副本来扩展分布式应用的能力。mongodb副本集是一组拥有相同数据的mongodb实例,主mongodb接受所有的写操作,所有的其他实例可以接受主实例的操作以保持数据同步。主实例接受客户的写操作,副本集只能有一个主实例,因为为了维持数据一致性,只有一个实例可写,主实例的日志保存在oplog


心跳检测:
整个集群需要保持一定的通信才能知道哪些节点活着哪些节点挂掉。mongodb节点会向副本集中的其他节点每两秒就会发送一次pings包,如果其他节点在10秒钟之内没有返回就标示为不能访问。每个节点内部都会维护一个状态映射表,表明当前每个节点是什么角色、日志时间戳等关键信息。如果是主节点,除了维护映射表外还需要检查自己能否和集群中内大部分节点通讯,如果不能则把自己降级为secondary只读节点。

数据同步
副本集同步分为初始化同步和keep复制。初始化同步指全量从主节点同步数据,如果主节点数据量比较大同步时间会比较长。而keep复制指初始化同步过后,节点
之间的实时同步一般是增量同步。初始化同步不只是在第一次才会被处罚,有以下两种情况会触发:
1)secondary第一次加入,这个是肯定的。
2)secondary落后的数据量超过了oplog的大小,这样也会被全量复制。

官方推荐MongoDB副本节点最少为3台,建议副本集成员为奇数,最多12个副本节点,最多7个节点参与选举。限制副本节点的数量,主要是因为一个集群中过多的副本节点,增加了复制的成本,反而拖累了集群的整体性能。太多的副本节点参与选举,也会增加选举的时间。而官方建议奇数的节点,是为了避免脑裂 的发生

复制流程

在 MongoDB 副本集中,主节点负责处理客户端的读写请求,备份节点则负责映射主节点的 数据。备份节点的工作原理过程可以大致描述为,备份节点定期轮询主节点上的数据操作,
然后对 自己的数据副本进行这些操作,从而保证跟主节点的数据同步。至于主节点上的所有 数据库状态改变 的操作,都会存放在一张特定的系统表中。备份节点则是根据这些数据进行自己的数据更新。

oplog
上面提到的数据库状态改变的操作,称为 oplog(operationlog,主节点操作记录)。oplog存储在local数据库的"oplog.rs"表中。副本集中备份节点异步的从主节点同步 oplog,然后重新 执行它记录的操作,以此达到了数据同步的作用。关于 oplog 有几个注意的地方:

1)oplog 只记录改变数据库状态的操作
2)存储在 oplog 中的操作并不是和主节点执行的操作完全一样,例如"$inc"操作就会转化为"$set"操作
3)oplog 存储在固定集合中(capped collection),当 oplog 的数量超过 oplogSize,新的操作就会覆盖就的操作

数据同步
在副本集中,有两种数据同步方式:
1)initial sync(初始化):这个过程发生在当副本集中创建一个新的数据库或其中某个节点刚从宕机中恢复,或者向副本集中添加新的成员的时候,默认的,副本集中的节点会从离 它最近的节点复制 oplog 来同步数据,这个最近的节点可以是primary也可以是拥有最新oplog副本的secondary节点。该操作一般会重新初始化备份节点,开销较大。
2)replication(复制):在初始化后这个操作会一直持续的进行着,以保持各个 secondary 节点之间的数据同步。

initial sync
当遇到无法同步的问题时,只能使用以下两种方式进行 initial sync 了
1)第一种方式就是停止该节点,然后删除目录中的文件,重新启动该节点。这样,这个节点就会执行initial sync注意:通过这种方式,sync的时间是根据数据量大小的,如果数据量过大,sync 时间就 会很长同时会有很多网络传输,可能会影响其他节点的工作
2)第二种方式,停止该节点,然后删除目录中的文件,找一个比较新的节点,然后把该节点目 录中的文件拷贝到要 sync 的节点目录中
通过上面两种方式中的一种,都可以重新恢复节点

选举注意事项

副本集的选举过程大致如下:
1)得到每个服务器节点的最后操作时间戳。每个mongodb都有oplog机制会记录本机的操作,方便和主服务器进行对比数据是否同步还可以用于错误恢复。
2)如果集群中大部分服务器 down 机了,保留活着的节点都为secondary状态并停止,不选举了。
3)如果集群中选举出来的主节点或者所有从节点最后一次同步时间看起来很旧了,停止选举等待人来操作。
4)如果上面都没有问题就选择最后操作时间戳最新(保证数据是最新的)的服务器节点作为主节点。
5) 在副本集的环境中,要是所有的Secondary都宕机了,只剩下Primary。最后Primary会变成Secondary,不能提供服务。

副本集选举的特点:
选举还有个前提条件,参与选举的节点数量必须大于副本集总节点数量的一半(建议副本集成员为奇数。最多12个副本节点,最多7个节点参与选举)如果已经小于一半了,那么所有节点保持只读状态。集合中的成员一定要有大部分成员(即超过一半数量)是保持正常在线状态,3个成员的副本集,需要至少2个从属节点是正常状态。
如果一个从属节点挂掉,那么当主节点down掉 产生故障切换时,由于副本集中只有一个节点是正常的,少于一半,则选举失败。
4个成员的副本集,则需要3个成员是正常状态(先关闭一个从属节点,然后再关闭主节点,产生故障切换,此时副本集中只有2个节点正常,则无法成功选举出新主节点)。

读取设置

db.getMongo().setSlaveOk();
db.getMongo().slaveOk();//从库只读,没有写权限,这个方法 java 里面不推荐了
db.setReadPreference(ReadPreference.secondaryPreferred());// 在 复 制 集 中 优 先 读
secondary,如果 secondary 访问不了的时候就从 master 中读
db.setReadPreference(ReadPreference.secondary());// 只 从 secondary 中 读 , 如 果
secondary 访问不了的时候就不能进行查询

分片

Sharding cluster是一种可以水平扩展的模式,在数据量很大时特给力,实际大规模应用一般会采用这种架构去构建。sharding分片很好的解决了单台服务器磁盘空间、内存、cpu等硬件资源的限制问题,把数据水平拆分出去,降低单节点的访问压力。每个分片都是一个独立的数据库,所有的分片组合起来构成一个逻辑上的完整的数据库。因此,分片机制降低了每个分片的数据操作量及需要存储的数据量,达到多台服务器来应对不断增加的负载和数据的效果

使用场景:
1)机器的磁盘不够用了。使用分片解决磁盘空间的问题。
2)单个mongod已经不能满足写数据的性能要求。通过分片让写压力分散到各个分片上面,使用分片服务器自身的资源。
3)想把大量数据放到内存里提高性能。和上面一样,通过分片使用分片服务器自身的资源。

要构建一个MongoDB Sharding Cluster(分片集群),需要三种角色:
1)分片服务器(Shard Server)
   mongod 实例,用于存储实际的数据块,实际生产环境中一个 shard server 角色可由几台机器组个一个 relica set 承担,防止主机单点故障
   这是一个独立普通的mongod进程,保存数据信息。可以是一个副本集也可以是单独的一台服务器。
2)配置服务器(Config Server)
   mongod 实例,存储了整个 Cluster Metadata,其中包括 chunk 信息。
   这是一个独立的mongod进程,保存集群和分片的元数据,即各分片包含了哪些数据的信息。最先开始建立,启用日志功能。像启动普通的 mongod 一样启动
   配置服务器,指定configsvr 选项。不需要太多的空间和资源,配置服务器的 1KB 空间相当于真是数据的 200MB。保存的只是数据的分布表。
3)路由服务器(Route Server)
   mongos实例,前端路由,客户端由此接入,且让整个集群看上去像单一数据库,前端应用
   起到一个路由的功能,供程序连接。本身不保存数据,在启动时从配置服务器加载集群信息,开启 mongos 进程需要知道配置服务器的地址,指定configdb选项。

片键的定义及意义

对数据库test进行分片
1. sh.enableSharding("test")
2. 在需要分片的集合上创建索引 db.users.ensureIndex("username":1)
3. 对集合进行分片 sh.ShardCollection("test.users",{"username":1})


一个好的片键对分片至关重要。 片键必须是一个索引 ,通过sh.shardCollection 会自动创建索引。一个自增的片键对写入和数据均匀分布就不是很好, 因为自增的片键总会在一个分片上写入,后续达到某个阀值可能会写到别的分片。但是按照片键查询会非常高效。随机片键对数据的均匀分布效果很好。注意尽量避免在多个分片上进行查询。在所有分片上查询,mongos 会对结果进行归并排序

释义

分片集群主要由三种组件组成:mongos,config server,shard
1) mongos  (路由进程, 应用程序接入 mongos 再查询到具体分片)
数据库集群请求的入口,所有的请求都通过 mongos 进行协调,不需要在应用程序添加一个路由选择器,mongos 自己就是一个请求分发中心,它负责把对应的数据请求
请求转发到对应的 shard 服务器上。在生产环境通常有多个 mongos 作为请求的入口,防止其中一个挂掉所有的 mongodb 请求都没有办法操作。

2) config server  (路由表服务。 每一台都具有全部 chunk 的路由信息)
顾名思义为配置服务器,存储所有数据库元信息(路由、分片)的配置。mongos 本身没有物理存储分片服务器和数据路由信息,只是缓存在内存里,配置服务器则实际存储
这些数据。mongos 第一次启动或者关掉重启就会从 config server 加载配置信息,以后如果配置服务器信息变化会通知到所有的 mongos 更新自己的状态,这样
mongos 就能继续准确路由。在生产环境通常有多个 config server 配置服务器,因为它存储了分片路由的元数据,这个可不能丢失!就算挂掉其中一台,只要还有存货,
mongodb 集群就不会挂掉。

3) shard  (为数据存储分片。 每一片都可以是复制集(replica set))
这就是传说中的分片了。如图所示,一台机器的一个数据表 Collection1 存储了 1T 数据,压力太大了!在分给 4 个机器后, 每个机器都是 256G,则分摊了集中在一台
机器的压力。事实上,上图4个分片如果没有副本集(replica set)是个不完整架构,假设其中的一个分片挂掉那四 分之一的数据就丢失了,所以在高可用性的分片架构还
需要对于每一个分片构建 replica set 副本集保 证分片的可靠性。生产环境通常是 2 个副本 + 1 个仲裁。

mongos:
首先我们要了解”片键“的概念,也就是说拆分集合的依据是什么?按照什么键值进行拆分集合。mongos就是一个路由服务器,它会根据管理员设置的"片键"
将数据分摊到自己管理的mongod集群,数据和片的对应关系以及相应的配置信息保存在"config服务器"上。
客户端只需要对 mongos 进行操作就行了,至于如何进行分片,不需要 客户端参与,由 mongos 和 config 来完成。

mongod:
一个普通的数据库实例或者副本集,如果不分片的话,我们会直接连上mongod。

分片是指将数据拆分,将其分散存在不同机器上的过程.有时也叫分区.将数据分散在不同的机器上MongoDB支持自动分片,可以摆脱手动分片的管理.集群自动切分数据,做负载均衡

参考: https://www.cnblogs.com/nulige/p/7613721.html