oplog相关设置的最佳实践及风险说明

云数据库 MongoDB 版oplog相关参数设置不合理可能会导致实例主从同步异常、实例无法按时间点恢复数据等问题,本文将指导您如何配置oplog相关参数并对相关的风险进行说明。

oplog基本信息

云数据库 MongoDB 版副本集实例的主从复制是通过oplog(operations log)逻辑日志来完成的,oplog表(local.oplog.rs)是一个特殊的限制集合(capped collection),其中存储了所有对数据库中文档的改动操作。oplog具备以下基础特性:

  • 在副本集中,写入操作只会在主节点上完成并产生相应的oplog,其他从节点将异步复制这些oplog并在自身回放,以保持主从复制状态。

  • 如果某个操作并不改动任何文档或者因某种原因失败,则不会产生相应的oplog记录。

  • 一条oplog记录在副本集中所有节点上都完全一致,回放并不会改变oplog表里的记录。

  • oplog表中的每个操作都是幂等的。无论一条oplog记录被回放了一次还是多次,得到的结果都是相同的。

  • oplog记录是与时间相关联的,oplog里每一条操作都有唯一的时间戳字段(ts)。该字段由UNIX时间戳和计数器两部分组成,因此可以确定任意两条oplog记录之间的先后顺序。

  • oplog窗口(oplog window)代表着oplog表里最老的一条oplog记录和最新的一条oplog记录之间的时间差。主从复制依赖这个oplog窗口,只有在同步源的oplog窗口找到期望的oplog记录时,从节点才能正常进行同步。

  • 从节点重启或者新增节点后,也是依赖oplog里的记录来确认自己能否成功成为副本集中正常的一员。如果发现自己期望的oplog记录在同步源中找不到,就会因为too stale to catch up的错误而变成异常的RECOVERING状态。

oplog大小

云数据库 MongoDB 版中,oplog的默认大小是实例磁盘空间的10%(例如您实例的磁盘空间为500 GB,则相应的oplog大小就是50 GB)。oplog大小会随着磁盘扩容而自动调整。

如需调整oplog大小,您可以在控制台对replication.oplogSizeMB参数进行调整,调整后无需重启,提交后即生效。如何修改配置参数,请参见设置数据库参数

您可使用以下两种方式查看oplog表的实际大小:

  • 在控制台监控信息页面的磁盘空间使用率指标中查看oplog表的实际大小。具体操作,请参见基本监控

  • 通过客户端工具(mongo shellmongosh)连接实例后,执行以下命令来查看oplog表的大小以及oplog窗口期。

    rs.printReplicationInfo()

    示例的结果如下:

    configured oplog size:   192MB
    log length start to end: 65422secs (18.17hrs)
    oplog first event time:  Mon Jun 23 2014 17:47:18 GMT-0400 (EDT)
    oplog last event time:   Tue Jun 24 2014 11:57:40 GMT-0400 (EDT)
    now:                     Thu Jun 26 2014 14:24:39 GMT-0400 (EDT)

    在示例中,oplog大小约为192MB,oplog窗口约为18小时。

oplog最小保留时间

MongoDB 4.4版本开始,支持了oplog最小保留时间的配置文件项storage.oplogMinRetentionHours,让您可以直接控制oplog的保留时间来确保足够的oplog窗口。

默认情况下,该配置项的值为0,表示不设置oplog最小保留时间,此时oplog的清理还是由之前的oplog大小控制。如果设置了该配置项,oplog清理将在以下2个条件均满足时发生:

  • oplog超过了配置的oplogSizeMB

  • oplog的时间戳比oplog最小保留时间还早。

oplog还没有达到配置的oplogSizeMB时(例如实例刚初始化,还未写入太多数据),实际的oplog窗口可能会比设置的oplog最小保留时间大很多,此时oplog表的大小只受oplogSizeMB限制;当达到配置的oplogSizeMB后,oplog表的大小受oplog最小保留时间限制,当oplog产生速度较快时,oplog的总大小可能会比配置的oplogSizeMB大很多。

如需调整oplog的保留时间,您可以在控制台对storage.oplogMinRetentionHours参数进行调整,调整后无需重启,提交后即生效。如何修改配置参数,请参见设置数据库参数

如需查看oplog的保留时间,您可以在控制台监控信息页面查看oplog保留时长指标。具体操作,请参见基本监控

云数据库 MongoDB 版日志备份

云数据库 MongoDB 版所有实例的日志备份都基于oplog,相关管控服务进程会不断拉取实例上最新的oplog记录并流式上传至OSS,形成一系列日志备份文件。在按时间点恢复时,这些日志备份文件会用来进行oplog回放。

特殊情况下,日志备份中可能会产生空洞而导致无法按时间点恢复,具体信息,请参见风险说明

说明

本文中提到的日志备份空洞与MongoDB术语中的oplog hole并不是一个概念。

最佳实践

设置合理的oplog大小或oplog保留时间

通常情况下,oplog大小保持默认值即可,但是在以下场景的业务负载下,建议您调大oplog的大小:

  • 经常对文档进行批量更新

    每一个批量更新的操作都会生成多条针对单个文档的更新操作,这会产生大量的oplog记录。

  • 反复地插入和删除

    如果文档插入一段时间后被删除,那么数据库的磁盘空间并不会有明显增长,但oplog里会有很多相关记录。

  • 针对相同文档的大量原地更新

    如果业务场景中大部分操作是不会增加文档大小的更新,这些更新会产生大量的oplog记录,但磁盘上的数据量不会有明显变化。

如果您的业务负载是以下类型,也可以酌情调小oplog大小,以更充分地利用磁盘空间:

  • 读多写少的业务负载。

  • 存储冷数据。

无论是设置oplog大小还是oplog保留时间,都建议您尽量将MongoDB实例的oplog窗口控制在24小时以上。在一些需要额外进行初始化同步(initial sync)的场景,oplog窗口需要覆盖一个节点完成所有数据同步的时间,该时间通常跟实例的整体数据量、库表总数、实例规格等因素相关,oplog窗口可能会需要更长的时间。

关注从节点的延迟情况并配置好相关告警

当从节点出现延迟并且不断变大时,一旦延迟时间超过了oplog窗口,从节点将会进入异常状态无法恢复。因此,您需要关注MongoDB实例中的从节点延迟情况,并且在延迟不断增加时及时提交工单联系阿里云技术支持协助解决。

导致从节点出现延迟的原因有很多,包括:

  • 网络延迟、丢包、中断等。

  • 从节点的磁盘吞吐达到瓶颈。

  • {w:1}writeConcern并且写入负载比较重。

  • 某些内核缺陷导致从节点主从复制被阻塞。

  • 其他未列出的原因。

您可使用以下两种方式查看从节点的延迟情况:

  • 在控制台监控信息页面的主备延迟指标中查看从节点的延迟情况。具体操作,请参见基本监控

  • 通过客户端工具(mongo shellmongosh)连接实例后,执行以下命令来查看从节点的延迟情况。

    rs.printSecondaryReplicationInfo()

    示例的结果如下:

    source: m1.example.net:27017
        syncedTo: Thu Apr 10 2014 10:27:47 GMT-0400 (EDT)
        0 secs (0 hrs) behind the primary
    source: m2.example.net:27017
        syncedTo: Thu Apr 10 2014 10:27:47 GMT-0400 (EDT)
        0 secs (0 hrs) behind the primary

    在示例中,2个从节点都没有延迟。

您可以通过控制台的报警规则功能,创建一条针对复制延迟的云监控告警,建议报警阈值设置为10秒以上。具体操作,请参见设置阈值报警规则

风险说明

可能导致日志备份出现空洞的主要原因有以下两种。

内核大版本低于3.4

周期性的空操作(periodic noop)是MongoDB内核在3.4大版本引入的,目的是为了适配readPreference的配套参数maxStalenessSeconds,详情请参见SERVER-23892。该空操作的目的主要是在没有业务写入的情况下,确保oplog依然在不断向前推进,由此可以判断副本集中主从节点的落后情况。

当数据库的内核大版本低于3.4时,如果很长时间都没有业务写入的情况,oplog不会再推进。因此,实例的日志备份也获取不到新的oplog数据而导致出现日志备份空洞,进而导致出现实例无法按时间点恢复的情况。

实例写入速度过快,oplog窗口太短

根据云数据库 MongoDB 版长期以来积累的实例日志备份数据判断,当一个实例的oplog产生速度达到250GB/h ~ 330GB/h左右时,就很有可能会出现日志备份无法跟上而导致产生日志备份空洞。

您可以通过前面提到的oplog大小以及oplog窗口来估算oplog产生速度。例如某个实例的oplog大小为20 GB,其oplog窗口为0.06h,则oplog生产速度大概是333.3GB/h。

这样的工作负载一般都是以下场景:

  • DTS、mongoShake或其他数据同步工具正在同步数据。

  • 短时间内大量的批量INSERTUPDATE负载。

  • 灌数据(将大量数据快速导入到数据库中)。

  • 压力测试。

为了避免写入速度过快而导致产生日志备份空洞,建议您考虑以下优化措施:

  • 使用同步工具时进行适当的限速(比如并发度、批次大小)。

  • writeConcern使用{w:"majority"}而不是{w:1}

如果您的工作负载就是会有比较高的oplog生产速度,则应转而考虑以下优化方向:

  • 使用分片集群实例或者增加分片数来降低单个分片上的oplog生产速度。

  • 结合业务场景适当调大oplog大小或者oplog最小保留时间,给日志备份预留更长的缓冲时间。使得在工作负载降低时日志备份可以追赶之前落后的oplog记录。

相关文档