3. 计量数据采集架构
用量计量的第一道工程关口不是配额计算,而是“数据怎么进来”。同一套计费系统里,往往同时存在 SDK 直报、API 网关旁路、消息队列异步汇聚、日志采集和批处理对账五条路径。它们不是互相替代的关系,而是按“延迟—完整性—改造成本”三个维度分工。选型错误通常不会立刻暴露,而是在月末对账时以“少计”“重复计”“迟到计”的形式集中爆发。
五条采集路径的定位与适用边界
SDK 直报适合客户端或服务端能主动感知业务动作的场景,例如前端点击“导出报表”、后端调用“生成摘要”。SDK 在业务代码内埋点,采集粒度最细,可携带 tenant_id、user_id、resource_type、quantity 等业务语义字段,延迟通常在秒级。代价是侵入业务代码,且客户端不可信,必须做签名与幂等校验。
API 网关旁路适合以 HTTP 调用次数、请求体大小、响应字节数为计量对象的场景。网关在转发链路上解析路由、状态码、请求/响应长度,无需业务改造,天然覆盖所有经过网关的流量。但它看不到“一次请求内部实际消耗了多少 token 或计算量”,只能计量可观测的传输层指标。
消息队列汇聚适合高吞吐、允许秒级到分钟级延迟的场景。业务侧只负责把计量事件投递到 Kafka、Pulsar 或 RocketMQ,由独立的计量消费者做聚合、去重、补全维度后写入计量库。它把采集与计费解耦,削峰填谷,是大多数中大型 SaaS 的主干路径。
日志采集适合已有结构化日志、且不希望改动业务链路的场景。通过 Filebeat/Fluent Bit 采集应用日志中的计量字段,经解析后进入管道。优点是零侵入,缺点是字段规范依赖日志纪律,格式漂移会直接导致漏采。
批处理对账不作为主采集路径,而是兜底与校准手段。每日或每小时从业务库、对象存储、第三方账单中抽取全量或增量数据,与实时路径的计量结果比对,修复差异。它延迟最高,但完整性最强。
埋点规范:让每条事件都可被计费
无论走哪条路径,计量事件的最小字段集必须统一。建议以如下结构作为契约,缺一不可:
{
"event_id": "evt_9f3a2c81", // 全局唯一,用于幂等去重
"tenant_id": "t_1024", // 计费主体,必填
"metric": "api_calls", // 指标名,需在指标字典注册
"quantity": 1, // 本次增量,整数或定点小数
"unit": "count", // 单位:count/byte/token/second
"occurred_at": "2025-03-11T10:22:31.482Z", // 业务发生时间
"reported_at": "2025-03-11T10:22:33.105Z", // 上报时间
"source": "sdk_web", // 采集路径标识
"resource_id": "rpt_7781", // 可选,用于明细追溯
"idempotency_key": "t_1024:rpt_7781:export"
}
其中 occurred_at 与 reported_at 必须分开记录。前者用于归属计费周期,后者用于监控采集延迟。若只保留一个时间戳,迟到事件会被错误地计入下一个周期,造成跨月争议。idempotency_key 用于业务级去重,event_id 用于传输级去重,两者互补。
指标命名要遵循“域_对象_动作”的稳定约定,例如 storage_bytes_stored、ai_tokens_generated、api_requests_handled。禁止在指标名中混入租户或环境信息,这些应放在维度字段中。指标字典需要版本化,新增指标必须先在字典注册,否则计量管道应将其路由到死信队列而非静默丢弃。
数据完整性与延迟的权衡
完整性、延迟、成本三者不可兼得。实时路径追求低延迟,通常采用“至少一次”投递加幂等去重,代价是管道复杂度上升;批处理路径追求完整性,采用全量比对,代价是延迟以小时计。工程上的常见做法是分层:
- 实时层:SDK 与消息队列负责秒级计量,用于配额实时拦截和用量看板。允许极小比例的重复,通过
event_id去重。 - 准实时层:日志采集与网关旁路做分钟级补充,覆盖实时层遗漏的路径。
- 批处理层:每日从业务库和对象存储抽取全量数据,与实时汇总比对。差异超过阈值(例如 0.5%)时触发告警,并以批处理结果为准修正计量库。
判断一条路径是否合格,可以看三个指标:采集覆盖率(实际采集事件数 / 业务应产生事件数)、端到端延迟 P99(从 occurred_at 到写入计量库)、重复率(去重后保留数 / 原始接收数)。覆盖率低于 99.5% 或 P99 超过业务容忍窗口,就需要调整路径或增加兜底。
常见陷阱:把批处理对账当作“事后补救”而长期忽略。一旦实时路径出现系统性漏采,批处理差异会持续扩大,最终在账单上体现为大规模少计或多计。对账任务必须每日执行并输出差异报告,而不是等到月末才跑一次。
选型决策参考
| 场景特征 | 推荐路径 | 延迟预期 | 关键约束 |
|---|---|---|---|
| 客户端行为计量,需业务语义 | SDK 直报 | 秒级 | 签名校验、幂等、客户端不可信 |
| HTTP 调用量、流量计量 | API 网关旁路 | 秒级 | 仅传输层指标,无法感知业务消耗 |
| 高吞吐、多来源汇聚 | 消息队列 | 秒~分钟 | 需消费者幂等、水位线、死信处理 |
| 已有结构化日志、零侵入 | 日志采集 | 分钟级 | 日志格式必须稳定,字段缺失需告警 |
| 月末对账、差异修复 | 批处理 | 小时~天级 | 全量抽取成本高,需增量优化 |
实际系统中,这五条路径通常组合使用。例如:SDK 负责前端导出次数,网关负责 API 调用量,消息队列汇聚后端异步任务消耗,日志采集补充第三方回调,批处理每日校准。选型的核心不是“哪条最好”,而是“这条路径的延迟和完整性是否匹配该指标的计费敏感度”。配额拦截要求秒级,就必须走实时路径;月末账单允许小时级修正,就可以用批处理兜底。