MongoDB-系统时钟跳变引发的风波
目录
声明:本文同步发表于 MongoDB 中文社区,传送门:
http://www.mongoing.com/archives/26201
背景
在生产环境的部署中,由于各种不确定因素的存在(比如机器掉电、网络延迟等),各节点上的系统时间很可能会出现不一致的情况。
对于MongoDB来说,时间不一致会对数据库的运行带来一些不可预估的风险,比如主从复制、定时调度都或多或少依赖于时间的取值及判断。
因此,在MongoDB集群中保持节点间的时间同步是一项重要的任务,这通常会使用一些NTP协调服务来实现。
通过人工执行的时间设定操作,或是NTP同步触发的校准,都会使当前的系统时间发生变化,这称之为时间跳变。
时间跳变对于正在运作的流程是存在影响的,尤其是副本集的复制、心跳机制。
接下来,将针对这些影响做一些分析。
一、 对 oplog 的影响
oplog 原理
oplog 是主从数据复制的纽带,主节点负责将写入数据变更记录写入到 oplog 集合,备节点则负责从oplog 中拉取增量的记录进行回放。
一个 典型的 oplog如下所示:
{ "ts" : Timestamp(1560861342, 2), "t" : NumberLong(12), "h" : NumberLong("7983167552279045735"), "v" : 2, "op" : "d", "ns" : "app.T_AppInfo", "o" : { "_id" : ObjectId("5d08da9ebe3cb8c01ea48a25") } }
字段说明
字段名 | 字段描述 |
---|---|
ts | 记录时间 |
h | 记录的全局唯一标识 |
v | 版本信息 |
op | 操作类型(增删改查等) |
ns | 操作的集合 |
o | 操作内容 |
o2 | 待更新的文档,仅 update 操作包含 |
关于 oplog 的结构可以参考这篇文章
其中,ts字段 实现日志拉取的关键,这个字段保证了 oplog是节点有序的,它的构成如下:
- 当前的系统时间,即UNIX时间至现在的秒数,32位
- 整数计时器,不同时间值会将计数器进行重置,32位
ts字段属于Bson的Timestamp类型,这种类型一般在 MongoDB内部使用。
既然 oplog 保证了节点有序,备节点便可以通过轮询的方式进行拉取,我们通过 db.currentOp()命令可以看到具体的实现:
db.currentOp({"ns" : "local.oplog.rs"}) > { "desc" : "conn611866", "client" : "192.168.138.77:51842", "clientMetadata" : { "driver" : { "name" : "NetworkInterfaceASIO-RS", "version" : "3.4.10" } }, "active" : true, "opid" : 20648187, "secs_running" : 0, "microsecs_running" : NumberLong(519601), "op" : "getmore", "ns" : "local.oplog.rs", "query" : { "getMore" : NumberLong("16712800432"), "collection" : "oplog.rs",