本文介绍排查 MongoDB 副本集部署问题的常见策略。
检查副本集状态
在连接到主节点的 mongosh 会话中运行 rs.status(),即可显示副本集及各成员的当前状态。各字段说明见 replSetGetStatus 数据库命令。
注意:rs.status() 是执行 replSetGetStatus 数据库命令的包装方法。
检查复制延迟
复制延迟是主节点上的操作发生,到从节点从 oplog 应用该操作之间的时间差。它可能成为严重问题,显著影响副本集部署。延迟过大,会使落后成员无法快速接任主节点,并增加分布式读取结果不一致的可能性。
检查当前延迟的方法:
- 在连接到主节点的
mongosh中调用rs.printSecondaryReplicationInfo()。 - 查看每个成员的
syncedTo,它表示最后一条 oplog 记录写入从节点的时间。例如:
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
如果主节点的无操作时长超过 members[n].secondaryDelaySecs,一个故意延迟的成员也可能显示落后主节点 0 秒。
注意:rs.status() 是 replSetGetStatus 数据库命令的包装。
慢查询日志中的 totalOplogSlotDurationMicros 表示:写操作取得用于提交存储引擎写入的提交时间戳,到实际完成提交之间的时间。mongod 支持并行写入,带有提交时间戳的写操作可以按任意顺序完成提交。
例如,假设 writeA、writeB、writeC 分别拥有 Timestamp1、Timestamp2、Timestamp3。若 writeB 先在 Timestamp2 提交,复制仍必须暂停,直到 writeA 提交,因为复制需要先有 Timestamp1 对应的 oplog 项,才能继续复制到从节点。
可以通过 Cloud Manager 或 Ops Manager 的“Replication Lag”图表监控复制速率,关注非零或持续增加的 oplog 时间值。
复制延迟的原因
网络延迟
检查成员之间的网络路由,确保没有丢包和路由问题。可以用 ping 测试成员之间的延迟,用 traceroute 查看网络端点之间的数据包路径。
磁盘吞吐量
如果从节点的文件系统和磁盘不能像主节点一样快速地将数据刷盘,就难以保持同步。磁盘问题在多租户系统和虚拟化实例中十分常见。如果通过 IP 网络访问磁盘,例如 Amazon EBS,也可能出现短暂问题。
使用 iostat、vmstat 等系统工具评估磁盘状态。
并发
某些情况下,主节点上的长时间操作会阻塞从节点复制。为获得更好的效果,可配置写关注,要求确认数据已经复制到从节点。这样,当复制跟不上写入负载时,写操作不会提前返回。
也可使用数据库分析器,查看是否有慢查询或长时间操作与延迟出现的时间一致。
合适的写关注
大规模数据摄入或批量载入需要向主节点写入大量数据,尤其使用不要求确认的写关注时,从节点可能来不及读取 oplog、追上变更。
为避免这一情况,可以每 100 次、1000 次或其他间隔请求一次写入确认,给从节点追赶的机会。
流量控制
管理员可以限制主节点应用写入的速率,将多数派提交延迟保持在可配置的 flowControlTargetLagSeconds 以内。流量控制默认启用。
启用后,延迟接近目标值时,主节点写入在取得锁、应用写入之前,必须先获取票据。流控通过限制每秒发出的票据数量,尝试将延迟维持在目标以下。
即使副本集负载不足以触发流控,也可能存在复制延迟,例如某个从节点没有响应。
在主节点上运行以下命令检查流控。首先查看是否有成员落后:
rs.printSecondaryReplicationInfo()
示例输出:
source: 192.0.2.2:27017
{
syncedTo: 'Mon Jan 31 2022 18:58:50 GMT+0000 (Coordinated Universal Time)',
replLag: '0 secs (0 hrs) behind the primary '
}
---
source: 192.0.2.3:27017
{
syncedTo: 'Mon Jan 31 2022 18:58:05 GMT+0000 (Coordinated Universal Time)',
replLag: '45 secs (0 hrs) behind the primary '
}
然后运行 serverStatus,通过 flowControl.isLagged 判断是否已触发流控:
db.runCommand( { serverStatus: 1 } ).flowControl.isLagged
示例输出:
false
如果没有触发流控,应检查从节点,确定是否存在硬件、网络或应用限制。
流控统计的参考项包括 flowControl、$currentOp.waitingForFlowControl、$currentOp.flowControlStats、currentOp.waitingForFlowControl 与 currentOp.flowControlStats。
Oplog 项应用缓慢
从节点会记录应用耗时超过慢操作阈值的 oplog 项。这些消息:
- 写入从节点的诊断日志。
- 归于
REPL组件,文字形式为applied op: <oplog entry> took <num>ms。 - 不依赖系统或组件级日志级别。
- 不依赖数据库分析级别。
- 受
slowOpSampleRate影响。
数据库分析器不会捕获慢 oplog 项。
测试所有成员之间的连接
为了支持复制,每个成员都必须能连接其他所有成员。应始终验证双向连通性。网络拓扑和防火墙规则可能阻止正常且必需的通信,进而阻塞复制。
警告:将实例绑定到公开可访问的 IP 之前,必须保护集群免受未授权访问。完整建议见 自托管部署安全检查清单。至少考虑启用身份验证、加固网络基础设施。
mongod 和 mongos 默认绑定 localhost。如果设置 net.ipv6 或命令行 --ipv6,还会绑定 localhost IPv6 地址。
只绑定 localhost 时,默认只能接受同一计算机上的客户端连接,包括 mongosh 以及其他副本集或分片集群成员;远程客户端无法连接。
要绑定其他地址,通过配置文件 net.bindIp 或命令行 --bind_ip 指定主机名或 IP 列表。
警告:从 MongoDB 5.0 开始,仅配置 IP 地址的分割视域 DNS 节点会在启动验证时失败并报错。详见 disableSplitHorizonIPCheck。
例如,以下实例同时绑定 localhost 和主机名 My-Example-Associated-Hostname,后者对应 198.51.100.1:
mongod --bind_ip localhost,My-Example-Associated-Hostname
远程客户端连接时,必须指定主机名或对应 IP:
mongosh --host My-Example-Associated-Hostname
mongosh --host 198.51.100.1
下面是双向网络测试示例。假设副本集的三个成员分别位于 m1.example.net、m2.example.net、m3.example.net,都使用默认端口 27017。
在 m1 上连接另外两台:
mongosh --host m2.example.net --port 27017
mongosh --host m3.example.net --port 27017
在 m2 上连接另外两台:
mongosh --host m1.example.net --port 27017
mongosh --host m3.example.net --port 27017
到此,m1 与 m2 之间的两个方向都已检查。再从 m3 连接另外两台:
mongosh --host m1.example.net --port 27017
mongosh --host m2.example.net --port 27017
只要任何方向连接失败,都应检查网络与防火墙配置,调整环境以允许这些连接。
同时重启多个从节点时的套接字异常
重启成员时,必须保证维护期间仍能选出主节点,也就是保证 members[n].votes 的多数票仍然可用。
活跃成员不能形成多数派时,当前主节点会退位为从节点。退位时不会关闭客户端连接,但在选出新主节点之前,客户端无法写入副本集。
例如,三个成员各有一票的副本集,至少两名成员可以互相连接时才能选举。若同时重启两个从节点,主节点会退位。在至少一个重启中的从节点恢复之前,集群没有主节点,也不能选出新的主节点。
关于投票,见 副本集选举;连接错误相关信息,见 TCP keepalive 时间是否影响 MongoDB 部署。
检查 oplog 大小
更大的 oplog 可以提升副本集对延迟的容忍度,使其更有韧性。
在 mongosh 中连接某个成员,运行 rs.printReplicationInfo(),即可检查它的 oplog 大小。
输出显示 oplog 大小,以及其中操作的日期范围。原文示例中,oplog 约为 10 MB,可容纳约 26 小时,即 94400 秒的操作:
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 应能覆盖你预期从节点最长停机期间的全部事务。[1] 至少应容纳 24 小时操作;许多用户更倾向于 72 小时,甚至一周。
大小如何影响运行,见 Oplog 大小、延迟副本集成员 和前面的“检查复制延迟”。
注意:通常应让所有成员的 oplog 大小一致。调整时,应同时调整全部成员。
操作方法见 修改自托管副本集成员的 oplog 大小。
[1] 为避免删除多数派提交点,oplog 可以增长到超过配置的大小上限。
原文:Troubleshoot Replica Sets。作者/维护者:MongoDB 文档团队。本文为原文的中文译文;代码保留原文内容。











暂无评论内容