Categraf 多实例配置与标签设计:如何避免实例混淆和高基数

本文介绍 Categraf 多实例采集时如何设计稳定标签,覆盖多个 [[instances]]、实例级 labels、global.labels、agent_hostname、ident、instance、server、outputaddress、Dashboard 变量和高基数控制。

作者 快猫星云

用 Categraf 接入第一个 Redis、MySQL 或 PostgreSQL 实例时,配置通常很简单:写一个 [[instances]],确认 --test 有指标,再看 Dashboard。真正进入生产环境后,问题会很快变复杂:一台 Categraf 采多个数据库实例,多套业务共用同一个插件,同一个实例又有主从、集群、机房、环境等维度。

这时最容易出问题的不是采集,而是标签。标签设计不清楚,会导致 Dashboard 变量分不出实例、告警事件不知道该通知谁、同一个目标被多条时序混在一起,甚至因为把动态值打进标签而制造高基数。

本文不聚焦某一个插件,而是把 Categraf 多实例场景下最常用的标签规则讲清楚:什么时候增加多个 [[instances]],什么时候用 labelsagent_hostnameidentinstanceserver 分别承担什么职责,PostgreSQL 的 outputaddress 又该怎么用。

核心要点

  • 多实例采集优先使用多个 [[instances]] 表达不同目标;同一组目标共享相同超时、认证、方法等配置时,可以放在同一个实例块。
  • 实例级 labels 优先级最高:同名时覆盖插件原始标签,值为 "-" 时删除已有标签。[global.labels]agent_hostname 只在标签缺失时补充。
  • agent_hostname 标识运行 Categraf 的采集器主机,不一定等于被监控对象。数据库、中间件、探测目标通常还需要额外的 instanceservertarget 或业务标签。
  • 经过夜莺写入时,原指标没有非空 ident 的情况下,夜莺通常会把 agent_hostname 作为监控对象标识;如果指标已有非空 ident,显式 ident 优先。直写其他 TSDB 时通常保留 agent_hostname
  • instance 应该使用稳定、全局唯一、可读的值,例如 prod-redis-01:6379order-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_hostnameidentinstanceserver 怎么分工

这几个标签经常被混用。建议按职责区分:

标签 推荐职责 注意事项
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 区分实例,通常用 instanceservertarget 更清晰。

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)

告警也可以围绕 instancecluster 写:

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)

这里 serverinstance 可以相同,也可以分工:

  • 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 文本 语句数量和敏感信息都不可控
错误信息全文 错误内容变化会制造大量时序

评估一个标签前,先问三个问题:

  1. 这个值是否会长期稳定?
  2. 这个值是否真的需要用于 Dashboard 分组或告警路由?
  3. 这个值的取值数量是否可预估、可控制?

如果三个问题有任意一个答案是否定,就不要把它放进指标标签。可以把它留在日志、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_uppostgresql_uphttp_response_result_code
  • 用哪个标签作为实例变量,例如 instanceservertarget
  • 是否需要上游变量过滤,例如 clusterserviceenv

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。可以另外保留 addresstarget 或插件自带标签用于定位。

可以把 ident 设置成数据库实例名吗?

可以,但要先明确目的。如果希望夜莺把远端数据库作为监控对象管理,可以设计 ident。如果只是 Dashboard 区分实例,使用 instance 或插件自带 server 更简单。

为什么配置了全局 team,某个实例还是另一个值?

实例级 labels 优先级高于 [global.labels],同名会覆盖。全局标签只补充缺失标签。

为什么 Dashboard 里变量为空?

先查变量基准指标是否存在,再用 count by (<label>) (<metric>) 看真实标签。很多问题不是没数据,而是 Dashboard 在查 server,实际数据只有 instance

12. 生产建议

  • 给每类插件定义固定标签规范,不要每个业务各写一套;
  • 统一 instance 的命名规则,保证稳定、可读、全局唯一;
  • envregionaz 等低变化维度可以放全局,跨环境采集时放实例;
  • 数据库和中间件建议补充 clusterservicerole
  • 探测类目标建议补充 serviceendpointprobe
  • 保留 agent_hostname,便于定位采集器问题;
  • 不把密码、Token、完整 DSN、完整 URL query、SQL 文本写入标签;
  • 新增标签前评估取值数量,特别是容器、Pod、SQL、请求相关字段;
  • Dashboard 变量必须基于真实后端标签验证;
  • 告警模板同时展示被监控实例和采集器主机;
  • 标签规范进入配置评审,避免线上临时添加高基数字段。

最小验收标准:

--test 输出目标指标
  + 后端裸指标有数据
  + count by (instance) 能区分目标
  + count by (agent_hostname) 能定位采集器
  + Dashboard 变量能列出真实实例
  + 告警事件能看懂业务归属
  + 没有明显高基数动态标签

13. 小结

多实例监控的核心不是把更多配置堆进 redis.tomlpostgresql.toml,而是给每条时序建立稳定身份。

建议记住三条规则:

agent_hostname 标识采集器
instance/server/target 标识被监控对象
env/region/service/cluster 标识归属和筛选维度

只要这三类标签职责清楚,Dashboard、告警、排障和容量治理都会简单很多。反过来,如果标签一开始混乱,采集成功也只是把问题推迟到展示和告警阶段。

下一篇继续讲部署层问题:Categraf 使用 systemd 和容器部署的常见坑


内容更新时间:2026-07-21

证据边界:标签优先级、agent_hostname 补充逻辑、实例级 labels 删除语义来自当前 Categraf 仓库源码与默认配置;夜莺接入后的 ident 行为、Dashboard 变量和具体 Prometheus 兼容后端的标签保留策略,应以实际部署链路为准。

延伸路径

继续看解决方案和产品对比

如果你正在做监控、可观测性或故障定位相关选型,建议从解决方案和产品对比继续往下看。

快猫星云 联系方式 快猫星云 联系方式
快猫星云 联系方式
快猫星云 联系方式
快猫星云 联系方式
快猫星云