ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

MongoDB 性能监控实战:Prometheus + Grafana 仪表板搭建指南

MongoDB 性能监控实战:Prometheus + Grafana 仪表板搭建指南 说实话MongoDB 跑起来很容易但等它性能出问题的时候你往往无从下手。这个项目就是围绕“MongoDB 性能监控仪表板”展开的核心链路是用 Prometheus 抓取 MongoDB 的运行时指标再交给 Grafana 渲染成可视化大盘。整套东西能覆盖连接数、操作量、内存、复制延时、慢查询等关键维度适合自己搭了 Mongo 集群又不想用官方云服务的后端、运维和偏运维的 DBA 参考。很多时候你只需要看一眼仪表板就能判断是索引问题还是锁竞争不用再挨个节点 SSH 上去敲命令对参数。这篇实战会从环境准备一直写到告警配置过程中把实打实踩过的坑也一并列出来希望你能少绕点弯路。1. 先想清楚监控 MongoDB 到底要解决什么问题1.1 为什么选 Prometheus Grafana而不是 MongoDB 官方全家桶一提 MongoDB 监控很多人第一反应是 Ops Manager、Atlas 高级监控或者第三方的 Percona Monitoring and ManagementPMM。这些工具的界面确实漂亮开箱即用但绑定感太强。社区版的 MongoDB 本来就没有 Ops ManagerAtlas 监控只覆盖云托管实例PMM 则是整套 PMM Server Client 体系光部署就够喝一壶后续升级还会连带好多组件。如果只是想要“一个能看到 QPS、连接数、复制延迟的仪表板”这些方案明显过重。Prometheus Grafana 不一样。它本质是一套“抓取、存储、展示、告警”的标准管线Prometheus 定期从 exporter 暴露的 HTTP 端点拉取指标存入自带的时间序列数据库Grafana 再用 PromQL 去查询这些指标画图。这套链路的好处是什么数据库层面是通用的。你今天监控 MongoDB明天要监控 MySQL、Redis、Nginx加一个 exporter、加一段 scrape_config照样进同一套 Grafana。对于团队里已经有 Prometheus 基础设施的公司新增一个 Mongo 监控的成本几乎为零。另外一个容易被忽略的点是标签体系。Prometheus 的指标自带 label比如会用instance区分不同节点用replset区分副本集。这样一来同一个面板模板可以同时展示整个集群的多个节点状态鼠标点一下 label 就能切换视角。这点比传统监控一个个单独配置要灵活太多也是我后来越来越愿意用它的原因。方案部署复杂度费用扩展性适合场景MongoDB Ops Manager高需独立部署企业版限额绑定 MongoDB 生态大型企业、统一管理大量集群Atlas Advanced Monitoring低云上即开按节点收费仅限 Atlas 托管实例用 Atlas 的团队Prometheus Grafana中组件多但单点开源免费极强一套监控全家桶自建 Mongo、愿意花时间打磨的团队1.2 数据从哪里来mongodb_exporter 在整个链路里的位置这条监控链路的中间人是 mongodb_exporter。你可能要问了Prometheus 为什么不直接连 MongoDB 拿数据因为 MongoDB 原生不暴露 Prometheus 格式的指标它的状态数据藏在serverStatus()、dbStats()、collStats()这些命令的返回里。exporter 的作用就是定期调用这些命令把结果翻译成 Prometheus 能识别的指标格式再放到 HTTP 端点等 Prometheus 来拉。这里有个关键认知MongoDB 的监控指标是分层的。第一层是实例级来自serverStatus()包括连接数、操作计数、内存、网络、复制状态等这类指标最核心。第二层是库级来自dbStats()能告诉你某个数据库占了多少磁盘、多少个集合、平均文档大小。第三层是集合级来自collStats()、indexStats()能看到每个集合的文档数、索引大小、碎片情况。对应到 MongoDB 的核心概念来说数据库database和集合collection在监控里就是你说的库级、集合级指标而文档document级别一般不会直接监控真到了单条文档的定位问题通常要靠慢日志和应用日志去追。搞清楚这个分层你就明白为什么 exporter 有那么多 collector 开关了。只做基础监控默认的实例级指标就够用想把每个集合的存储趋势也看明白就要额外开启--collector.dbstats和--collector.collstats。后面实操部分我会再展开讲参数这里先记住一句话exporter 的采集范围是可控的不是越全越好越全对数据库本身的压力就越大。2. 环境准备从零搭一套能用的监控环境2.1 先把 MongoDB 装好并跑起来常见的安装失败排查这个项目的前提是 Mongo 本身能连否则后面全是白搭。很多人第一步就卡在“mongod 装了但起不来”。我见过最多的报错无非这几类用apt install mongodb会装到 Ubuntu 自带的旧版包版本老得离谱很多监控指标命令缺失建议用官方源装mongodb-org。启动时日志报Permission denied或者缺少/var/lib/mongodb目录这是目录权限问题chown 给mongodb:mongodb基本能解。配置文件里用了 Tab 缩进。MongoDB 的mongod.conf是 YAML 格式YAML 不能用 Tab藏得很深报错又不容易一眼看出来。装好后直接跑mongosh -u xxx认证失败很可能是因为net.bindIp还写着127.0.0.1外部机器根本连不进来。验证方式很简单先在本地跑一句mongosh --eval db.runCommand({ping:1})能返回{ ok: 1 }就算 Ok。如果这一步都过不了先别碰监控把 Mongo 本身弄干净再说。我习惯在项目最开始就写清楚数据库版本、端口、是否开启认证后面配 exporter 连接串和告警阈值会省很多事。2.2 部署 Prometheus配置文件里的 target 就是数据源Prometheus 本身是个单个二进制的 Go 程序装起来非常简单。下载对应架构的 tar 包解压或者直接用容器跑都行。我建议用二进制方式方便你用 systemd 管理也方便理解整个文件结构。核心动作是改prometheus.yml。这是全局配置你需要在scrape_configs里把 mongodb_exporter 的地址加进去。最简版是这样global: scrape_interval: 15s evaluation_interval: 15s scrape_configs: - job_name: mongodb static_configs: - targets: [127.0.0.1:9216] labels: instance: mongo-01注意这里的scrape_interval我习惯设 15 秒。太快了对 exporter 和 Mongo 都有不必要的压力太慢了比如 60 秒遇到连接数飙涨这类瞬时故障面板上只能看到锯齿状的残缺曲线排查时很容易漏掉关键证据。配置文件改好后后台启动prometheus --config.fileprometheus.yml --storage.tsdb.retention.time30d--storage.tsdb.retention.time是时序数据保留时长默认 15 天。这个参数定多大取决于你想回溯多久的性能数据。磁盘够大就留 30 天别上来就整一年Prometheus 存高基数的指标时磁盘空间和查询响应时间都会让你后悔。启动后去http://localhost:9090/targets看一眼能搜到 mongodb 这个 job 并且 state 是 UP说明抓取链路已经通了。2.3 Grafana 安装启动端口占用与初始化密码Grafana 的安装更无脑一个 deb/rpm 包装好或者docker run -d --namegrafana -p 3000:3000 grafana/grafana默认监听 3000 端口。这里有个高频坑如果你本地已经开了其他服务占着 3000Grafana 启动会反复报 “bind: address already in use”很多人以为装失败了其实改一下配置就行。编辑 Grafana 的app.ini把http_port改成比如 3001重启完就能访问。第一次打开 Grafana默认账号密码是admin/admin登录后第一件事就是强制改密码。这个没什么好说的安全习惯要好。另外提醒一点Grafana 本身是无状态的面板配置存在它的 SQLite 元数据库里。看起来不像什么大事但我建议你把后面导入的每个 dashboard 的 JSON model 下载下来跟着配置文件放一起管理。重装 Grafana 时一键导入就恢复了这个习惯能避免很多返工。3. 集成实战把 MongoDB 指标真正接到 Grafana 仪表板3.1 创建最小权限监控账号连接串里藏着的坑生产环境的 MongoDB 一般都要开启认证不会让你裸奔。那 exporter 连接 Mongo 用什么账号很多人图省事直接丢一个 root 账号进去这是非常危险的做法。监控工具的数据源一旦泄露等于把整个库的管理权限送给别人。我建议单独建一个专用账号只给监控需要的权限。在mongosh里执行use admin db.createUser({ user: mongo-monitor, pwd: 用密码生成器造一个强口令, roles: [ { role: clusterMonitor, db: admin }, { role: readAnyDatabase, db: admin }, { role: read, db: local } ] })这里用到的是 MongoDB 内置角色。clusterMonitor给的是serverStatus、replSetGetStatus等实例级监控命令的权限readAnyDatabase用来支撑dbStats、collStats这类库级集合级读取local库上的read是为了读副本集相关配置。实践下来这一套权限组合是监控场景里比较标准的配置既不会给业务读写风险又能覆盖绝大多数 dashboard 的查询需求。有了账号exporter 的连接串要写成带认证信息的形式。以官方 mongodb_exporter 为例./mongodb_exporter \ --mongodb.urimongodb://mongo-monitor:强口令127.0.0.1:27017/admin?sslfalse \ --collector.dbstats \ --collector.collstats \ --collector.indexstats \ --collector.replicasetstatus \ --web.listen-address127.0.0.1:9216这里有个非常容易踩的坑认证库不是test不是admin的前面那个名字而是你db.createUser时use admin的admin。连接串里/admin指的是认证数据库如果写成了其他库exporter 启动时大概率报Authentication failed。另外新版 mongodb_exporter 默认不开启所有 collector不加--collector.collstats的话你即使导入社区仪表板集合层面的面板全是空的。很多人一上来就骂官方仪表板有问题其实大半是 collector 没开齐。补充一点如果你的 Mongo 是副本集或者分片集群我建议每个 mongod 节点单独跑一个 exporter 实例不要一个 exporter 连接整个副本集地址。原因很简单exporter 每次调用serverStatus只能拿到当前连接节点的状态如果你用副本集地址它只会连到其中一个节点抓到的状态是漂移的做报警时很不可靠。每个节点一个 exporterPrometheus 侧用instance标签区分后面 Grafana 里看多个节点就非常直观。3.2 Grafana 数据源接入和仪表板导入Grafana 装好之后先加数据源。路径是Configuration Data Sources Add data source类型选 PrometheusURL 填http://localhost:9090。这里唯一要留意的是网络模式Prometheus 和 Grafana 都跑在宿主机的话localhost没问题如果 Grafana 是容器而 Prometheus 是宿主机进程localhost:9090指向的是容器内部妥妥连不上。要么用host.docker.internal:9090要么直接让 Grafana 也用 host 网络。数据源加好可以先在 Explore 里跑一句mongodb_up能出1就说明 Prometheus 到 exporter 这层已经通了。之后导入 dashboard打开Dashboards Import在Grafana.com dashboard ID框里填社区仪表板 ID。比较常用的是 2583 和 12083前者老一些后者新版指标适配更好。如果你不确定就去 grafana.com 的官网搜 MongoDB挑 star 数高的就行。很多时候导入之后面板还是空的先别急着怀疑插件坏了。按我的排查顺序走第一步确认 Prometheus 里mongodb_up 1第二步在 Explore 里看看那些mongodb_mongod_*指标到底有没有数据第三步打开具体面板的编辑模式看它的 PromQL 是否和你环境里的指标名对得上。这一步十有八九能发现是 exporter 版本差异导致指标名变了。版本不同指标名确实会从mongodb_connections_current这种旧风格迁移到mongodb_mongod_connections_current新风格dashboard 作者没跟上版本就会留坑。实战里不要死记指标名学会用 Prometheus 表达式浏览器搜{__name__~mongodb_.*}就足够了。3.3 核心 PromQL 查询与面板解读哪些指标真正有用dashboard 导入只是第一步你得看懂每个面板在表达什么。这里挑几个最关键的查询对应到日常运维最关心的几个问题关注点PromQL 示例说明当前连接数mongodb_mongod_connections_current和 maxIncoming 对比连接数接近 max 就是 Connections 告警的预兆操作 QPSsum(rate(mongodb_mongod_op_counters_total[1m])) by (type)按 insert/query/update/delete/command 分类看各类型占比复制延迟mongodb_mongod_replset_optime_behind单位通常是秒长期大于 0 说明 secondary 追不上主节点进程内存占用mongodb_mongod_process_resident_memory_bytes结合系统可用内存判断 Mongo 是否有内存压力或配置不合理的 cache 占用我看面板的习惯是这样的先看op_counters的整体曲线确认当前有没有明显的读写尖峰再看连接数是否同步上涨如果两者都涨说明是正常流量如果连接数涨而 QPS 没涨大概率是连接泄漏或者客户端配置问题最后扫一眼复制延迟确保所有从节点都在安全范围内。这三个维度可以覆盖绝大多数“数据库变慢了”的现场还原。顺带说一句很多 community dashboard 上都有一个叫 “Query Executor / Scanned vs Returned” 的面板本质是想让你看扫描文档数和返回文档数的比例。如果这个比例长期大到离谱直接提示索引没命中或者查询条件写得太宽。这种面板不是所有 dashboard 都有但看到了一定好好留着它是以后做性能调优最宝贵的线索。4. 告警规则与常用排障技巧实录4.1 三条 P1 级告警规则建议光有仪表板还不够出了问题不可能二十四小时盯屏幕告警规则必须配上。Prometheus 的告警规则写在独立 YAML 文件里比如mongo_alerts.yml然后在prometheus.yml里通过rule_files引入rule_files: - mongo_alerts.yml我建议从这三条规则开始覆盖最关键的稳定性和高可用场景groups: - name: mongodb_alerts rules: - alert: MongoDBDown expr: mongodb_up 0 for: 5m labels: severity: critical annotations: summary: MongoDB 实例不可抓取请立即检查 mongod 进程 - alert: MongoDBReplicationLagHigh expr: mongodb_mongod_replset_optime_behind 60 for: 5m labels: severity: warning annotations: summary: 从节点复制延迟超过 60 秒这里有一个特别要注意的点规则里的指标名一定要用你当前环境里实际存在的指标名。不同 exporter 版本之间复制延迟的指标名有可能从mongodb_replset_optime_behind变成mongodb_mongod_replset_optime_behind。验证办法是在 Prometheus 的 Alerts 页面看规则能否正确求值如果提示 “no data” 或者 “vector does not contain”就要回头改指标名。我见过太多人照着网上的规则文件一贴以为完事了结果评估半天全是不满足条件的空查询等同于没告警。告警阈值不要拍脑袋。每个环境的基准不一样如果是写入密集的日志系统QPS 每分钟上十万也正常。我习惯先观察两周看面板上的常态水位再在常态水平上留出 50% 的余量来设阈值。从 80% 的连接数占用率开始告警复制延迟超过 60 秒开始告警这两个阈值对大多数中小团队是合理的起点。4.2 新手最容易踩的坑从“安装失败”到“面板空白”现在把实战里的高频问题集中说一下。这些坑我基本都亲身踩过一遍哪怕你只避掉其中两个今天这一整篇也算没白看。mongodb_exporter 启动报Authentication failed。前一步的连接串认证库写错了。记住db.createUser时use的库是哪个连接串里就写哪个通常都是admin。启动报--collector.collstats requires --collector.dbstats。这种情况直接两个参数一起开因为collStats的数据依赖dbStats拉取的数据库列表。Prometheus 起不来检查 YAML 缩进。Prometheus 对配置里的 Tab 零容忍编辑器里把 “显示空白字符” 开关打开确保所有缩进都是空格。Grafana 导入仪表板后一张图都没有最常见原因是数据源没有设置为默认。导入面板时有个下拉框让你选数据源如果界面里的面板用的是DS_PROMETHEUS变量数据源没匹配上就会这样。Mongo 和 exporter 之间网络不通。exporter 和 mongod 是不是在同一台机器如果 exporter 配了--web.listen-address127.0.0.1:9216Prometheus 却装在另一台机器上自然抓取不到。监听地址要么改成0.0.0.0:9216要么让 Prometheus 和 exporter 同机部署二选一。面板图表固定出现“无数据”但 PromQL 明明能查到。检查仪表板右上角的时间范围刚开始采集的指标可能只有最近 15 分钟的数据而默认时间范围是过去 6 小时尝试切到Last 15 minutes再看。一直开着 collstats 采集把 MongoDB 拖慢了。集合级统计是轮询扫描采集范围大、频率高时对实例是有真实压力的。日常只开启实例级和dbstatscollstats在专项排障时再临时打开。用第三方 GUI 工具的“破解”渠道。我知道很多人喜欢拿 NoSQLBooster 这种工具连 Mongo网上也确实流传过所谓破解版。这里我明确劝退破解工具往往捆绑后门而 GUI 工具连接字符串里存的可都是生产库的账号密码何必拿生产安全换一个看似省钱的便利。官方 MongoDB Compass 已经免费且好用监控连接请始终使用最小权限账号不要图省事把业务账号填进任何工具里。4.3 进阶技巧从仪表板往下钻定位慢查询和锁问题仪表板能告诉你“现在慢”但更要想办法回答“为什么慢”。Prometheus 的作用是缩小范围具体原因还需要和 Mongo 的日志、profiler 配合。比如某个面板显示query的 QPS 没有明显上涨但数据库整体 CPU 飙升这时候不要急着去 mongod 里找慢查询先在 Mongo 侧开启 profilingdb.setProfilingLevel(1, { slowms: 200 })这里把超过 200ms 的查询都记录到system.profile集合里积累几分钟后就可以去查db.system.profile.find({ op: query }).sort({ millis: -1 }).limit(20)同样的思路也可以用来看“查询和删除”这种操作慢在哪里是COLLSCAN了还是内存排序过大还是锁等待时间太长。Prometheus 负责持续盯梢profiler 负责精准打击这俩组合起来才是完整的性能问题排查闭环。这里再顺手分享一个锁相关的常用指标。MongoDB 的锁等待信息在serverStatus().locks里对应到 Prometheus 里一般会有mongodb_mongod_locks_*之类的指标。你做性能分析时可以加一个面板把全局锁的等待时间画出来。一旦发现写入慢的趋势同时锁等待曲线也在上涨基本可以断定是并发写冲突而不是磁盘 IO 的问题。这个判断依据能帮你少走很多弯路。从整个项目体量看这套“MongoDB 性能监控仪表板”并不复杂难点在于把每个环节的细节都处理到位。我个人在实际操作中最大的体会是抓取间隔不要过度追求短15 秒已经能让绝大多数瞬时故障留下痕迹collstats 这类重量级采集只在排障时临时开启开一晚上你会发现数据库负载凭空高了一截。最后再说一个实用技巧把 Grafana 面板导出的 JSON、prometheus.yml、告警规则一起放进 git 管理等哪天机器要重装或者换团队接手十分钟就能把这套系统原样拉起来。监控从来不是一个一次性搭建的活它应该和你写的代码一样有版本、有备份、有迭代。
返回列表