这是《MongoDB 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 排障原则:先固定影响面和时间线,再定位层级,最后做可回滚止损。不要在未看指标前重启、切主或修改参数,避免破坏证据。
24.1 排查框架
confirm impact
-> collect timeline
-> check topology
-> check resources
-> check slow queries
-> check application
-> mitigate
-> verify
-> review
需要记录:
- 开始和恢复时间;
- 环境、集群、数据库;
- 错误率、延迟、可用性;
- 发布和配置变更;
- 依赖服务状态;
- 最终根因和动作。
24.2 连接失败
常见错误:
| 错误 | 排查 |
|---|---|
| Connection refused | 进程退出、端口、bindIp |
| Authentication failed | 用户、密码、authSource |
| Timeout | 网络或 DNS |
| No primary | 选举、多数丢失 |
| Not primary | 写入 Secondary |
| ReplicaSetNoPrimary | 拓扑发现异常 |
检查:
mongosh --host mongo1 --port 27017 -u admin -p --authenticationDatabase admin
ss -lntp | grep 27017
24.3 慢查询
定位:
db.setProfilingLevel(1, { slowms: 100, sampleRate: 1 })
查看:
db.system.profile
.find()
.sort({ ts: -1 })
.limit(10)
执行计划:
db.orders.find({ user_id: "u_1001" })
.explain("executionStats")
常见原因:
- COLLSCAN;
- 索引选择性差;
- 内存排序;
- 返回大文档;
- 聚合数据放大;
- cache 压力;
- 磁盘瓶颈。
24.4 写入延迟高
检查:
operation write latency
write conflicts
transaction duration
cache dirty pages
disk util
journal latency
replication lag
index count
处理:
- 控制写入速率;
- 拆小事务;
- 减少热点文档冲突;
- 检查索引数量;
- 评估磁盘性能;
- 降低 Secondary 压力;
- 扩展分片。
24.5 Cache 与磁盘
查看:
db.serverStatus().wiredTiger.cache
典型信号:
| 信号 | 可能 |
|---|---|
| pages read into cache 高 | 工作集大于内存 |
| dirty pages 高 | 写入过快或 checkpoint 慢 |
| pages evicted 高 | cache 竞争 |
| disk util 高 | IO 瓶颈 |
| checkpoint duration 长 | 脏页或磁盘压力 |
止损:
- 停止重查询;
- 限制批处理;
- 扩容内存;
- 归档冷数据;
- 增加分片;
- 优化索引和工作集。
24.6 复制延迟
查看:
rs.printSecondaryReplicationInfo()
rs.status()
原因:
- Secondary 磁盘慢;
- 网络带宽不足;
- 重查询影响;
- 索引构建;
- 大量写入;
- 大事务;
- 初始同步。
处理:
- 停止 Secondary 重负载;
- 降低写入;
- 修复网络;
- 等待索引完成;
- 必要时重新同步;
- 切读回 Primary。
24.7 选举异常
检查:
rs.status()
db.hello()
原因:
- Primary 故障;
- 网络分区;
- 多数成员不可用;
- priority 配置错误;
- 节点资源异常;
- 心跳超时。
处理:
- 恢复多数成员;
- 检查网络;
- 恢复磁盘和进程;
- 手动 stepDown 前确认目标健康;
- 保留选举日志。
24.8 正在执行的长时间操作
查看:
db.currentOp({
active: true,
secs_running: { $gte: 60 }
})
终止:
db.killOp(opid)
注意:
- 确认不是事务协调关键操作;
- 记录操作来源;
- 应用端同时取消;
- 强杀是止损,不是根因修复;
- 必须追溯为什么无超时。
24.9 分片问题
常见现象:
| 现象 | 排查 |
|---|---|
| 查询广播 | 查询不带分片键 |
| 某 shard 慢 | 数据倾斜、热点、资源 |
| 迁移卡住 | 网络、目标空间、元数据 |
| mongos 错误 | 路由缓存、Config 状态 |
| chunk jumbo | 分片键频率过高 |
查看:
sh.status()
use config
db.chunks.find({ ns: "shop.orders" })
24.10 数据不一致疑云
分层确认:
application sent?
-> write ack?
-> primary visible?
-> majority committed?
-> secondary read?
-> application cache?
-> downstream index?
处理前先保存:
- 文档
_id; - 请求 ID;
- 写关注和读偏好;
- 操作时间;
- oplog 或审计;
- 应用日志。
24.11 应急预案
| 故障 | 止损 |
|---|---|
| 无 Primary | 恢复多数成员、降级写 |
| 磁盘将满 | 停批处理、扩容、清理临时文件 |
| cache 压力 | 停重查询、限流、扩内存 |
| 复制延迟 | Secondary 摘读、恢复资源 |
| 慢查询风暴 | 限流、kill、启用缓存 |
| 误删除 | 停写、备份、时间点恢复 |
| 分片迁移压力 | 暂停 balancer |
本章小结
MongoDB 故障通常由查询、索引、cache、磁盘、复制、选举或分片路由共同造成。先用 serverStatus、rs.status、Profiler、explain 和系统指标固定证据,再做可回滚动作。恢复后必须验证业务数据和复盘。
思考题
- 为什么排障初期不建议直接重启?
secs_running高的操作如何处理?- 复制延迟的常见原因有哪些?
- 广播查询为什么代价高?
- 误删除后第一步应该做什么?