Mongodb复制集
作用
复制集的主要意义是实现服务高可用
实现依赖两个方面功能:
1)数据写入的时候,会将数据迅速复制到另一个独立节点上
2)在接收写入的节点发生故障时,自动选举出一个新的替代节点。
附加作用
1)数据分发:将数据从一个区域复制到另一个区域,减少另一个区域的读延迟。
2)读写分离:不同类型的压力分别在不同的节点上执行。
3)异地容灾:在数据中心故障时,快读切换到异地。
副本集设计
大多数
副本集中重要的一个概念是“大多数”(majority):选择主节点时需要由大多数决定,主节点只有得到大多数支持才能继续作为主节点。大多数被定义为:副本集中一半以上的成员。
副本集中的成员数 | 副本集中的大多数 |
---|---|
1 | 1 |
2 | 2 |
3 | 2 |
4 | 3 |
5 | 3 |
6 | 4 |
7 | 4 |
选举机制
想要成为主节点,就需要得到副本集中的大多数成员投票。如果大多数成员中有一个投了反对票,那么选举就会取消。应为赞同票相当于1张票,而反对票相当于10000张票。
另外希望成为主节点的成员,必须使用复制将自己的数据更新为最新,副本集中的成员对此进行检查。复制操作严格按照时间排序。
还有一点需要注意:每个成员只能要求自己被选举为主节点,不能推荐别人为主节点。
成员配置项
仲裁节点
仲裁者(arbiter)唯一的作用就是参与选举,并不存储数据,也不会为客户端提供服务。它只是为了帮助具有两个成员的副本集满足大多数的条件。
最多只能使用一个仲裁者,仲裁者的目的是为了避免出现平票。
成员尽可能是数据节点,而不是仲裁节点。(出现问题时,复制会对主节点造成很大压力,拖慢应用)。
优先级
优先级用于表示一个成员渴望成为主节点的程度,取值范围在0-100,默认是1.优先级为0的含义:永远不能成为主节点,这样的成员称为被动成员(passive member)拥有最高优先级的成员会优先选举为主节点,只要它能得到大数据成员支持,并且数据是最新的。
隐藏成员
客户端不会向隐藏成员发送请求,隐藏成员不会作为复制源(尽管其他复制源不可用时,隐藏成员也会被使用)。
只有优先级为0的成员才能被隐藏,不能将主节点隐藏。(指定配置hidden:true)
延迟备份节点
可以使用slaveDelay设置一个延迟的备份节点。延迟备份节点的数据会比主节点延迟指定的时间(单位秒),这是有意为之。
saveDelay要求成员的优先级为0,如果应用会将请求路由到延迟备份几点,应该将该节点隐藏掉,以免读请求被路由到延迟备份节点。
工作原理
oplog
oplog是一个特殊的限制集合(有限制大小),它存在于每个复制节点的local数据库里,而且记录所有的数据变化。每次写入主节点的数据,就会添加到主节点的oplog中。一旦写入的数据被复制到某个从节点,从节点的oplog也会存储这个写入请求的记录。每个oplog项目通过BSON的时间戳来区分,并且所有的从节点使用时间戳来跟踪他们数据的最新值。
任何成员都可以从任何其他成员上导入oplog记录。
oplog中的操作是幂等的,也就是oplog操作会产生相同的结果,无论一次还是多次应用于目标数据集。
从节点追踪oplog步骤
前提:主节点写入数据,写操作会被记录并添加到主节点的oplog中。同时所有的从节点都会复制主节点的oplog。
当某个从节点准备更新自己的数据时,会进行以下处理:
1)会先查看自己oplog里最新记录的时间戳。
2)会查询主节点的oplog,查询所有时间戳大于自己当前oplog记录的时间戳。
3)根据获取到的oplog,写入数据,并添加每个操作日志到自己oplog里。
如果出现故障,任意的提升为主节点的从节点都会有一个oplog,这样其他的从节点可以复制,这个特性本质上支持可复制集的故障恢复功能。
从节点使用了长轮询在主节点上复制oplog记录,长轮询意味着从节点向主节点发起请求,当主节点收到修改时,会记录响应从节点的等待请求。因此从节点可以做到实时更新。
停止复制
如果从节点无法在主节点oplog中找到同步的日志记录点,就会永久停止复制。oplog是有限制的集合,意味着只能存储固定数量的数据。如果从节点离线一段时间,oplog可能无法存储这段时间里的所有修改记录,一旦从节点无法从主节点找到同步的oplog点,就无法确保从节点是主节点的完美复制集合了。
停止复制的补救措施就是完整地重新同步主节点的数据,这肯定需要避免,因为需要消耗大量时间。因此oplog空间的大小也至关重要。
oplog的大小
首次启动副本集成员时,mongodb将创建默认大小的操作日志。可以通过oplogSizeMB选项指定大小。
对于Unix和Windows系统
默认操作日志大小取决于存储引擎:
储存引擎 | 默认操作日志大小 | 下界 | 上界 |
---|---|---|---|
内存中存储引擎 | 物理内存的5% | 50兆字节 | 50 GB |
WiredTiger存储引擎 | 可用磁盘空间的5% | 990兆字节 | 50 GB |
MMAPv1存储引擎 | 可用磁盘空间的5% | 990兆字节 | 50 GB |
可以通过命令:db.getReplicationInfo() 知道当前的复制信息。一旦知道了每个小时生成的oplog日志数量,就可以决定分配多大的oplog空间。主要目标是消除从节点与主节点的oplog差别,以保持实时更新。应该至少考虑8小时的离线时间,因为要避免完整的复制日志工作。
同步
复制用于多台服务器之间备份数据,mongodb的复制功能是使用操作日志oplog实现的,操作日志包含了主节点的每一次写操作。
每个备份节点都维护自己的oplog,记录着每一次从主节点复制数据的操作。备份节点从当前使用的同步源中获取需要执行的操作,然后在自己数据集上执行这些操作,最好再将这些操作写入到自己的oplog。
初始化同步
副本集中的成员启动后,会检查自身状态,确定是否可以从某个成员那里进行同步。如果不行,会尝试从副本的另一个成员那里进行完整的数据复制,这个过程就是初始化同步。包括以下步骤:
1)记录准备工作:选择一个成员作为同步源,在Local.me中为自己创建一个标识符,删除所有已存在的数据库,以一个全新的状态开始进行同步。
2)克隆,就同步源所有记录全部复制到到本地。
3)进入oplog同步第一步,克隆过程中所有操作都会被记录到oplog中,如果有文档在克隆过程中被移动了,可能会遗漏,对于这样的文档,可能需要重新进行克隆。
4)oplog同步第二步,用于将第一个open同步中的操作记录下来。(从同步源中获取克隆时间段内的oplog? 这一步不太理解?)
5)到目前为止,本地数据应该与主节点在某个时间点的数据集完全一致,可以开始创建索引了。
6)如果当前节点的数据远远落后于同步源,那么oplog同步过程的最后一步就是将创建索引期间的所有操作全部同步过来,防止该成员成为备份几点。
7)当前成员已经完成初始化同步,切换到普通同步状态,这是当前成员就可以成为备份节点。
初始化同步过程中经常遇到的问题是,克隆和创建索引消耗太长的时间,这种情况下新成员就与同步源的oplog“脱节”:新成员远远落后于同步源,导致新成员的数据同步速度赶不上同步源的变化速度。
处理陈旧数据
如果备份节点远远落后于同步源当前的操作,那么这个备份节点就是陈旧的。当一个备份节点陈旧后,他会查看副本集中的其他成员,如果某个成员的oplog足够详尽,可以用于处理那些落下的操作,就从这个成员处进行同步。如果任何一个成员的oplog都没有参考价值,那么这个成员的复制操作就会终止,这个成员需要重新进行完全同步。
为了避免陈旧本分节点的出现,让主节点使用比较大的oplog保存足够多的操作日志。但是大的oplog会占用更多的磁盘空间。不过实际中使用oplog只有一小部分,因此oplog不占用太多RAM。
心跳
复制集心跳便于实现选举和灾备。默认情况下,每个复制集成员会每隔2秒ping一次其他成员,这样系统就可以判断自己的健康状况。
每个复制集都要确保一直只有一个主节点存在,在大多数节点可用的情况下。
如果关闭了某个从节点,但是大多数节点还存在,那么复制集就不会改变,而是简单等待从节点回来,重新上线。
如果主节点挂了,大多数节点还在,这时就会从一群从节点中提升一个从节点为主节点。
如果从节点全部挂掉,只有一个主节点,那么该主节点会降级为从节点。原因:如果是网络分区等原因导致心跳失败,其他节点将仍然在线,如果从节点仍然在线,并且它们心跳是通的,根据大多数原则,剩余的从节点会变成主节点。而如果之前的主节点不降级的话,就会变成一个复制集中有两个主节点,操作就会变得不一致。因此,主节点看不到其他成员时,它必须退位降级。
成员状态
-
STARTUP:成员刚启动时处于这个状态,这个状态下,mongodb会尝试加载成员的副本集配置,配置成功后,进入STARTUP2状态
-
STARTUP2:整个初始化同步过程都处于这个状态,但是如果在普通成员上,这个状态只会持续几秒钟,这个状态下,mongodb会创建几个县城,用于处理复制和选举,然后就会切换到RECOVERING状态。
-
RECOVERING:表明成员运转正常,但是暂时还不能处理读取请求。在启动过程中,成为备份节点之前,每个成员都要经历该状态;处理非常耗时的操作时,成员也可能进入该状态;当一个成员与其他成员脱节时,也会进入该状态,此时并没有进入错误状态,期望发现一个拥有足够详尽oplog的成员,然后继续同步oplog,最后会到正常状态。
-
ARBITER:正常的操作中,仲裁者应该始终处于该状态。
系统出问题时,会处于下面这些状态。
-
DOWN:一个正常圆正常的成员变得不可达,就处于DOWN状态。(如果有成员被报告为DOWN状态,它有可能仍然处于正常运行状态,不可达只是网络问题)
-
UNKNOW:一个成员无法到达其他任何成员,其他成员就无法知道它处于什么状态,会将其报告为UNKNOW状态。
-
REMOVED:当成员被移除副本集,它处于这个状态。如果又被重新添加到副本集,就回到正常状态。
-
ROLLBACK:如果成员进行数据回滚,就处于该状态。回滚结束时,会转为RECOVERING状态,然后成为备份节点。
-
FATAL:如果一个成员发生了不可挽回的错误,也不再尝试恢复正常的话,他就处于FATAL状态。可以通过查看详细日志来查明这个成员为何处于FATAL状态。
选举
当一个成员无法到达主节点,它就会申请被选举为主节点,它会向它所能到达的所有成员发送通知。如果这个成员不符合候选人要求,其他成员会知道相关原因:这个成员的数据落后于副本集,或者已经有一个运行中的主节点。这些情况,其他成员不会允许进行选举。
如果没有反对的理由,其他成员就会对这个成员进行投票。如果这个成员得到副本集中的“大多数”赞成票,就选举成功,会转换到主节点状态。反之,则选举失败,仍然是备份节点,之后还可以再次申请成为主节点。
主节点一般会一直处于主节点状态,除非它由于不满足“大多数”的要求或者挂了而退位,另外副本集被重新配置也会导致主节点退位。
如果网络状况良好,大多数服务器也正常运行,那么选举过程时很快的。如果主节点不可用,2秒钟(心跳是2秒)之内就会有成员发现这个问题,然后立即开始选举。如果网络有问题,或者服务器过载导致响应缓慢,都可能触发选举。在这种情况下,心跳会在最多20秒之后超时,如果选举达成平局,每个成员都需要等待30秒才能开始下一次选举。如果太多错误发生的话,选举可能会花费几分钟的时间。
回滚
对于monggodb单个文档的操作都是原子性的,但是对于多个文档的操作并非原子性的。
假设向主节点插入了一些数据,但由于某种原因没有及时复制到从节点(连接问题、从节点无法备份、从节点延迟等)。现在假设从节点忽然提升为主节点,向新的主节点写入数据,但最终旧的主节点又回来了,并且尝试从新的主节点复制数据。当旧的主节点中有一些写入数据,在新的主节点oplog不存在时,就会触发回滚。
在回滚里,没有复制给从节点的写入操作都会被取消。意味着它们会在从节点oplog和集合里删除。
某些情况下,如果要回滚的内容太多,Mongodb可能承受不了,如果要回滚的数据量大于300MB,或者要回滚30分钟以上的操作,回滚就会失败。对于回滚失败的节点,必须要重新进行同步。
参考资料
-
《Mongodb权威指南 第二版》
-
《Mongodb实战 第二版》
网友评论