首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >IT咖啡馆 | 漫谈OTel Gateway 的设计与思考

IT咖啡馆 | 漫谈OTel Gateway 的设计与思考

原创
作者头像
行者深蓝
修改2025-08-25 21:16:22
修改2025-08-25 21:16:22
15600
代码可运行
举报
运行总次数:0
代码可运行

摘要

OpenTelemetry Gateway 在本方案中承担“区域网关”角色:统一接入 OTLP(gRPC/HTTP)与(可选)Kafka,完成标签规范化、事件 ID 生成、限流/采样、路由与多路扇出,并用 sending_queue + file_storage 构建 持久化 WAL,在后端短抖或升级期间保证不丢与可重放。近线检索走 OpenObserve,“真源”沉淀在 Kafka,再由 ETL 汇入 PostgreSQL/ClickHouse 等数仓。该架构天然支持多区域自治 + 主区统一查询,并为 AI 运维与回放分析夯实数据底座。OpenTelemetryAxoflow


1. 要点与设计目标

定位(区域网关)

  • 统一接入:receivers.otlp(gRPC/HTTP),可选 receivers.kafka(otlp_proto)。
  • 可靠传递:所有关键 exporter 开启 sending_queue 并指定 storage: file_storage,落到本地 WAL,进程崩溃或重启后可恢复;队列与 WAL 尺度受控。OpenTelemetrySplunk Community
  • 治理与扇出:在网关做规范化、打标签、事件 ID、限流/采样、路由,多路发往 OpenObserve(近线)Kafka(真源)

职责分层

  • 边缘(Vector/Agent):轻量采集 + 本地背压/磁缓冲;尽量少做重处理。
  • 区域(otelcol):协议汇聚 + WAL + 流量治理 + 扇出与路由。
  • 后端:OpenObserve(近线检索/告警)、Kafka(旁路真源/回放/镜像)、PG/CH(分析)。

SLO 目标

  • “不丢 + 可回放 + 可观测”为一等公民:端到端 P95 延迟、投递成功率、重试次数、队列深度、WAL 占用纳入面板与告警。
  • 严禁把日志/指标塞进 span 属性膨胀负载;各类信号各司其职。Grafana Labs

2. 区域拓扑与处理链

代码语言:javascript
代码运行次数:0
运行
复制
[Producers/Agents/Apps]
   └─ OTLP gRPC/HTTP / Filelog/Prom→OTLP
        → [OTel Gateway (Region-A, N副本 behind LB)]
             ├─ 归一/打标签/生成 event_id(OTTL/attributes)
             ├─ 分流→ OpenObserve.A(近线检索/告警)
             └─ 分流→ Kafka.A(*_raw 真源/回放)
                     ↘(ETL)→ PostgreSQL.A / ClickHouse(明细/聚合/向量)

通用处理链(建议)

  1. resource/attributes 归一化:补齐 service.name/host.name/cluster/region/env/tenant 等关键维度。
  2. event_id 生成:基于(tenant、service、内容片段、时间窗)稳定哈希去重键;在日志/事件面生成。
  3. 限流/采样:日志采样、Trace tail-sampling、裁剪高基数字段。
  4. 路由与扇出:按 tenant/region/env/kind 分流到不同 exporter(OpenObserve、Kafka、VictoriaMetrics 等)。
  5. 批处理与压缩:统一 batch / flush 降压。(OTTL/Processors 详见 OTel 官方“Transforming telemetry”与 OTTL 指南。)OpenTelemetrydash0.comBetter Stack

3. 多区域设计

分区自治,主区统一查询

  • A/B/C 各区自有 OpenObserve / Kafka / PG,互不影响
  • 主区(A)提供统一查询与汇总(API Gateway / Query Proxy / 联邦查询)。
  • 跨区镜像策略
    • 关键数据双写(例如 *_norm、抽样 trace)到主区;
    • 或以 MirrorMaker2 做 Kafka 镜像到中央集群,再统一归一化、构建合并视图(跨区 RCA/报表)。

近线与真源

  • 近线(OpenObserve):最近 N~30 天快速检索与告警;
  • 真源(Kafka):长期保留 *_raw(冷热分层 + 对象存储),用于回放、重建索引或 AI 训练集。

关于 Loki Ingestion

  • OpenObserve 在 v0.15.0 里程碑支持 Loki Push API/loki/api/v1/push)的写入兼容;查询仍走 O2 原生接口或 Grafana O2 插件,不等同于 Loki 查询 API。GitHub

4. LogQL → OpenObserve Facade(自建查询门面)

目标是在不改动前端面板(Grafana 使用 Loki 数据源 + LogQL)的前提下,把查询转译为 O2 的 SQL/原生检索,并返回 Loki API 兼容 JSON

  • 对外暴露:/loki/api/v1/query/query_range/labels 等。
  • 内部流程:解析 LogQL AST → 映射到 O2 过滤/解析/聚合 → 重组为 Loki 响应结构(streams/matrix/vector)。
  • AST 建议复用 Loki 开源解析器(只用解析,不依赖其存储)。HTTP 语义参见 Loki 官方文档。Grafana Labs

基本映射规则

  • 选择器 {app="web", env=~"prod|staging"} → O2 标签列等值/正则过滤;
  • 时间窗/方向/limit → O2 查询的 time range / order / limit
  • 管道 |= / |~ → O2 全文/正则;
  • | json / | logfmt → O2 动态字段解析;
  • count_over_time()/rate_over_time() + sum by(...) → O2 分桶聚合 + 维度分组。
  • 注意返回结构:严格遵循 Loki HTTP API 的 status/data/resultType/result 形态(兼容 Grafana)。Grafana Labs

备注:这是查询门面,与采集/转发无耦合;不建议塞进 otelcol 里实现(otelcol 不提供对外用户查询 API)。如果未来要把“日志→迹”的跨信号转换做成组件,建议基于 otelcol connector 自研。OpenTelemetry


5. DeepFlow L4/L7 → Tracing Span 聚合(思路与步骤)

目标:把 DeepFlow 的 L4/L7 flow log / metric 聚合成 OTLP Trace(span)并与应用侧 trace 互相补充(网络面观察 + 业务面调用)。 参考做法:

  1. 接入
    • DeepFlow 产生的 L4/L7 明细以结构化日志(JSON)进入 otelcol(receivers.filelog 或 HTTP/OTLP 转换)。
    • 建议尽可能在源头附带 trace_id/span_id 线索;若无,则按 5 元组 + 起止时间窗 确定性哈希 生成。OpenTelemetry

2. 聚合与构造 span

  • 聚合键{src_ip, src_port, dst_ip, dst_port, protocol} + 方向 + 首包时间窗(例如 1s 滑窗)。
  • span 属性映射(择要):
    • 网络:net.transportnet.peer.ip/portnet.host.ip/port、RTT、bytes_{sent,received}。
    • HTTP:http.request.methodhttp.response.status_codeurl.pathuser_agent
    • 数据库:db.systemdb.statement(脱敏)。
    • RPC:rpc.systemrpc.servicerpc.method
  • span.kind:Client/Server 依据方向与监听端口。
  • 错误归因:TCP RST/超时、HTTP ≥ 500 映射为 status.code=ERROR 并附 exception.message

3. 实现形态

  • A 案:在 otelcol 自研 Connector(logs→traces):消费 logs,产出 traces(官方文档提供 Connector 开发指引);
  • B 案:外部微服务 flow2trace(Go),从 Kafka *_raw 消费,产出 OTLP trace 送回 otelcol(receivers.otlp)。

说明:OTTL/processor 很难“凭空生成 span 对象”并写回 traces pipeline;因此更推荐 Connector 或外部微服务 路径(类似官方 spanmetrics 这种跨信号组件的做法)。OpenTelemetry


6. otelcol(区域网关)最小可用配置

代码语言:javascript
代码运行次数:0
运行
复制
extensions:
  file_storage:
    directory: /var/lib/otelcol/wal
  health_check: {}
  pprof: { endpoint: 0.0.0.0:1777 }
  zpages: {}

receivers:
  otlp:
    protocols:
      grpc: { endpoint: 0.0.0.0:4317 }
      http: { endpoint: 0.0.0.0:4318 }

processors:
  memory_limiter:
    check_interval: 1s
    limit_percentage: 75
    spike_limit_percentage: 15

  batch:
    send_batch_size: 10000
    timeout: 2s

  resource/env:
    attributes:
      - key: region       ; action: upsert ; value: region-a
      - key: environment  ; action: upsert ; value: prod

  attributes/normalize:
    actions:
      - key: cluster      ; action: insert ; value: default
      - key: tenant       ; action: insert ; value: public
      - key: service.name ; action: upsert ; from_attribute: service

  transform/logs:
    error_mode: ignore
    log_statements:
      - set(attributes.event_id, SHA1(Concat([attributes.tenant, attributes.service.name, body, TruncateTime(timestamp, "1s")], "|")))

  tail_sampling:
    decision_wait: 5s
    num_traces: 50000
    expected_new_traces_per_sec: 10000
    policies:
      - name: error-traces
        type: status_code
        status_code: { status_codes: [ERROR] }
      - name: key-services
        type: string_attribute
        string_attribute: { key: service.name, values: ["api-gateway","payment"] }
      - name: probabilistic
        type: probabilistic
        probabilistic: { sampling_percentage: 10 }

exporters:
  # OpenObserve(注意:若用 Loki Push API,请用 loki exporter/receiver,见下方提示)
  otlphttp/openobserve:
    endpoint: https://o2.region-a.example/api/default/
    headers: { Authorization: "Basic <REDACTED>" }
    retry_on_failure: { enabled: true }
    sending_queue:
      enabled: true
      num_consumers: 8
      queue_size: 20000
      storage: file_storage

  # Kafka 真源(*_raw)
  kafka/logs:
    brokers: ["kafka-a-1:9092","kafka-a-2:9092","kafka-a-3:9092"]
    topic: logs_raw
    encoding: otlp_proto
    sending_queue: { enabled: true, storage: file_storage }

  kafka/metrics:
    brokers: ["kafka-a-1:9092","kafka-a-2:9092","kafka-a-3:9092"]
    topic: metrics_raw
    encoding: otlp_proto
    sending_queue: { enabled: true, storage: file_storage }

  kafka/traces:
    brokers: ["kafka-a-1:9092","kafka-a-2:9092","kafka-a-3:9092"]
    topic: traces_raw
    encoding: otlp_proto
    sending_queue: { enabled: true, storage: file_storage }

service:
  extensions: [file_storage, health_check, pprof, zpages]
  pipelines:
    logs:
      receivers: [otlp]
      processors: [memory_limiter, resource/env, attributes/normalize, transform/logs, batch]
      exporters: [otlphttp/openobserve, kafka/logs]
    metrics:
      receivers: [otlp]
      processors: [memory_limiter, resource/env, attributes/normalize, batch]
      exporters: [otlphttp/openobserve, kafka/metrics]
    traces:
      receivers: [otlp]
      processors: [memory_limiter, resource/env, attributes/normalize, tail_sampling, batch]
      exporters: [otlphttp/openobserve, kafka/traces]

提示(Loki Push 相关)

  • 若要从 otelcol 写 Loki Push API,请使用 loki exporter/receiver,确保路径就是 /loki/api/v1/push;避免 OTLP HTTP exporter 额外拼 /v1/logs 造成 404(曾有踩坑 issue)。GitHub

7. Topic & Schema 治理(范式)

  • 命名<region>.<tenant>.<kind>_<form>.v<schema>,如:a.public.logs_raw.v1a.public.traces_raw.v1
  • 分区键tenant + service.name + yyyyMMddHH(控热点兼顾有序)
  • 保留策略*_raw 保留 7–30 天(冷热分层);*_norm 更长;审计类可启用 compaction。
  • Schema 演进:双写新旧版本、灰度切读,落文档契约。

8. 安全与多租户

  • 全链路 TLS/mTLS;Kafka ACL 以 tenant/topic 细分。
  • 在网关强制写入 tenant,以此做配额、路由与访问控制。
  • 脱敏与审计:在网关完成敏感字段裁剪(PII、Secrets)。

9. 容量规划与 K8s 部署要点(要点清单)

  • WAL 盘:本地 NVMe(Local PV/hostPath),容量= 峰值入流量 × 预期不可用窗口 × 放大系数;启用 file_storage 的持久化队列。OpenTelemetry
  • 副本与升级:pod 反亲和 + PDB;滚更 maxUnavailable=1;灰度观察 exporter_send_failed_total、队列深度、WAL 占用。
  • HPA 指标:基于 receiver_accepted_*exporter_queue_size、CPU/内存。
  • 自观察:暴露 otelcol 自身 metrics,做“队列深度、重试、失败率、处理延迟”面板。
  • 已知坑: 某些组合下 headers_setter 与持久队列会影响 header(如 X-Scope-OrgID)透传,需关注版本与已修 issue。GitHub

10. Runbook(浓缩)

  • 下游挂了:观察 exporter_send_failed_total / sending_queue_size / WAL;评估恢复窗口与 WAL 容量;必要时临时降采样。
  • 流量暴涨:在网关动态采样/裁剪,热点服务可路由至专用 Kafka 主题。
  • 跨区查询慢:使用主区联邦/汇总视图;只镜像 *_norm 与关键 traces。
  • Schema 升级:双写新旧、灰度消费者;成功后切读并清理旧版。

附录 A:边缘 Vector 与区域 otelcol 的分工

  • 为何边缘用 Vector:轻量、背压稳、本地缓存好维护;采集侧尽可能简单可靠。
  • 为何网关用 otelcol:协议原生、处理器/connector 生态丰富、WAL 可靠、扇出广,适合区域级“数据治理与转运中枢”。OpenTelemetry

附录 B:LogQL→O2 Facade 的最小实现清单

  • 解析:复用 Loki LogQL 解析器;
  • 映射:覆盖选择器 + |= / |~ + | json/logfmt + count_over_time/rate_over_time + sum by()
  • 端点:/query/query_range
  • 结果:严格按 Loki HTTP API 返回;
  • 性能:分片并发到 O2,再在门面层归并;适当做二级缓存。Grafana Labs

附录 C:DeepFlow 融合路径

  • 直接 OTLP 导出 span(DeepFlow→OTLP→otelcol);或flow2trace(Kafka *_raw → OTLP spans);或
  • 自研 logs→traces connector(官方 connector 开发指引可复用)。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 摘要
  • 1. 要点与设计目标
  • 2. 区域拓扑与处理链
  • 3. 多区域设计
  • 4. LogQL → OpenObserve Facade(自建查询门面)
  • 5. DeepFlow L4/L7 → Tracing Span 聚合(思路与步骤)
  • 6. otelcol(区域网关)最小可用配置
  • 7. Topic & Schema 治理(范式)
  • 8. 安全与多租户
  • 9. 容量规划与 K8s 部署要点(要点清单)
  • 10. Runbook(浓缩)
    • 附录 A:边缘 Vector 与区域 otelcol 的分工
    • 附录 B:LogQL→O2 Facade 的最小实现清单
    • 附录 C:DeepFlow 融合路径
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档