第十四章:监控与诊断

最后更新: 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 操作延迟过高"

💡 实践提示

  1. 建立基线:记录正常状态的指标,便于对比分析
  2. 分层监控:应用层、数据库层、系统层全方位监控
  3. 告警阈值:根据业务特点设置合理的告警阈值
  4. 日志关联:结合日志和监控数据进行问题诊断
  5. 定期巡检:定期执行健康检查脚本

📚 继续学习