Skip to content

MongoDB 性能监控:mongostat、mongotop、Profiler

MongoDB 跑得怎么样?有没有慢查询?内存够不够?

这一篇,我来介绍 MongoDB 的监控工具。

MongoDB 监控工具概览

工具用途实时性
mongostat查看数据库操作统计实时
mongotop查看集合级别的读写时间实时
Profiler记录慢查询可配置
serverStatus服务器状态统计实时
db.stats()数据库统计信息静态
coll.stats()集合统计信息静态

mongostat:操作统计

基本用法

bash
# 每秒刷新一次
mongostat --port 27017

# 每 5 秒刷新一次,显示 3 次
mongostat --port 27017 5 3

# 显示详细信息
mongostat --port 27017 --humanReadable

输出解读

bash
# mongostat 输出示例
insert  query update delete getmore command % idx miss    flushes  vsize   res qrw  arw
*0     *0    *0    *0     0     2|0  0         0       0  1.42GB 1.13GB q0 r0 0|0
10     50    20     5     0    100|0  0         0       0  1.45GB 1.15GB q0 r0 0|0
字段说明
insert每秒插入数
query每秒查询数
update每秒更新数
delete每秒删除数
getmore每秒获取更多游标数
command每秒命令数
% idx miss索引未命中率
flushes每秒刷盘次数(Journal)
vsize虚拟内存使用
res实际内存使用
qrw读写队列长度
arw主从读写队列

mongostat 常用参数

bash
# 只看特定字段
mongostat --port 27017 --discover --humanReadable insert query update

# 查看副本集所有成员
mongostat --host rs0/mongo1:27017,mongo2:27017,mongo3:27017

# 查看特定数据库
mongostat --port 27017 --dynamicCollectionNames

mongotop:集合读写时间

基本用法

bash
# 每秒刷新一次
mongotop --port 27017

# 每 3 秒刷新一次
mongotop 3

# 只显示写入
mongotop --port 27017 --locks

输出解读

bash
# mongotop 输出示例
                        ns    total    read    write
              admin.$cmd    0ms     0ms      0ms
            myapp.orders 1234ms   100ms   1134ms
              myapp.users  200ms   200ms      0ms
           myapp.products   50ms    30ms     20ms
字段说明
ns命名空间(数据库.集合)
total该集合总读写时间
read读取时间
write写入时间

serverStatus:服务器状态

基本用法

javascript
// 查看完整状态
db.adminCommand({serverStatus: 1})

// 只看特定部分
db.adminCommand({serverStatus: 1}).connections
db.adminCommand({serverStatus: 1}).mem
db.adminCommand({serverStatus: 1}).wiredTiger

关键指标

javascript
// 1. 连接数
db.adminCommand({serverStatus: 1}).connections

// 输出
{
  "current": 100,        // 当前连接
  "available": 9900,    // 可用连接
  "totalCreated": 50000  // 历史总连接
}

// 2. 内存使用
db.adminCommand({serverStatus: 1}).mem

// 输出
{
  "bits": 64,
  "resident": "2GB",    // 实际占用
  "virtual": "10GB",    // 虚拟内存
  "supported": true
}

// 3. WiredTiger Cache
db.adminCommand({serverStatus: 1}).wiredTiger.cache

// 输出
{
  "maximum bytes configured": "8GB",
  "size in memory": "5GB",
  "percentage of maximum bytes used": "62.5%"
}

Profiler:慢查询分析

开启 Profiler

javascript
// 查看当前配置
db.getProfilingStatus()

// { "was": 0, "slowms": 100, "sampleRate": 1 }

// 开启 Profiler(记录慢查询)
db.setProfilingLevel(1, {slowms: 100})

// 开启 Profiler(记录所有查询)
db.setProfilingLevel(2)

// 参数说明:
// was: 0 - 关闭
// was: 1 - 只记录慢操作
// was: 2 - 记录所有操作

// slowms: 慢查询阈值(毫秒)
// sampleRate: 采样率(0.0 - 1.0)

查看 Profiler 数据

javascript
// 查看最近的慢查询
db.system.profile.find().sort({millis: -1}).limit(10).pretty()

// 输出示例
{
  "op": "query",           // 操作类型
  "ns": "myapp.orders",   // 命名空间
  "command": {
    "find": "orders",
    "filter": {"userId": "123"},
    "limit": 10
  },
  "nreturned": 10,
  "responseLength": 1024,
  "millis": 1234,         // 执行时间(毫秒)
  "ts": ISODate("..."),
  "client": "192.168.1.100",
  "user": "app_user"
}

Profiler 操作类型

op说明示例
query查询db.orders.find()
insert插入db.orders.insertOne()
update更新db.orders.updateOne()
delete删除db.orders.deleteOne()
command命令db.adminCommand()
getmore游标获取翻页

dbStats 和 collStats

dbStats:数据库统计

javascript
// 查看数据库统计
db.stats()

// 输出
{
  "db": "myapp",
  "collections": 10,
  "views": 2,
  "objects": 1000000,          // 文档总数
  "avgObjSize": 1024,         // 平均文档大小
  "dataSize": "1GB",          // 数据大小
  "storageSize": "2GB",       // 磁盘占用
  "indexes": 25,              // 索引数
  "indexSize": "500MB",       // 索引大小
  "totalSize": "2.5GB",       // 总大小
  "scaleFactor": 1
}

collStats:集合统计

javascript
// 查看集合统计
db.orders.stats()

// 输出
{
  "ns": "myapp.orders",
  "count": 1000000,
  "size": "500MB",
  "avgObjSize": 512,
  "numOrphanDocs": 0,
  "storageSize": "600MB",
  "capped": false,
  "wiredTiger": {
    "metadata": {...},
    "compression": "snappy",
    "block signature": "snappy"
  },
  "indexDetails": {...},
  "indexSizes": {
    "_id_": "100MB",
    "userId_1": "80MB",
    "createdAt_1": "90MB"
  }
}

副本集监控

副本集状态

javascript
// 查看副本集状态
rs.status()

// 查看同步状态
rs.printSecondaryReplicationInfo()

// 查看 Oplog 状态
db.getReplicationInfo()

// 输出
{
  "logSizeMB": 10240,
  "usedMB": 2048,
  "timeDiff": 3600,
  "tFirst": "2024-01-01T00:00:00",
  "tLast": "2024-01-01T01:00:00"
}

监控复制延迟

javascript
// 查看每个从节点的延迟
db.adminCommand({replSetGetStatus: 1}).members.forEach(m => {
  if (m.stateStr !== "PRIMARY") {
    const lag = (new Date() - m.optimeDate) / 1000
    print(m.name + ": " + lag + " 秒延迟")
  }
})

Java 监控实现

java
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import org.bson.Document;
import java.util.concurrent.atomic.AtomicReference;

public class MongoMonitor {
    public static void main(String[] args) {
        try (MongoClient client = MongoClients.create()) {
            var admin = client.getDatabase("admin");

            // 1. serverStatus
            Document status = admin.runCommand(new Document("serverStatus", 1));
            System.out.println("=== Server Status ===");
            System.out.println("连接数: " + status.get("connections"));
            System.out.println("内存: " + status.get("mem"));
            System.out.println("WiredTiger: " + status.get("wiredTiger"));

            // 2. collStats
            var collStats = client.getDatabase("myapp")
                .runCommand(new Document("collStats", "orders"));
            System.out.println("=== Orders Collection ===");
            System.out.println("文档数: " + collStats.get("count"));
            System.out.println("大小: " + collStats.get("size"));

            // 3. Profiler
            admin.runCommand(new Document("setParameter", 1)
                .append(" profiler", 2));

            // 4. 副本集状态
            var replStatus = admin.runCommand(new Document("replSetGetStatus", 1));
            System.out.println("=== Replication ===");
            replStatus.getList("members", Document.class).forEach(m -> {
                System.out.println(m.get("name") + ": " + m.get("stateStr"));
            });
        }
    }
}

监控脚本示例

javascript
// MongoDB Shell 监控脚本

// 1. 慢查询检查
function checkSlowQueries() {
  const queries = db.system.profile.find(
    {millis: {$gt: 1000}}
  ).sort({millis: -1}).limit(5)

  print("=== Slow Queries (> 1s) ===")
  queries.forEach(q => {
    print(q.ns + ": " + q.millis + "ms")
    print("Command: " + q.command)
  })
}

// 2. Cache 使用检查
function checkCache() {
  const cache = db.adminCommand({serverStatus: 1}).wiredTiger.cache
  const usage = cache.size in memory / cache.maximum bytes configured * 100

  print("=== WiredTiger Cache ===")
  print("使用率: " + usage + "%")

  if (usage > 80) {
    print("警告:Cache 使用率过高!")
  }
}

// 3. 副本延迟检查
function checkReplicationLag() {
  const status = rs.status()
  const primary = status.members.find(m => m.stateStr === "PRIMARY")

  print("=== Replication Lag ===")
  status.members.forEach(m => {
    if (m.stateStr !== "PRIMARY") {
      const lag = primary.optimeDate - m.optimeDate
      print(m.name + ": " + lag + "ms")
    }
  })
}

// 定期执行
checkSlowQueries()
checkCache()
checkReplicationLag()

总结

监控工具速查:

工具命令用途
mongostatmongostat --port 27017操作统计
mongotopmongotop --port 27017集合读写时间
serverStatusdb.adminCommand({serverStatus: 1})服务器状态
Profilerdb.setProfilingLevel(1, {slowms: 100})慢查询分析
collStatsdb.collection.stats()集合统计
dbStatsdb.stats()数据库统计

核心监控指标

类别指标告警阈值
连接当前连接数> 80% 可用
内存Cache 使用率> 80%
查询慢查询数持续存在
复制从节点延迟> 30 秒

下一步,你可以:

基于 VitePress 构建