用 Categraf 接入第一个 Redis、MySQL 或 PostgreSQL 实例时,配置通常很简单:写一个 [[instances]],确认 --test 有指标,再看 Dashboard。真正进入生产环境后,问题会很快变复杂:一台 Categraf 采多个数据库实例,多套业务共用同一个插件,同一个实例又有主从、集群、机房、环境等维度。
这时最容易出问题的不是采集,而是标签。标签设计不清楚,会导致 Dashboard 变量分不出实例、告警事件不知道该通知谁、同一个目标被多条时序混在一起,甚至因为把动态值打进标签而制造高基数。
本文不聚焦某一个插件,而是把 Categraf 多实例场景下最常用的标签规则讲清楚:什么时候增加多个 [[instances]],什么时候用 labels,agent_hostname、ident、instance、server 分别承担什么职责,PostgreSQL 的 outputaddress 又该怎么用。
核心要点
- 多实例采集优先使用多个
[[instances]]表达不同目标;同一组目标共享相同超时、认证、方法等配置时,可以放在同一个实例块。 - 实例级
labels优先级最高:同名时覆盖插件原始标签,值为"-"时删除已有标签。[global.labels]和agent_hostname只在标签缺失时补充。 agent_hostname标识运行 Categraf 的采集器主机,不一定等于被监控对象。数据库、中间件、探测目标通常还需要额外的instance、server、target或业务标签。- 经过夜莺写入时,原指标没有非空
ident的情况下,夜莺通常会把agent_hostname作为监控对象标识;如果指标已有非空ident,显式ident优先。直写其他 TSDB 时通常保留agent_hostname。 instance应该使用稳定、全局唯一、可读的值,例如prod-redis-01:6379、order-mysql-primary,不要使用 PID、请求 ID、临时容器 ID、完整 URL query、SQL 文本。- PostgreSQL 插件中的
outputaddress会影响指标里的server标签,适合把复杂连接串归一成稳定名称。 - Dashboard 变量和告警规则要基于真实后端标签设计,不能只看配置文件里“以为会有”的标签。
1. 什么时候算“多实例”问题
下面几种都属于多实例场景:
| 场景 | 示例 | 常见风险 |
|---|---|---|
| 一个插件采多个地址 | 两个 Redis、三个 MySQL | 指标混在一个变量里 |
| 一个地址有多个逻辑身份 | 同一个 PostgreSQL 采多个业务库 | 告警无法定位业务 |
| 一个探测插件采多组目标 | HTTP GET、POST、不同超时 | 配置共享导致误判 |
| 一个 Categraf 采本机和远端 | 本机 Linux + 远端数据库 | agent_hostname 被误认为目标 |
| 集群组件有多种角色 | MongoDB mongos、config、shard | Dashboard 缺少拓扑筛选 |
排障时如果出现下面现象,通常要回到标签设计:
- Dashboard 变量里有多个相同名字的实例;
- 告警标题只显示采集器主机,不显示实际数据库或接口;
count by (instance)结果少于实际目标数量;- 同一个实例更换 IP 后历史趋势断裂;
- 后端时序数量异常增长,主要由某个标签扩散导致;
- 直写 VictoriaMetrics 能查到
agent_hostname,夜莺 Dashboard 却在查ident。
2. Categraf 标签处理顺序
普通 input 产生一条指标后,会经过 Categraf 的统一标签处理。可以按下面顺序理解:
插件原始标签
|
v
实例级 labels:同名时覆盖,值为 "-" 时删除
|
v
global.labels:只补充缺失标签
|
v
agent_hostname:只在缺失且 omit_hostname=false 时补充
|
v
relabel_configs:最后再处理
例如主配置有:
[global.labels]
env = "prod"
region = "shanghai"
team = "platform"
Redis 实例配置:
[[instances]]
address = "10.23.25.2:6379"
labels = { instance = "prod-redis-01:6379", team = "checkout" }
最终这一组 Redis 指标会带上:
instance=prod-redis-01:6379
team=checkout
env=prod
region=shanghai
agent_hostname=<CATEGRAF_HOST>
team=checkout 会覆盖全局的 team=platform。如果确实要删除某个已有标签,可以写:
labels = { region = "-" }
这个能力适合少数特殊目标,不建议当成常规标签治理方式。大量删除标签会让同一个插件不同实例的标签结构不一致,Dashboard 和告警规则很难复用。
3. agent_hostname、ident、instance、server 怎么分工
这几个标签经常被混用。建议按职责区分:
| 标签 | 推荐职责 | 注意事项 |
|---|---|---|
agent_hostname |
Categraf 采集器自身 | 远端数据库场景下不是数据库实例 |
ident |
夜莺侧监控对象标识 | 是否存在取决于写入链路和显式标签 |
instance |
用户定义的被监控实例标识 | 适合作为 Dashboard 变量和告警主维度 |
server |
某些插件自带的目标服务标签 | PostgreSQL、Nginx 等插件会使用 |
target |
探测类插件的探测目标 | HTTP/TCP/DNS/Ping 常见 |
cluster |
集群名称 | 适合 Kafka、MongoDB、Kubernetes 等 |
role / component |
实例角色或组件类型 | 适合 primary、replica、mongos、broker |
env / region / az |
稳定环境维度 | 适合放在全局或实例标签 |
一个常见误区是直接用 agent_hostname 当所有目标的实例标识。比如一台 Categraf 采集十个 Redis,如果只靠 agent_hostname,这些 Redis 在 Dashboard 里都会归到同一个采集器下面。你仍然能看到指标,但告警和变量会很难定位到真实目标。
另一个误区是强行给所有指标打 ident。如果你的链路以夜莺监控对象为中心,且希望网络设备或远端服务进入夜莺对象列表,可以明确设计 ident;但如果只是为了 Dashboard 区分实例,通常用 instance、server、target 更清晰。
4. Redis 多实例推荐写法
Redis README 中已经给出了最小模式:每个 Redis 一个 [[instances]],并用 labels.instance 标识实例。
[[instances]]
address = "10.23.25.2:6379"
username = ""
password = ""
labels = {
instance = "prod-redis-01:6379",
cluster = "checkout-redis",
role = "primary",
service = "checkout"
}
[[instances]]
address = "10.23.25.3:6379"
username = ""
password = ""
labels = {
instance = "prod-redis-02:6379",
cluster = "checkout-redis",
role = "replica",
service = "checkout"
}
这样后端可以直接验证:
count by (instance, cluster, role, service) (redis_up)
告警也可以围绕 instance 和 cluster 写:
redis_up{cluster="checkout-redis"} == 0
不推荐把 address 里的密码、URL 参数或临时域名作为标签。实例名可以包含地址,但应保证长期稳定。如果业务侧会频繁替换 IP,建议用业务实例名:
labels = { instance = "checkout-redis-primary", cluster = "checkout-redis" }
5. PostgreSQL 的 outputaddress 怎么用
PostgreSQL 插件会在指标中使用 server 标签标识服务端。连接串通常很长,还可能包含用户名、参数和 PgBouncer 地址:
[[instances]]
address = "host=10.23.25.10 port=5432 user=categraf password=${PG_PASSWORD} sslmode=disable dbname=postgres"
如果直接从连接信息生成 server,Dashboard 变量可读性会很差,也容易暴露不必要信息。此时应配置 outputaddress:
[[instances]]
address = "host=10.23.25.10 port=5432 user=categraf password=${PG_PASSWORD} sslmode=disable dbname=postgres"
outputaddress = "order-postgresql-primary"
labels = {
instance = "order-postgresql-primary",
cluster = "order-postgresql",
service = "order",
env = "prod"
}
验证:
count by (server, instance, cluster, service) (postgresql_up)
这里 server 和 instance 可以相同,也可以分工:
server保持插件 Dashboard 兼容,使用outputaddress;instance用作跨插件统一实例名;cluster表示一组主从或一套数据库集群;service表示业务归属。
如果启用 pg_stat_statements,要特别注意 query 标签。它的基数通常比实例标签高很多,应该限制采集数量,不要把完整 SQL、用户输入或请求参数额外塞进自定义标签。
6. HTTP、TCP、DNS 探测类插件怎么拆实例
探测类插件经常同时采很多目标。一般原则是:
- 同一组目标使用相同方法、超时、认证和期望值时,可以放在一个
[[instances]]; - 只要方法、超时、Header、Body、证书、期望状态码不同,就拆成多个
[[instances]]; - 目标级别的业务标签优先用
mappings,组级别标签再用实例labels。
HTTP 示例:
[mappings]
"https://api.example.com/health" = { service = "api", endpoint = "health" }
"https://pay.example.com/health" = { service = "pay", endpoint = "health" }
[[instances]]
targets = [
"https://api.example.com/health",
"https://pay.example.com/health",
]
method = "GET"
response_timeout = "3s"
labels = { env = "prod", probe = "public" }
[[instances]]
targets = [
"https://api.example.com/internal/check",
]
method = "POST"
response_timeout = "5s"
labels = { env = "prod", probe = "internal", service = "api" }
后端验证:
count by (target, service, endpoint, probe, env) (http_response_result_code)
不要把完整 URL query 作为 target 的长期标签,例如:
https://api.example.com/search?keyword=<USER_INPUT>&trace_id=<TRACE_ID>
如果必须探测带参数接口,应固定参数值,并用稳定的 endpoint 标签描述业务含义。
7. 哪些标签适合全局,哪些适合实例
可以用这个表快速判断:
| 标签 | 放置位置 | 原因 |
|---|---|---|
env |
全局或实例 | 整台采集器环境一致时放全局 |
region |
全局或实例 | 跨地域采集时放实例 |
az |
全局或实例 | 采集器与目标同可用区时可全局 |
team |
实例 | 同一 Categraf 可能采多个团队目标 |
service |
实例或 mappings | 通常随目标变化 |
cluster |
实例 | 数据库、中间件、Kubernetes 常用 |
role |
实例或插件原始标签 | primary、replica、broker 等 |
instance |
实例 | 应稳定标识被监控对象 |
version |
谨慎 | 版本升级会产生新时序,可接受但要评估 |
pod / container_id |
谨慎 | Kubernetes 场景可能高基数 |
request_id / trace_id |
禁止 | 每次请求都变化 |
sql / query |
非必要不新增 | 极易高基数和泄露信息 |
全局标签适合描述“这台 Categraf 所在环境”。实例标签适合描述“这个被采集目标是谁”。一台 Categraf 跨环境采集时,不要把 env=prod 写到全局,否则测试目标也会被打成生产。
8. 高基数标签的典型错误
高基数不是“标签多”这么简单,而是某个标签的取值数量很大或变化很快。常见错误:
| 错误标签 | 风险 |
|---|---|
pid |
进程重启后不断产生新时序 |
container_id 完整长 ID |
容器滚动发布后快速扩散 |
pod_uid |
Pod 重建后取值变化 |
request_id / trace_id |
每次请求几乎唯一 |
| 完整 URL query | 用户输入和分页参数导致爆炸 |
| 原始 SQL 文本 | 语句数量和敏感信息都不可控 |
| 错误信息全文 | 错误内容变化会制造大量时序 |
评估一个标签前,先问三个问题:
- 这个值是否会长期稳定?
- 这个值是否真的需要用于 Dashboard 分组或告警路由?
- 这个值的取值数量是否可预估、可控制?
如果三个问题有任意一个答案是否定,就不要把它放进指标标签。可以把它留在日志、Trace 或事件系统中,而不是时序指标。
9. 用 PromQL 验证标签是否符合预期
配置完成后,不要只看 --test 输出。最终以后端真实标签为准。
基础验证:
redis_up
看实例维度:
count by (instance, agent_hostname) (redis_up)
看业务维度:
count by (cluster, service, env, region) (redis_up)
看是否存在重复实例:
count by (instance) (redis_up)
如果同一个 instance 下出现多个不该存在的采集器,可以进一步查:
count by (instance, agent_hostname) (redis_up)
查某个标签取值数量:
count(count by (instance) (redis_up))
不同后端对元数据 API 支持不完全一致,但 PromQL 聚合足够发现大部分标签问题。Dashboard 变量设计也应该先用这些表达式验证,再写进 JSON。
10. Dashboard 和告警怎么依赖标签
一个可复用 Dashboard 至少要明确三件事:
- 用哪个指标作为变量基准,例如
redis_up、postgresql_up、http_response_result_code; - 用哪个标签作为实例变量,例如
instance、server、target; - 是否需要上游变量过滤,例如
cluster、service、env。
Redis 可以这样设计:
cluster -> instance
PostgreSQL 可以这样设计:
cluster -> server -> db
HTTP 探测可以这样设计:
service -> target
告警规则中也要带上稳定标签:
redis_up{env="prod"} == 0
告警事件模板重点展示:
env={{$labels.env}}
cluster={{$labels.cluster}}
instance={{$labels.instance}}
agent={{$labels.agent_hostname}}
agent_hostname 保留在事件里很有价值,它能告诉你是哪台 Categraf 在采集。但告警的主对象通常应是被监控目标,而不是采集器。
11. 常见问题
一个 [[instances]] 里能放多个目标吗?
取决于插件。Redis、PostgreSQL 这类通常一个实例块对应一个连接目标;HTTP、TCP、Ping 等探测插件常用一个实例块配置多个 targets。判断标准是这些目标是否共享同一组采集参数。
instance 一定要写 IP:Port 吗?
不一定。IP:Port 直观,但 IP 会变化的环境更适合用稳定业务名,例如 order-postgresql-primary。可以另外保留 address、target 或插件自带标签用于定位。
可以把 ident 设置成数据库实例名吗?
可以,但要先明确目的。如果希望夜莺把远端数据库作为监控对象管理,可以设计 ident。如果只是 Dashboard 区分实例,使用 instance 或插件自带 server 更简单。
为什么配置了全局 team,某个实例还是另一个值?
实例级 labels 优先级高于 [global.labels],同名会覆盖。全局标签只补充缺失标签。
为什么 Dashboard 里变量为空?
先查变量基准指标是否存在,再用 count by (<label>) (<metric>) 看真实标签。很多问题不是没数据,而是 Dashboard 在查 server,实际数据只有 instance。
12. 生产建议
- 给每类插件定义固定标签规范,不要每个业务各写一套;
- 统一
instance的命名规则,保证稳定、可读、全局唯一; env、region、az等低变化维度可以放全局,跨环境采集时放实例;- 数据库和中间件建议补充
cluster、service、role; - 探测类目标建议补充
service、endpoint、probe; - 保留
agent_hostname,便于定位采集器问题; - 不把密码、Token、完整 DSN、完整 URL query、SQL 文本写入标签;
- 新增标签前评估取值数量,特别是容器、Pod、SQL、请求相关字段;
- Dashboard 变量必须基于真实后端标签验证;
- 告警模板同时展示被监控实例和采集器主机;
- 标签规范进入配置评审,避免线上临时添加高基数字段。
最小验收标准:
--test 输出目标指标
+ 后端裸指标有数据
+ count by (instance) 能区分目标
+ count by (agent_hostname) 能定位采集器
+ Dashboard 变量能列出真实实例
+ 告警事件能看懂业务归属
+ 没有明显高基数动态标签
13. 小结
多实例监控的核心不是把更多配置堆进 redis.toml 或 postgresql.toml,而是给每条时序建立稳定身份。
建议记住三条规则:
agent_hostname 标识采集器
instance/server/target 标识被监控对象
env/region/service/cluster 标识归属和筛选维度
只要这三类标签职责清楚,Dashboard、告警、排障和容量治理都会简单很多。反过来,如果标签一开始混乱,采集成功也只是把问题推迟到展示和告警阶段。
下一篇继续讲部署层问题:Categraf 使用 systemd 和容器部署的常见坑。
内容更新时间:2026-07-21
证据边界:标签优先级、agent_hostname 补充逻辑、实例级 labels 删除语义来自当前 Categraf 仓库源码与默认配置;夜莺接入后的 ident 行为、Dashboard 变量和具体 Prometheus 兼容后端的标签保留策略,应以实际部署链路为准。