复制集(replica set)提供了数据冗余和高可用。它是一组mongod
进程。
一个复制集里面有很多数据节点(data bearing node)和一个可选择的仲裁节点(arbiter node)。数据节点的角色也分为主节点(primary node)和二级节点(secondary node)。所有写操作都是在主节点上的,并记录oplog(operation log)。二级节点通过主节点的oplog重放来保持数据的最终一致性,这个“主从复制”是异步的。当主节点挂了,二级节点会进行新的选举,从中找一个二级节点来充当主节点的角色。仲裁节点只负责参与选举,而不存储数据。
MongoDB推荐的最小架构是:一个主节点,两个二级节点。最大可以有50个成员节点,但是只有7个是voting member。
仲裁节点有一票的选票,优先级为0(priority
为0)。一般是在你只有一个主节点和二级节点,也许由于一些原因如配额预算不够导致不能再部署一个二级节点,可以用一个仲裁节点来参与选举,完成故障转移。
优先级为0的节点,不能成为主节点,也不能发起选举,但是有一票选票(members[n].votes > 0
)。一般来说优先级为0的节点部署得会离主要部署点较远,如下图,所以有较高的延迟latency,不能很好地充当主节点的角色,但是对于local read性能较好。
对于一些特殊场景,复制集还能设立隐藏节点或者延迟节点。隐藏节点将不会有任何reads和writes的traffic, db.hello()
也不会展示隐藏节点,一般用来上报一些信息或者作为备份。延迟节点,存储的数据备份比正常的数据晚一段时间,延迟节点需要设置为隐藏,且优先级为0。
Oplog是一个特殊的capped collection
。二级节点通过主节点记录的Oplog来实现数据复制, 他们保存在local.oplog.rs
。Oplog记录的是对数据的操作,且这些操作是幂等的,也就是执行一次和很多次是结果一样的。
Storage Engine | Default Oplog Size | Lower Bound | Upper Bound |
---|---|---|---|
In-Memory | 5% of physical memory | 50MB | 50GB |
WiredTiger | 5% of free disk space | 990MB | 50GB |
mongod
将删掉Oplog如果它的大小超过上限或者存在的时间超过参数oplogMinRetentionHours
主要有两种同步方式:
初始化的节点会根据一系列规则选择一个source来进行数据同步。3.4过后的初始化将会建立一致的索引。初始化同步完成,该节点的状态由STARTUP2
转为SECONDARY
。
二级节点的同步是异步的,且开启了多个线程并行复制。4.4过后MongoDB传送Oplog是流式一直发送的,用来减少同步延迟。
默认情况是会根据一些规则从复制集中选一个出来当source来同步,但如果chaining
设置为disabled就会选主节点来同步。
默认发送心跳的周期是2s, 心跳检测的默认值(electionTimeoutMillis
)是10s。超过这个值,二级节点还没有收到主节点的心跳,那么就会开启自动故障转移(automatic failover),选举一个新的主节点。在这个选举过程中,是不支持写操作的可以支持打到二级节点上的读操作的。选举过程耗时的中位数大概是12s。
rs.stepDown()
方法等就是根据节点的vote和priority等信息,票数最高且超过一半成员支持的节点成为主节点。如果票数相同,则谁同步数据快,谁胜利。
基于这个架构,我们可以把一些读操作放到二级节点上,来做到读写分离。