云数据库 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 shell或mongosh)连接实例后,执行以下命令来查看oplog表的大小以及oplog窗口期。
rs.printReplicationInfo()
示例的结果如下:
configured oplog size: 10.10546875MB log length start to end: 94400 (26.22hrs) oplog first event time: Mon Mar 19 2012 13:50:38 GMT-0400 (EDT) oplog last event time: Wed Oct 03 2012 14:59:10 GMT-0400 (EDT) now: Wed Oct 03 2012 15:00:21 GMT-0400 (EDT)
在示例中,oplog大小约为10MB,oplog窗口约为26小时。
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 shell或mongosh)连接实例后,执行以下命令来查看从节点的延迟情况。
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或其他数据同步工具正在同步数据。
短时间内大量的批量INSERT或UPDATE负载。
灌数据(将大量数据快速导入到数据库中)。
压力测试。
为了避免写入速度过快而导致产生日志备份空洞,建议您考虑以下优化措施:
使用同步工具时进行适当的限速(比如并发度、批次大小)。
writeConcern使用
{w:"majority"}
而不是{w:1}
。
如果您的工作负载就是会有比较高的oplog生产速度,则应转而考虑以下优化方向:
使用分片集群实例或者增加分片数来降低单个分片上的oplog生产速度。
结合业务场景适当调大oplog大小或者oplog最小保留时间,给日志备份预留更长的缓冲时间。使得在工作负载降低时日志备份可以追赶之前落后的oplog记录。