4、Counter(计数器)详解:适用场景、创建方式、Add方法、常见错误(如重复累加)
Counter 是 OpenTelemetry 中最基础、最常用的同步指标类型,用于记录单调递增的累积值。它只支持增加操作,不支持减少或重置(除非进程重启)。理解 Counter 的语义、创建方式和常见陷阱,是构建可靠可观测性体系的第一步。
4.1 适用场景
Counter 适合统计只增不减的事件或量,典型场景包括:
- 请求计数:HTTP 请求总数、RPC 调用次数。
- 错误计数:4xx/5xx 响应次数、异常抛出次数。
- 业务量统计:订单创建数、用户注册数、消息投递数。
- 吞吐量统计:处理的字节数、写入的记录数。
提示:如果指标需要支持减少或重置(如当前连接数、队列深度),应使用 UpDownCounter 或 Gauge,而非 Counter。
4.2 创建方式
Counter 通过 Meter 实例创建,需要指定名称、可选的描述和单位。以下是 Java 和 Python 的典型创建方式:
Java (OpenTelemetry SDK)
// 获取 Meter
Meter meter = GlobalOpenTelemetry.getMeter("com.example.metrics");
// 创建 Counter
LongCounter requestCounter = meter
.counterBuilder("http.requests.total")
.setDescription("Total number of HTTP requests")
.setUnit("1")
.build();
Python (opentelemetry-api)
from opentelemetry import metrics
meter = metrics.get_meter("com.example.metrics")
request_counter = meter.create_counter(
name="http.requests.total",
description="Total number of HTTP requests",
unit="1",
)
| 参数 | 说明 | 建议 |
|---|---|---|
| name | 指标名称,全局唯一 | 使用点分命名空间,如 http.requests.total |
| description | 可读描述,帮助理解指标含义 | 必填,便于团队协作 |
| unit | 单位,如 1、ms、bytes |
推荐使用 UCUM 标准单位 |
4.3 Add 方法详解
Counter 的核心操作是 Add(),用于增加计数。每次调用必须传入非负整数或浮点数,并可以附带标签(Attributes)。
基本用法
// Java
requestCounter.add(1, Attributes.of(
AttributeKey.stringKey("method"), "GET",
AttributeKey.stringKey("status"), "200"
));
# Python
request_counter.add(1, {"method": "GET", "status": "200"})
批量累加
当需要一次性增加较大数值时,直接传入增量值:
// 记录一次请求处理了 2048 字节
bytesCounter.add(2048, Attributes.of(
AttributeKey.stringKey("endpoint"), "/upload"
));
警告:
Add() 的增量值必须 ≥ 0。传入负数会抛出异常或导致未定义行为,不同 SDK 实现可能不同。
4.4 常见错误:重复累加
Counter 最常见的错误是无意中重复累加,导致指标值远高于实际值。以下场景极易触发此问题:
- 中间件/拦截器重复调用:请求经过多个拦截器,每个拦截器都执行了一次
Add()。 - 异步回调重复触发:回调函数被多次调用,每次调用都增加计数。
- 重试逻辑未去重:客户端重试时,每次重试都记录一次“请求总数”,而非仅记录一次。
- 指标对象被多次创建:每次请求都重新创建 Counter 实例,导致同一标签组合被多个实例累加。
正确做法
- 单点计数:在请求处理的最外层或唯一入口处执行
Add()。 - 使用标签区分:如果必须多次计数,用不同标签区分(如
stage: "before_retry"vsstage: "after_retry")。 - 复用 Meter 和 Counter 实例:Counter 应在应用启动时创建一次,全局复用。
最佳实践:在关键路径上打印日志或使用单元测试验证 Counter 的最终值,确保累加次数与预期一致。
4.5 Counter 数据流与累加逻辑
下图展示了 Counter 从创建到被后端系统消费的完整数据流,以及重复累加如何影响最终值:
4.6 Counter 与 UpDownCounter 对比
| 特性 | Counter | UpDownCounter |
|---|---|---|
| 增减方向 | 仅增加(单调递增) | 可增可减 |
| 典型场景 | 请求总数、错误总数 | 当前连接数、队列深度 |
| Add 参数 | 必须 ≥ 0 | 可为负数 |
| 聚合语义 | Sum(求和) | Sum(求和) |
| 重置行为 | 进程重启后重置 | 进程重启后重置 |
4.7 避坑清单
- 不要用 Counter 记录瞬时值:如 CPU 使用率、内存占用,应使用 Gauge。
- 不要用 Counter 记录可减少的量:如活跃用户数,应使用 UpDownCounter。
- 不要在热点路径中频繁创建 Counter 实例:应在初始化阶段创建并复用。
- 注意标签基数:每个唯一的标签组合都会产生一个时间序列,避免高基数标签(如用户 ID、请求 ID)。
- 测试时验证累加次数:使用单元测试或集成测试,确保每个请求只触发一次
Add()。
总结:Counter 是 OpenTelemetry 指标体系的基石,正确使用它需要理解单调递增语义、合理选择标签、避免重复累加。掌握这些要点后,你将能构建出准确、可靠的自定义指标。