第7篇 业务数据监控:SQL Exporter 与自定义业务指标

业务数据躺在关系型数据库里,Prometheus 拉不到它,中间必须有人做翻译。而这一层该不该独立部署、该不该在抓取时查库,决定了它是"监控"还是"事故源"。

前几篇已铺满监控体系的外围,但有一个共同点:描述的都是「系统跑得好不好」,而不是「业务现在是什么状态」。

真正的业务真相在数据库里:今天新增了多少订单、还有多少工单压着没人处理、账务对不平的笔数有几条、库存逼近零的商品有几个。而这类问题,都不在 node_exporter、JVM、Blackbox 的探针范围。

本篇讨论的就是这一层:**如何把数据库里的业务数据,稳定、低成本地变成 Prometheus 指标。**由于业务数据都有其独特性,本篇只做粗线条的方案性介绍,不追求面面俱到。


一、为什么必须有中间层

Prometheus 只认一种数据形态:HTTP 端点返回的文本指标

复制代码
metric_name{label="value"} 数值

而数据库吐出来的是结果集(行 × 列)。两者的格式不兼容,中间必须有个 Exporter翻译层。它只做三件事:

  • 按一定节奏向数据库发 SQL;
  • 把结果集的「行 → 标签」「列 → 数值」映射成 Prometheus 样本;
  • 在 /metrics 上以文本格式暴露,等 Prometheus 来抓。

因此采集链路变成:

复制代码
数据库 ──SQL──▶ Exporter ──/metrics(文本)──▶ Prometheus ──▶ Grafana / Alertmanager

但需注意:该 Exporter 不是无状态的旁路组件。每一次采数,都要真实消耗数据库的连接、CPU 和 IO。


二、调研:现成的三方 Exporter 够不够用

结论:绝大多数场景不需要自己写 Exporter,三方方案已经很成熟。

|------------------------------------------------------------|-----------------------------------------------------------------|------------------------------------------------|------------------------------------------------------------------|
| 方案 | 数据库支持 | 能否采集业务数据(自定义 SQL) | 说明 |
| sql_exporter (burningalchemist / prometheus-community) | MySQL、PostgreSQL、SQL Server、Oracle、ClickHouse、Snowflake、Vertica | ✅ 完全配置驱动,任意 SQL → 任意指标 | free/sql_exporter 的活跃继任者。collector 用 YAML 定义,无需写代码。业务数据监控的首选 |
| mysqld_exporter / postgres_exporter | MySQL / PostgreSQL | ⚠️ 以数据库自身指标为主(连接数、慢查询、缓存命中),不提供通用业务 SQL 能力 | 解决的是"数据库监控",不是"业务数据监控",两者互补而非替代 |
| oracledb_exporter | Oracle | ✅ 支持 TOML + SQL 定义自定义指标 | Oracle 环境可用;比 sql_exporter 更偏向 Oracle 专有视图 |
| dameng_exporter | 达梦 DM8(信创) | ✅ 30+ 内置指标,并支持通过 SQL 定义自定义指标 | 国产生态适配较好,配套 Grafana 面板 |
| Prometheus 官方 mysqld/node 系列 | --- | ❌ 不涉及 | 与本篇主题无关,仅作对照 |

选型建议与自研边界


三、Prometheus 四种数据类型速览

Prometheus 只有四种数据类型,选错了类型,后面的 PromQL 和告警全是歪的。

|------------------|-----------------------|-------------------------|---------------------------------|----------------------|
| 维度 | Counter | Gauge | Histogram | Summary |
| 值的方向 | 只增(进程重启才归零) | 可增可减 | 观测值按桶累计 | 观测值按分位统计 |
| 语义 | 累计总量 | 瞬时快照 | 分布(延迟/尺寸) | 分布(延迟/尺寸) |
| 暴露的序列 | 单条 | 单条 | _bucket{le}、_sum、_count | _sum、_count、φ 分位 |
| 典型 PromQL | rate()、increase() | 直接读、delta()、deriv() | histogram_quantile()、rate() | 直接读分位值 |
| 跨实例聚合 | ✅ sum 有意义 | ✅ sum / avg 有意义 | ✅ 同桶可聚合 | ❌ 分位数不可聚合 |
| 从 SQL 直接生成 | ⚠️ 困难 | ✅ 天然契合 | ⚠️ 需 GROUP BY 手工造桶 | ❌ 基本不可行 |
| 业务数据监控中的使用频率 | 低~中 | 高(主力) | 低 | 极低 |
| 业务侧典型例子 | 累计注册用户数 | 待支付订单数、库存水位 | 支付耗时分布 | 单实例接口 P99 |

业务数据监控一般以 Gauge 为主,Counter 慎用,Histogram / Summary 基本留给应用侧。

|---------------|--------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 类型 | 在业务数据监控中的定位 | 关键注意点 |
| Gauge | 绝对主力。订单存量、待处理工单、金额、库存、对账差异笔数------业务数据绝大多数是"某一刻的快照",天然就是 Gauge | 用 delta() / deriv() 看变化趋势,用窗口值(近 1h 新增)表达"速率" |
| Counter | 谨慎使用 | 坑点 :从 SQL 查出来的"累计值"不等于 Counter。Counter 的语义是「由本进程累加、单调递增」,而库里的累计值可能被数据清理、归档、回滚而下降 ,rate() 会把下降误判为"重置",算出来的速率完全失真。只有在确定该值严格单调时才用 Counter,否则一律用 Gauge |
| Histogram | 少见 | Prometheus 的直方图是客户端分桶 ,而 SQL 侧拿不到分桶。若一定要做,只能在 SQL 里按耗时区间 GROUP BY 手工拼出 le 桶,成本高、收益低。延迟分布这类需求,应该在第4篇的应用侧埋点里解决 |
| Summary | 基本不用 | 分位数由客户端计算且不可跨实例聚合,与"从数据库取数"的模型天然冲突 |


四、可实施方案

1、总体架构与部署位置

复制代码
                    ┌──────────── 每 1~5 分钟 ────────────┐
                    ▼                                    │
        [ Exporter 独立进程 ] ──SQL──▶ [ 只读从库 / 只读账号 ]
                    │
          内存缓存(最近一次采集结果)
                    │
        /metrics ──抓取 15~30s──▶ Prometheus

Exporter 放在哪里,有三种选择:

|----------------------|-----------------------------|------------------------------------------------------------------------|
| 部署方式 | 说明 | 评价 |
| ❌ 内嵌进业务应用 | 在业务进程里加定时任务查库并暴露 /metrics | 不推荐。监控代码与业务共享线程池、连接池和 CPU;SQL 慢查询、内存泄漏会直接拖垮业务;监控的本意是保障稳定性,结果成了不稳定源 |
| ✅ 独立 Exporter 进程(旁挂) | 单独部署一个 exporter,用独立连接与独立账号 | 推荐。故障域隔离:Exporter 挂掉只丢指标,不影响业务 |
| ✅ 独立 Exporter + 只读从库 | 同上,且 SQL 走从库/只读实例 | 最优。把采数压力从主库彻底剥离,避免影响在线事务 |

2、四条硬性原则

3、取数时机:三种方式对比

注意:「什么时候查库」比「查什么」更重要。

|---------------------------------|----------------------------------|----------------------|--------------------------------------------|---------------------|
| 方式 | 查询时机 | 优点 | 缺点 | 适用 |
| sql_exporter + min_interval | 抓取时触发,但受最小间隔限制,间隔内返回缓存 | 零开发、配置即用 | 首次抓取仍是同步执行;对 DB 的节奏仍由抓取驱动 | 绝大多数场景的默认选择 |
| 自研 Exporter(后台采集 + 内存缓存) | 后台 goroutine / 定时器驱动,与抓取完全解耦 | 抓取链路零查库;可跨源聚合、可自定义计算 | 需要开发与维护 | 抓取必须零查库、多数据源聚合、复杂计算 |
| 定时任务 + Pushgateway | 定时任务采集后主动 push | 无需常驻进程 | 无 up 语义,任务挂掉后指标停留在旧值而不自知,易产生"陈旧数据当正常"的误判 | 离线批处理类指标,且必须配套新鲜度告警 |

关于第一种,sql_exporter 的默认行为需要特别说明:

min_interval 默认为 0s,表示每次 /metrics 被访问都会执行全部查询 。要避免"抓取即查库",必须显式设置 min_interval(如 1m),让高频抓取命中缓存。

4、落地方案(以 sql_exporter 为例)

第一步:数据库侧准备只读账号

复制代码
CREATE USER 'monitor'@'%' IDENTIFIED BY '***';
GRANT SELECT ON order_db.* TO 'monitor'@'%';
-- 限制并发连接,避免监控账号挤占业务连接
ALTER USER 'monitor'@'%' WITH MAX_USER_CONNECTIONS 5;

第二步:Exporter 主配置

1)主配置字段说明(0.24)

global 段

|------------------------------|----------|----------------------------------------------------------------------------------------------------------------|
| 字段 | 默认值 | 说明 |
| scrape_timeout | 10s | 单次抓取总超时。实际生效值 = min(scrape_timeout, 请求头 X-Prometheus-Scrape-Timeout-Seconds − scrape_timeout_offset);≤0 表示不设 |
| scrape_timeout_offset | 500ms | 从 Prometheus 的超时里扣掉的余量,保证是 exporter 先返回而不是 Prometheus 先超时。必须为正数 |
| min_interval | 0s | 最关键的一项 :collector 结果的缓存 TTL。0s 表示每次抓取都执行全部查询,线上必须改 |
| warmup_delay | 0s | 启动后首次填充缓存时,各 collector 之间错开的延迟,避免同时压库(惊群) |
| max_connections | 3 | 到单个 target 的最大连接数(查询会并发跑在多个连接上) |
| max_idle_connections | 3 | 最大空闲连接数,通常与 max_connections 相同 |
| max_connection_lifetime | 0(无限) | 连接最长复用时间 |
| scrape_error_drop_interval | 0s | 多久清一次累计的 scrape_errors_total,0 表示不清 |
| enable_query_metrics | false | 开启后额外暴露 per-query 的 query_duration_seconds / query_rows_returned,做自监控强烈建议打开 |

target / jobs 段(二选一)

|----------------------------|---------------------|------------------------------------------------------------------------------|
| 字段 | 位置 | 说明 |
| name | target | 可选。设置后额外暴露带 target 标签的 up / scrape_duration_seconds,且始终返回 HTTP 200 |
| data_source_name | target | URL 格式 DSN;特殊字符需 URL 编码 |
| collectors | target / jobs[] | 在该目标上执行的 collector 名,支持 glob (如 biz_*) |
| enable_ping | target / jobs[] | 采集前是否 ping,默认 true |
| job_name | jobs[] | 任务名,会作为 job 标签 |
| static_configs[].targets | jobs[] | 键值对:实例名: DSN,键会成为 instance 标签 |
| static_configs[].labels | jobs[] | 该组所有目标的附加标签(env、svc 等) |
| collector_files | 顶层 | collector 文件 glob,一个文件一个 collector |

2)配置示例
复制代码
# sql_exporter.yml
global:
  scrape_timeout: 10s              # 单次抓取上限;<=0 表示不设
  scrape_timeout_offset: 500ms     # 从 Prometheus 超时里预留的余量,必须为正
  min_interval: 1m                 # 【必改】collector 结果缓存 TTL。0s = 每次抓取都查库
  warmup_delay: 200ms              # 启动预热时各 collector 错开的间隔,防惊群
  max_connections: 3               # 到单个 target 的最大连接数
  max_idle_connections: 3          # 通常与 max_connections 一致
  max_connection_lifetime: 30m     # 0 表示无限复用
  scrape_error_drop_interval: 1h   # 0 表示 scrape_errors_total 只增不清
  enable_query_metrics: true       # 暴露 per-query 耗时/行数,用于自监控

# ── 单目标模式:与 jobs 二选一 ───────────────────────────────
target:
  name: order_db                                    # 可选;设置后会自带 up / scrape_duration_seconds
  data_source_name: 'mysql://monitor:p%40ssw0rd@order-db-read:3306/order_db'
  collectors: [biz_order]                           # 支持 glob,如 biz_*
  enable_ping: true                                 # pgbouncer / 数仓 建议 false

# ── 多目标模式:一个 exporter 监控多个库,与 target 二选一 ────
# jobs:
#   - job_name: biz_order
#     collectors: [biz_order]
#     enable_ping: true
#     static_configs:
#       - targets:
#           # 左侧是 instance 名(会作为 instance 标签),右侧是 DSN
#           'order-db-read:3306': 'mysql://monitor:pwd@order-db-read:3306/order_db'
#         labels:
#           env: prod
#           svc: order
#   - job_name: biz_payment
#     collectors: [biz_payment]
#     static_configs:
#       - targets:
#           'pay-db-read:5432': 'postgresql://monitor:pwd@pay-db-read:5432/pay_db?sslmode=disable'
#         labels:
#           env: prod
#           svc: payment

# collector 定义文件:一个文件一个 collector
collector_files:
  - "/etc/sql_exporter/collectors/*.collector.yml"

关于 0.24 的两个细节:

第三步:指标定义(collector)

复制代码
# biz_order.collector.yml
collector_name: biz_order
metrics:
  # 用于判断数据是否能正常查询
  # 网上有文章介绍有 last_success_timestamp_seconds 指标,但在0.24版本里并没有,需自建
  - metric_name: last_success_timestamp_seconds
    type: gauge
    help: '该查询最近一次真实执行成功的时刻(Unix 秒)'
    values: [ts]
    query: |
      SELECT UNIX_TIMESTAMP() AS ts
  - metric_name: biz_order_total
    type: gauge                 # 业务数据统一用 gauge
    help: '各状态订单存量(近 7 天)'
    key_labels: [status]        # 结果集的 status 列 → 标签
    values: [cnt]               # 结果集的 cnt 列 → 数值
    query: |
      SELECT status, COUNT(*) AS cnt
      FROM t_order
      WHERE create_time >= NOW() - INTERVAL 7 DAY
      GROUP BY status;

一行结果 status=pending, cnt=1820 会被翻译成:

复制代码
biz_order_total{status="pending",job="biz_order",instance="order-db:3306",env="prod",svc="order"} 1820

第四步:启动 sql_exporter 服务

1)Docker 启动服务
复制代码
docker run -d --name sql_exporter \
  --restart=no \
  --network my-bridge \
  -p 9399:9399 \
  -v /data/volumes/sql_exporter:/etc/sql_exporter:ro \
  burningalchemist/sql_exporter:0.24 \
    --config.file=/etc/sql_exporter/sql_exporter.yml \
    --web.enable-reload

坑点:collector_files 是相对于配置文件所在目录 的 glob。容器内必须把 sql_exporter.yml 与所有 *.collector.yml 放在同一目录整体挂载,否则 collector 会静默加载不到,不报错,只是"没有指标"。

2)命令行参数速查(0.24)

|----------------------------------|--------------------|-----------------------------------------------|
| 参数 | 默认值 | 说明 |
| --config.file | sql_exporter.yml | 主配置文件路径。也可用环境变量 SQLEXPORTER_CONFIG 覆盖 |
| --config.check | false | 只校验配置并退出。变更前必跑 |
| --config.data-source-name | 空 | 用命令行覆盖配置里的 DSN,多环境复用同一份配置文件 |
| --config.enable-ping | true | 采集前是否 ping 数据库。pgbouncer / 按需付费数仓要设 false |
| --config.target-label | target | 多目标模式下标识目标的标签名 |
| --config.ignore-missing-values | false | 实验 忽略结果集中缺失列的行 |
| --web.listen-address | :9399 | 监听地址 |
| --web.metrics-path | /metrics | 业务指标暴露路径 |
| --web.config.file | 空 | TLS / BasicAuth / 限流配置文件(exporter-toolkit 格式) |
| --web.enable-reload | false | 开启 /reload 端点。默认关闭 ,不开启时用 SIGHUP 重载 |
| --log.level | info | 日志级别 |
| --log.format | logfmt | 日志格式 |
| --log.file | 空(stderr) | 日志文件路径 |
| --version | false | 打印版本并退出 |

第五步:接入 Prometheus

复制代码
- job_name: 'sql_exporter'
  scrape_interval: 30s
  honor_labels: true        # 关键:保留 exporter 打的 instance/job,不被抓取侧覆盖
  static_configs:
    - targets: ['sql_exporter:9399']

第六步:验证

复制代码
$ curl -s localhost:9399/metrics | grep biz_order_total
biz_order_total{env="prod",instance="order-db:3306",job="biz_order",status="pending",svc="order"} 1820
biz_order_total{env="prod",instance="order-db:3306",job="biz_order",status="paid",svc="order"} 9642

注意:当数据库不可达时,sql_exporter 的 /metrics 会返回 HTTP 500,Prometheus 侧会记为 up=0。

5、数据库侧风险控制

监控引入的每一次查询,都是对生产数据库的一次访问。

|--------------|---------------------------------------------|-------------------------------------------------------------------------------------------|
| 风险 | 后果 | 控制措施 |
| 连接数占用 | 监控账号与业务争抢连接池,连接打满后业务不可用 | 单实例连接数固定(max_connections: 3);用独立只读账号并限制 MAX_USER_CONNECTIONS;复用长连接而非每次新建 |
| 大表全量扫描 | 千万级大表上 COUNT(*) 直接把 DB CPU 打到 100%,从库延迟飙升 | 查询必须先 EXPLAIN 验证走索引;禁止 SELECT *;为筛选/分组字段建索引;尽量用时间窗口限定范围 |
| 查询频率过高 | 15 秒一次抓取 = 15 秒一次全量 SQL,DB 承受持续脉冲压力 | 设置 min_interval: 1m~5m;业务数据变化以分钟计,秒级刷新没有意义 |
| 结果集基数爆炸 | 时间序列数量失控,Prometheus 内存/磁盘耗尽 | 标签基数 ≤ 10³;绝不把 user_id / order_id 放进标签 ;SQL 内先 GROUP BY 收敛维度再返回 |
| 查询无超时 | 慢查询堆积,Exporter 卡死、抓取超时、级联告警 | SQL 侧设 statement_timeout / max_execution_time;配置 scrape_timeout_offset 留余量 |
| 数据陈旧却无人知 | 面板显示的是 1 小时前的数据,被误判为"业务正常" | 必须暴露 last_success_timestamp_seconds,并对"数据过期"单独告警。但默认没有该指标,需参考前文自建。 |
| 主库被反复打扰 | 影响在线事务,引发用户可感知的抖动 | 走只读从库 / 只读实例;确需读主库时,把查询降到最低频率并选在低峰执行 |

一句话总结风险控制原则:把监控当成一个不受信任的、需要限流的外部客户端来对待。


五、一个业务数据监控会产生哪些指标

很多人以为"业务数据监控"就是那几条业务指标,实际上一个可用的落地需要三层指标同时到位。少了后两层,业务数据的可信度无从判断。

|--------------|-------------------------------------------|---------|------------------------------------------------------|
| 层 | 指标 | 类型 | 作用 |
| ① 业务数据 | biz_order_pending_count | Gauge | 待处理订单数------核心业务水位 |
| | biz_order_total{status} | Gauge | 各状态订单存量 |
| | biz_order_amount_yuan{channel} | Gauge | 各渠道订单金额 |
| | biz_order_timeout_count | Gauge | 超时未支付订单数 |
| | biz_order_created_1h | Gauge | 近 1 小时新增(窗口值,表达"速率") |
| ② 采集健康度 | up{job="sql_exporter"} | Gauge | 抓取链路是否通(Prometheus 自动生成) |
| | ..._query_duration_seconds{query} | Gauge | 单条 SQL 执行耗时(enable_query_metrics 开启后由 exporter 暴露) |
| | ..._query_rows_returned{query} | Gauge | 单条 SQL 返回行数,异常跳变往往先于业务异常 |
| | last_success_timestamp_seconds{query} | Gauge | 自建指标,最后一次成功采集的时间戳。数据新鲜度,最该配的一条告警。 |
| ③ 数据库与连接 | ..._db_connections_open / in_use / idle | Gauge | Exporter 到 DB 的连接池水位 |
| | biz_query_errors_total{reason} | Counter | SQL 报错累计(权限、超时、语法、连接拒绝) |
| | 数据库自身指标(连接数、慢查询、从库延迟) | --- | 由 mysqld_exporter / 内置视图提供,与本篇互补 |

注意:

第③ 层数据库与连接,默认无该层指标, 需通过编写自定义的 collector 配置文件来实现:


六、一个 Exporter 配多少条 SQL

这是直接影响稳定性上限的问题。

核心约束:所有 SQL 都要在一次采集周期内跑完。

|-----------------------------|-------------------------|------------------------|---------------------------------------------------|
| 维度 | 建议值 | 理由 | 超限怎么办 |
| 单 Exporter 的 SQL 条数 | 10~20 条为宜,上限 30 条 | 条数越多,单次采集耗时与 DB 压力线性增长 | 按业务域拆分多个 Exporter 实例(订单 / 支付 / 库存各一个),各自独立端口与 job |
| 单条 SQL 执行时间 | P95 < 1s | 采集耗时需远小于采集间隔 | 加索引、缩小时间窗口、改走从库;仍慢则改为预聚合中间表 |
| 单次采集总耗时 | < min_interval 的 1/3 | 避免"上一次还没跑完,下一次又来了" | 拆分实例;不同 Exporter 错峰设置 min_interval |
| 单条 SQL 返回行数 | ≤ 1000 行 | 行数 × 标签组合 = 时间序列数 | SQL 内先 GROUP BY 收敛维度,只返回真正需要的分类 |
| 单指标的标签基数 | ≤ 10³,多标签乘积 ≤ 10⁴ | 时间序列爆炸的临界点 | 剔除 id 类标签;或改为"多个指标"而不是"一个指标多个标签" |
| 单实例连接数 | 3~5 | 控制对 DB 的连接占用 | 提高前先核算数据库剩余连接额度 |
| 采集频率 min_interval | 1~5 分钟 | 业务数据变化以分钟计 | 与 SQL 耗时、DB 负载联动调整,不做低于 30s 的采集 |

拆分阈值(任一条命中就该拆)

拆分的成本很低------多跑一个容器、多加一个 job;而不拆的代价是:一条慢查询拖慢整个 Exporter 的采集,所有业务指标一起失真。


七、与应用内埋点的边界

|--------|------------------|---------------------|
| 维度 | 应用内埋点(第4篇) | 数据库侧采集(本篇) |
| 数据来源 | 代码里主动打点 | 从库里查出来的既成事实 |
| 典型指标 | 接口耗时、业务动作次数、异常计数 | 订单存量、待处理量、对账差异、库存水位 |
| 是否改代码 | 需要 | 不需要(只加配置) |
| 精度 | 高(事件级) | 低(快照级,受采集间隔限制) |
| 对业务的影响 | 同在进程内,需谨慎 | 完全隔离 |

互补关系:应用埋点回答"这个动作发生了多少次、花了多久",数据库采集回答"现在还剩多少、积压了多少"。存量类、外部系统写库类、历史遗留系统类指标,都只能靠本篇的方式拿到。


八、小结

  • 优先直接落地 sql_exporter 这一类配置驱动的方案:新加一个业务指标 = 加一段 YAML + 一条 SQL,不用发版、不用重启业务。

  • 只有下面三种情况才值得自研:

    1. 要求抓取链路绝对不触发数据库查询(安全或性能红线);
    2. 需要在多个数据源之间做跨库聚合与计算,而不是单条 SQL 出结果;
    3. 取数来源不只是 SQL(还要读 HTTP 接口、文件、消息队列)后统一成一个指标。
    • 业务数据指标不集成进应用。监控采集是"额外负载",绝不能和业务抢资源、共用失败边界。要独立进程、独立账号、独立连接池。
    • 不在 Prometheus 抓取时同步查库 。抓取间隔通常是 15~30 秒,如果每次抓取都跑一遍 SQL,等于给数据库挂了一个 15 秒一次的压力源。正确做法是后台定时采集 + 内存缓存 ,/metrics 只读缓存、秒回。
    • 查询走只读从库、只读账号、带超时 。最小权限 SELECT,禁止 DDL/DML;SQL 必须设执行超时。
    • 标签基数必须受控 。把 user_id、order_id 放进标签,时间序列数量会随数据量线性膨胀,几小时内就能吃光 Prometheus 的内存。
    • 启动预热 :进程启动后缓存为空,会先把所有 collector 跑一遍(warmup)。预热期间 /metrics 请求会被阻塞直到预热完成,warmup_delay 就是用来错开这一轮采集、避免瞬间把所有查询压到数据库上的。
    • min_interval 同样作用于启动后的第一次采集 ,因此它不只是"缓存 TTL",同时也是控制单次压库节奏的手段。
    • last_success_timestamp_seconds :用 time() - biz_last_success_timestamp_seconds > 600 直接告警"数据已过期",是防止"看着旧数据做决策"的唯一手段。但需注意,数据库和 Prometheus 之间要有 NTP 同步,否则新鲜度会带着固定偏移。
    • query_rows_returned:返回行数突然从 20 涨到 2000,通常意味着数据异常或维度失控,比业务阈值更早报警。
    • 连接池水位指标 (db_connections_open / in_use / idle):对于 MySQL,可以查询 information_schema.PROCESSLIST 或 performance_schema 来获取当前连接数、活跃连接数等;对于 PostgreSQL,可以查询 pg_stat_activity 视图,如 SELECT COUNT(*) as connections FROM pg_stat_activity 。
    • 业务错误计数器 ( biz_query_errors_total{reason}):需要应用程序或数据库中间件在发生特定错误时进行记录。sql_exporter 无法自动感知业务层面的错误。如在数据库中创建一个用于记录错误日志的表。
    • SQL 条数 > 30 条;
    • 单次采集总耗时 > 5s;
    • 单个 Exporter 产生的总时间序列数 > 5 万;
    • 涉及两个以上互不相关的业务域。
    • 需要中间层,但不必造轮子。 业务数据 → Prometheus 必须有一个 Exporter 做翻译;优先选 sql_exporter 这类配置驱动方案,配置即指标,改指标不用发版。
    • 独立部署是底线。 业务数据指标不要集成进业务应用,共享资源、共享故障域,监控反而会拖垮被监控的对象。独立进程 + 独立只读账号 + 天然隔离。
    • 抓取时不查库。 Prometheus 的抓取节奏(15~30s)不适合驱动数据库查询。要么给 sql_exporter 配好 min_interval 走缓存,要么自研带后台采集与内存缓存的 Exporter。
    • 业务数据几乎都用 Gauge。 库里查出的"累计值"不满足 Counter 的单调语义,rate() 会算错;Histogram / Summary 是客户端能力,留给应用侧埋点。
    • 风险控制先于指标设计。 连接数、查询性能、结果集基数、查询超时、数据新鲜度,这五件事在写第一条 SQL 之前就应定好规矩。监控的价值是"早知道",但前提是它自己没有变成新的故障源。
相关推荐
Cheney Pan7 小时前
第4篇 Spring Boot 应用监控:Micrometer 与 JVM 指标
jvm·spring boot·后端·prometheus
飞鸟真人7 小时前
应用性能监测(APM)之 (四)Prometheus与Metrics集群存储
prometheus
Cheney Pan9 小时前
第09篇 告警体系设计:Alertmanager 路由与告警治理
prometheus
蓝胖的四次元口袋1 天前
Prometheus+Grafana知识梳理(1)
grafana·prometheus
晨陌y1 天前
CentOS 7 部署 mysqld_exporter:MySQL 指标采集、Prometheus 告警与远程监控
mysql·centos·prometheus
倔强的小石头_2 天前
Ubuntu部署Prometheus与Alertmanager:systemd配置、告警对接及cpolar远程访问
数据库·ubuntu·prometheus
打工仔折腾 AI2 天前
Prometheus接入Pushgateway实战:二进制与Docker部署、指标推送与远程写入
后端·python·docker·容器·性能优化·prometheus·ai agent 实战
Elastic 中国社区官方博客3 天前
两个依赖和一个配置块:通过 Prometheus 远程写入将 Spring Boot 指标发送到 Elasticsearch
大数据·数据库·spring boot·elasticsearch·搜索引擎·全文检索·prometheus
User_芊芊君子4 天前
Prometheus接入Pushgateway实战:二进制与Docker部署、指标推送及远程上报
docker·容器·prometheus