MongoDB 副本集故障排查

本文介绍排查 MongoDB 副本集部署问题的常见策略。

检查副本集状态

在连接到主节点的 mongosh 会话中运行 rs.status(),即可显示副本集及各成员的当前状态。各字段说明见 replSetGetStatus 数据库命令。

注意:rs.status() 是执行 replSetGetStatus 数据库命令的包装方法。

检查复制延迟

复制延迟是主节点上的操作发生,到从节点从 oplog 应用该操作之间的时间差。它可能成为严重问题,显著影响副本集部署。延迟过大,会使落后成员无法快速接任主节点,并增加分布式读取结果不一致的可能性。

检查当前延迟的方法:

  1. 在连接到主节点的 mongosh 中调用 rs.printSecondaryReplicationInfo()。
  2. 查看每个成员的 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 次或其他间隔请求一次写入确认,给从节点追赶的机会。

更多信息见 写关注、副本集写关注 与 Oplog 大小。

流量控制

管理员可以限制主节点应用写入的速率,将多数派提交延迟保持在可配置的 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 文档团队。本文为原文的中文译文;代码保留原文内容。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容