bigywater.tech
MongoDB · 88

FTDC:诊断数据里记了什么

mongod 一直在往 diagnostic.data 里写什么?格式是什么?能不能自己读出来?这篇写了个解码器,拿已知的 5,000 次插入去验证。

5,036
一个采样里的指标个数
7000
解码出的 opcounters.insert 总增量,与真实插入一致
5.6×
一个块的 zlib 压缩比(32,183 → 181,762 字节)

默认配置

实测 · 本机执行输出
  参数: {'diagnosticDataCollectionDirectorySizeMB': 500, 'diagnosticDataCollectionEnabled': True, 'diagnosticDataCollectionFileSizeMB': 10, 'diagnosticDataCollectionPeriodMillis': 1000, 'diagnosticDataCollectionSamplesPerChunk': 300, 'diagnosticDataCollectionSamplesPerInterimUpdate': 10}
  刚启动约 3 秒后目录里的文件: [('metrics.2026-10-12T06-07-05Z-00000', 69922)]
  在运行期间精确插入了 5,000 个文档(serverStatus 的 opcounters.insert 从 2000 涨到 7000)
  运行约 36 秒后(mongod 还在运行)目录里的文件: [('metrics.2026-10-12T06-07-05Z-00000', 69922), ('metrics.interim', 32159)]
  mongod 正常关闭之后: [('metrics.2026-10-12T06-07-05Z-00000', 102144)]

FTDC 默认开启,每秒一个采样,每块 300 个采样,单文件 10 MB、目录 500 MB。

文件格式

实测 · 本机执行输出
  metrics.2026-10-12T06-07-05Z-00000:102,144 字节,共 4 个 BSON 文档,type 的计数 = {0: 1, 2: 1, 1: 2}
  type 0 文档的字段: ['_id', 'type', 'doc'],doc 里的顶层字段: ['start', 'buildInfo', 'getCmdLineOpts', 'hostInfo', 'end']
  type 1 文档:_id = 2026-10-12 06:07:05.004000,data 是 BinData 30,356 字节,前 4 字节 = 解压后长度 177,308
  type 1 文档:_id = 2026-10-12 06:07:06.005000,data 是 BinData 32,183 字节,前 4 字节 = 解压后长度 181,762

顺序排列的 BSON 文档:type 0 元数据、type 1 压缩指标块、type 2 周期性元数据;未满的块先写在 metrics.interim,正常关闭时刷成正式块。

解压一个块

实测 · 本机执行输出
  块 0:1 个采样,5,033 个指标,压缩后 30,356 字节,解压后 177,308 字节
  块 1:37 个采样,5,036 个指标,压缩后 32,183 字节,解压后 181,762 字节
  取采样最多的块 1:压缩后 32,183 字节 → 解压后 181,762 字节(压缩比 5.6×)
  参考文档的顶层字段: ['start', 'serverStatus', 'connPoolStats', 'networkInterfaceStats', 'transportLayerStats', 'end']
  指标个数(数值型叶子字段)= 5,036,采样个数 = 37

zlib 解压后是参考文档、指标数、增量数,然后是 varint 编码的差值;指标集变化时开新块。

指标

实测 · 本机执行输出
  {'serverStatus.metrics': 1922, 'serverStatus.wiredTiger': 1460, 'serverStatus.queues': 433, 'serverStatus.incrementalRollout': 192, 'serverStatus.lockContentionMetrics': 144, 'serverStatus.locks': 132, 'serverStatus.opLatencies': 84, 'serverStatus.searchTaskExecutorMetrics': 82, 'serverStatus.network': 68, 'connPoolStats': 59}

一个采样 5,036 个指标,主要是 serverStatus 的各个部分,另有连接池统计。

验证解码

实测 · 本机执行输出
  所有块的指标名完全相同: False(每个块的指标集若变了就要开新块)
  共 38 个采样;start 时间戳相邻差(毫秒)最常见的取值: [(1000, 15), (996, 3), (1004, 3), (995, 3)]
  opcounters.insert 序列首尾: 0 → 7000
  insert 计数有变化的采样 (第几个采样, 增量): [(5, 2000), (10, 2000), (11, 2000), (12, 1000)]
  增量之和 = 7000;其中 2,000 来自先插入的那批,后面 5 次 insert_many(各 1,000 个)分落在三个采样里;serverStatus 自己读到的 2000 → 7000,增量 5000
  serverStatus.connections.current 序列的取值: [0, 3, 5]

写了解码器还原序列:opcounters.insert 的增量之和 7000,与 serverStatus 读到的一致。

占用空间

实测 · 本机执行输出
  取采样最多的块(37 个采样)分开压缩:参考文档(完整的第一个采样,177,418 字节)压缩后 30,562 字节;其余 36 个采样的差值流(4,344 字节)压缩后 1,536 字节 → 每个采样的差值约 43 字节
  按每块 300 个采样估算:每块约 43 KB,每天 288 块约 12.5 MB;500 MB 的目录上限约够 40 天(这是空闲实例的外推,不是实测)

参考文档压缩后约 30 KB,每个采样的差值约 43 字节;空闲实例每天约 12.5 MB 的估算下,500 MB 约能保存 40 天。

分步演示

FTDC 诊断数据
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / MongoDB 9.0.2(Homebrew 的 mongod、mongos)/ mongosh 2.12.0 / pymongo 4.18.3;每个实验在临时目录里起全新的 mongod(独立 dbpath,端口 9900 以上,只监听 127.0.0.1,WiredTiger 缓存 0.25 GB),需要副本集或分片集群时在本机起多个进程;命令输出来自真实的 mongosh,批量写入、计时与多线程用 pymongo;计时用 time.perf_counter,数字每次运行会有小幅抖动,ObjectId、时间戳等每次运行都不同。单机 mongod,运行约 36 秒,关闭后读取 diagnostic.data;解码器是按 FTDC 格式自己写的 Python,用已知负载校验了 opcounters.insert
    • 没有验证:Linux 上 systemMetrics(CPU、内存、磁盘)这一组指标(macOS 上参考文档里没有);副本集上的 replSetGetStatus 与 oplog 统计;繁忙实例的块大小和实际保留天数;文件满 10 MB 轮转与目录超过 500 MB 删除最旧文件的行为;metrics.interim 在崩溃后的可读性;type 2 元数据的内容;用 FTDC 做事后分析的具体流程
    京ICP备2026067502号-1京公网安备11010502063487号