目录

声明:本文同步发表于 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",