啊!你还不了解MongoDB复制集?先看这里科普一下
复制集的成员启动后,会选举出一个Primary,Primary需要得到大多数成员的投票。所有的写入操作都必须向Primary发起,通过oplog将写操作同步到Secondary。
在复制集运行的过程中,难免会遇到需要重启节点的场景,比如复制集版本升级、节点维护等,在重启节点的过程中,建议不要直接shutdown Primary
,这样可能导致已经写入primary但未同步到secondary的数据丢失
,过程类似如下:
- shutdown Primary (shutdown会等待Secondary oplog追到10s以内)
- Primary退出后,剩余的节点选举出一个新的Primary(复制集只包含1或2节点例外)
- Primary重新启动,因为当前复制集已经有了新的Primary,这个Primary将以Secondary的角色运行。
- 从新的Primary同步的过程中,发现自己有
无效的oplog
,会先进行rollback。(rollback的数据只要不超过300M是可以找回的)
如果想不丢数据重启复制集,更优雅的打开方式应该是这样的
- 逐个重启复制集里所有的Secondary节点
- 对Primary发送stepDown命令,等待primary降级为Secondary
- 重启降级后的Primary
注意:如果Secondary的同步一直追不上Primary,步骤2可能会失败,这时应该重试步骤2直到stepDown成功;步骤2也可以通过调用replSetReconfig命令,来调整节点优先级来实现,让Secondary拥有更高的优先级,然后等待Primary降级为Secondary。
从上述分析可以看出,复制集里Primary、Secondary节点角色切换是很正常的事情,所以连接复制集一定不要直连Primary,否则在节点角色切换时不能正确容错,服务高可用无法保证。
另外,要想保证数据的高可靠,除了在运维上加强,在开发层面也可以做些工作,比如重要的数据写入通过WriteConcern: {w: "majority"}
来保证写入到大多数节点才向客户端确认。