第十四章:监控与诊断
最后更新: 2024-01-01
作者: MongoDB Team
页面目录
第十四章:监控与诊断
MongoDB 监控体系与问题诊断
14.1 监控概述
┌─────────────────────────────────────────────────────────────────┐
│ MongoDB 监控架构 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ mongod │ │ mongos │ │ mongod │ │
│ │ 节点 1 │ │ Router │ │ 节点 2 │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │
│ └──────────────────┼──────────────────┘ │
│ │ │
│ ┌────────▼────────┐ │
│ │ 指标采集 │ │
│ │ serverStatus │ │
│ │ collStats │ │
│ │ indexStats │ │
│ └────────┬────────┘ │
│ │ │
│ ┌────────▼────────┐ │
│ │ 监控工具 │ │
│ │ MongoDB Ops │ │
│ │ Prometheus │ │
│ │ Grafana │ │
│ └────────┬────────┘ │
│ │ │
│ ┌────────▼────────┐ │
│ │ 告警 │ │
│ │ AlertManager │ │
│ └────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
14.2 serverStatus
基本状态
// 获取服务器状态
db.adminCommand({ serverStatus: 1 })
// 获取简化状态
db.serverStatus()
// 获取特定部分
db.adminCommand({
serverStatus: 1,
metricNames: ["connections", "network", "opLatencies"]
})
关键指标说明
// connections - 连接状态
db.serverStatus().connections
{
current: 125, // 当前连接数
available: 1875, // 可用连接数
totalCreated: 4521 // 总创建连接数
}
// opLatencies - 操作延迟
db.serverStatus().opLatencies
{
reads: { latencyMicros: 523, ops: 1523 },
writes: { latencyMicros: 312, ops: 892 },
commands: { latencyMicros: 145, ops: 456 }
}
// asserts - 断言统计
db.serverStatus().asserts
{
regular: 0,
warning: 0,
msg: 0,
user: 5, // 用户触发断言(如唯一键冲突)
tripwire: 0
}
// 内存使用
db.serverStatus().mem
{
resident: 8192, // 物理内存使用(MB)
virtual: 16384, // 虚拟内存使用(MB)
mapped: 4096, // 映射内存
mappedWithJournal: 8192
}
14.3 collStats 和 indexStats
集合统计
// 查看集合统计
db.orders.stats()
// 查看集合大小(字节)
db.orders.dataSize()
// 查看集合大小(含索引)
db.orders.totalSize()
// 查看索引大小
db.orders.totalIndexSize()
// 查看集合计数
db.orders.count()
// 查看集合磁盘空间
db.collection.stats({ scale: 1024 * 1024 }) // MB
// 批量查看所有集合统计
db.getCollectionNames().forEach(function(collection) {
var stats = db.getCollection(collection).stats();
print(collection + ": " + stats.count + " documents, " +
(stats.size / 1024 / 1024).toFixed(2) + " MB");
})
索引统计
// 查看集合的索引
db.orders.getIndexes()
// 查看索引使用统计(需要启用)
db.orders.aggregate([{ $indexStats: {} }])
// 索引统计示例输出
[
{
name: "user_id_1",
key: { user_id: 1 },
host: "mongo1:27017",
accesses: {
ops: 15234,
since: ISODate("2024-01-01")
}
}
]
14.4 Profiler 分析
启用分析器
// 启用分析器(记录慢查询)
// level: 0=关闭, 1=慢查询, 2=所有操作
db.setProfilingLevel(1, { slowms: 100 })
// 查看当前配置
db.getProfilingStatus()
// 记录所有操作
db.setProfilingLevel(2)
// 关闭分析器
db.setProfilingLevel(0)
分析慢查询
// 查看最近的慢查询
db.system.profile.find().sort({ millis: -1 }).limit(10)
// 按查询时间过滤
db.system.profile.find({
millis: { $gt: 1000 }
}).sort({ ts: -1 }).limit(10)
// 按集合过滤
db.system.profile.find({
ns: "mydb.orders"
}).sort({ millis: -1 }).limit(10)
// 按操作类型过滤
db.system.profile.find({
op: "query"
}).sort({ millis: -1 }).limit(10)
// 常用 op 类型
// "query" - find 查询
// "insert" - 插入操作
// "update" - 更新操作
// "remove" - 删除操作
// "aggregate" - 聚合管道
分析报告
// 生成慢查询分析报告
function analyzeSlowQueries() {
var report = {
total: 0,
byCollection: {},
byOperation: {},
byTime: {}
};
db.system.profile.find({
ts: { $gt: new Date(Date.now() - 3600000) } // 最近 1 小时
}).forEach(function(doc) {
report.total++;
// 按集合统计
var coll = doc.ns;
if (!report.byCollection[coll]) {
report.byCollection[coll] = { count: 0, totalTime: 0, avgTime: 0 };
}
report.byCollection[coll].count++;
report.byCollection[coll].totalTime += doc.millis;
// 按操作统计
var op = doc.op;
if (!report.byOperation[op]) {
report.byOperation[op] = { count: 0 };
}
report.byOperation[op].count++;
});
// 计算平均值
for (var coll in report.byCollection) {
var stats = report.byCollection[coll];
stats.avgTime = (stats.totalTime / stats.count).toFixed(2);
}
return report;
}
printjson(analyzeSlowQueries());
14.5 Prometheus 监控
导出器配置
# mongodb_exporter 配置
# https://github.com/percona/mongodb_exporter
version: '3.8'
services:
mongodb-exporter:
image: percona/mongodb_exporter:0.37.0
container_name: mongodb-exporter
environment:
MONGODB_URI: "mongodb://admin:password@localhost:27017"
METRICS_METHOD: "diag"
ports:
- "9216:9216"
restart: unless-stopped
关键监控指标
| 指标 | 说明 | 告警阈值 |
|---|---|---|
mongodb_connections |
当前连接数 | > 80% 最大值 |
mongodb_memory |
内存使用 | > 90% 配置值 |
mongodb_oplatencies |
操作延迟 | p99 > 100ms |
mongodb_replset_member_state |
副本集状态 | != 1 |
mongodb_replset_sync_lag |
复制延迟 | > 10s |
mongodb_asserts |
断言数量 | 增长率 > 0 |
mongodb_lock_* |
锁等待 | > 1s |
Prometheus 配置
# prometheus.yml
scrape_configs:
- job_name: 'mongodb'
static_configs:
- targets: ['mongodb-exporter:9216']
relabel_configs:
- source_labels: [__address__]
target_label: instance
14.6 Grafana 仪表盘
常用仪表盘
{
"dashboard": {
"title": "MongoDB Overview",
"panels": [
{
"title": "Connections",
"targets": [
{
"expr": "mongodb_connections{state='current'}"
}
]
},
{
"title": "Operations/sec",
"targets": [
{
"expr": "rate(mongodb_op_count_total[5m])"
}
]
},
{
"title": "Memory Usage",
"targets": [
{
"expr": "mongodb_memory_bytes{type='resident'}"
}
]
},
{
"title": "Replication Lag",
"targets": [
{
"expr": "mongodb_replset_sync_lag"
}
]
}
]
}
}
关键图表
┌─────────────────────────────────────────────────────────────────┐
│ MongoDB 监控仪表盘布局 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ 连接数 │ │ QPS │ │ 内存使用 │ │
│ │ [ 125 ] │ │ [ 1523 ] │ │ [ 8.2GB ] │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐│
│ │ 操作延迟趋势 ││
│ │ 50ms ┤ ││
│ │ 40ms ┤ █████ ││
│ │ 30ms ┤ █████████████ ││
│ │ 20ms ┤████████████████ ││
│ │ 10ms ┤████████████████████████ ││
│ │ 0ms ┼────────────────────────────────────────────── ││
│ │ 00:00 04:00 08:00 12:00 16:00 20:00 24:00 ││
│ └─────────────────────────────────────────────────────────────┘│
│ │
│ ┌─────────────────────────────────────────────────────────────┐│
│ │ 副本集状态 ││
│ │ PRIMARY [✓] SECONDARY [✓] SECONDARY [✓] ARBITER [✓] ││
│ └─────────────────────────────────────────────────────────────┘│
│ │
└─────────────────────────────────────────────────────────────────┘
14.7 诊断脚本
健康检查脚本
// health-check.js
function checkMongoHealth() {
var health = {
status: "OK",
timestamp: new Date(),
checks: []
};
// 1. 基本状态检查
try {
var serverStatus = db.adminCommand({ serverStatus: 1 });
health.checks.push({
name: "serverStatus",
status: "OK",
uptime: serverStatus.uptime
});
} catch (e) {
health.status = "ERROR";
health.checks.push({ name: "serverStatus", status: "ERROR", error: e.message });
}
// 2. 副本集检查
try {
var rsStatus = rs.status();
var primary = rsStatus.members.find(m => m.stateStr === 'PRIMARY');
var secondaries = rsStatus.members.filter(m => m.stateStr === 'SECONDARY');
if (primary) {
health.checks.push({
name: "replicaSet",
status: "OK",
primary: primary.name,
secondaries: secondaries.map(s => s.name)
});
// 检查复制延迟
secondaries.forEach(s => {
if (s.health === 1 && s.optimeDate) {
var lag = (new Date() - s.optimeDate) / 1000;
if (lag > 10) {
health.checks.push({
name: "replicationLag",
status: "WARNING",
member: s.name,
lagSeconds: lag
});
}
}
});
} else {
health.status = "WARNING";
health.checks.push({
name: "replicaSet",
status: "WARNING",
message: "No primary detected"
});
}
} catch (e) {
// 非副本集环境
}
// 3. 连接数检查
try {
var connections = serverStatus.connections;
var usagePercent = (connections.current / connections.available) * 100;
health.checks.push({
name: "connections",
status: usagePercent > 80 ? "WARNING" : "OK",
current: connections.current,
available: connections.available,
usagePercent: usagePercent.toFixed(1) + "%"
});
if (usagePercent > 90) {
health.status = "CRITICAL";
}
} catch (e) {}
// 4. 磁盘空间检查
try {
var stats = db.adminCommand({ dbStats: 1 });
// 需要结合文件系统检查
} catch (e) {}
return health;
}
printjson(checkMongoHealth());
定期监控脚本
#!/bin/bash
# monitor.sh
MONGODB_URI="mongodb://admin:password@localhost:27017"
# 检查连接
echo "=== MongoDB Status ==="
mongosh "$MONGODB_URI" --quiet --eval 'printjson(db.adminCommand({ serverStatus: 1 }).ok)'
# 检查副本集
echo -e "\n=== Replica Set Status ==="
mongosh "$MONGODB_URI" --quiet --eval 'rs.status().ok && rs.status().members.forEach(m => print(m.name + ": " + m.stateStr))'
# 检查连接数
echo -e "\n=== Connections ==="
mongosh "$MONGODB_URI" --quiet --eval '
var c = db.adminCommand({ serverStatus: 1 }).connections;
print("Current: " + c.current + ", Available: " + c.available)
'
# 检查慢查询
echo -e "\n=== Slow Queries (last hour) ==="
mongosh "$MONGODB_URI" --quiet --eval '
db.system.profile.find({
ts: { $gt: new Date(Date.now() - 3600000) }
}).sort({ millis: -1 }).limit(5).forEach(q => {
print("Collection: " + q.ns + ", Time: " + q.millis + "ms")
})
'
# 检查索引使用
echo -e "\n=== Index Access Stats ==="
mongosh "$MONGODB_URI" --quiet --eval '
db.getSiblingDB("mydb").mycollection.aggregate([{ $indexStats: {} }]).forEach(idx => {
print(idx.name + ": " + idx.accesses.ops + " ops")
})
'
14.8 告警配置
告警规则
# Prometheus 告警规则
groups:
- name: mongodb
rules:
# 连接数告警
- alert: MongoDBHighConnections
expr: mongodb_connections{state="current"} / mongodb_connections{state="available"} > 0.8
for: 5m
labels:
severity: warning
annotations:
summary: "MongoDB 连接数过高"
description: "当前连接数 {{ $value }}%"
# 复制延迟告警
- alert: MongoDBReplicationLag
expr: mongodb_replset_sync_lag > 10
for: 2m
labels:
severity: critical
annotations:
summary: "MongoDB 复制延迟"
description: "复制延迟 {{ $value }} 秒"
# 副本集故障告警
- alert: MongoDBReplicaSetDown
expr: mongodb_replset_member_state != 1
for: 1m
labels:
severity: critical
annotations:
summary: "MongoDB 副本集成员不可用"
# 操作延迟告警
- alert: MongoDBHighLatency
expr: rate(mongodb_op_latency_sum[5m]) / rate(mongodb_op_latency_count[5m]) > 100
for: 5m
labels:
severity: warning
annotations:
summary: "MongoDB 操作延迟过高"
💡 实践提示
- 建立基线:记录正常状态的指标,便于对比分析
- 分层监控:应用层、数据库层、系统层全方位监控
- 告警阈值:根据业务特点设置合理的告警阈值
- 日志关联:结合日志和监控数据进行问题诊断
- 定期巡检:定期执行健康检查脚本
📚 继续学习