Skip to content

eBPF 零侵入全链路观测方案(Beyla + Tempo)

微服务上了 K8s 之后,"服务慢/报错"的定位链条往往断在最痛的一环:基础设施监控(K8s 全链路观测告警方案)告诉你节点健康、Pod 存活,但应用层谁在调谁、哪个环节慢、哪次请求 5xx 了,传统方案要么给每个语言接 APM SDK(改代码、版本对齐、维护噩梦),要么上 Service Mesh(为观测引入一整套数据面,代价过高)。eBPF 给出了第三条路:在内核层自动埋点,不改一行代码、不加一个 sidecar,对所有进程(无论什么语言)产出 RED 指标与分布式 trace。

本文给出已在 uat1(RKE2,6 节点)完整落地验证的方案:Grafana Beyla(eBPF 采集)+ Tempo(trace 存储)+ 复用现有 Prometheus/Grafana/Alertmanager,并提供部署与运维全套文档。

读完本文你将得到

  • eBPF 应用观测的选型对比(Beyla / Pixie / DeepFlow / OTel Operator)与决策依据
  • 一套零侵入 RED 指标 + Trace + 服务拓扑的完整架构(已在 RKE2 落地)
  • Beyla v3 落地的关键踩坑清单(glob 选择器、静默忽略的配置键、双管线假象)
  • 从指标 exemplar 一键跳 trace 的排障动线设计

一、为什么是 eBPF

1.1 候选方案全景对比

方案采集方式侵入性信号覆盖数据去向长期存储/告警资源与运维结论
Beyla / OBI内核 eBPF(uprobe/kprobe)零侵入RED 指标 + Trace(HTTP/gRPC/SQL/Redis/Kafka/Mongo)OTLP/Prometheus,发到任意后端由后端决定(可复用现有栈)DS 每节点 ~100Mi,单一进程✅ 选它
Pixie(CNCF)内核 eBPF零侵入指标/Trace/全量请求体/Profile节点内存滚动存储(小时级)长期保留须导出或接 New Relic;自带 UI + PxL 查询语言每节点 1GiB 内存起步;查询/UI 自成体系❌ 见 1.2
DeepFlow内核 eBPF零侵入指标/Trace/流日志/Profile,网络面最强自带 server + ClickHouse自带完整平台组件多(agent/server/clickhouse),小集群过剩❌ 平台太重
Coroot内核 eBPF零侵入指标/Trace/日志/Profile + SLO/AI 根因自带 ClickHouse + 自有 UI自带完整平台(社区版免费)引入第二套 UI/告警/存储,与现有栈重复❌ 栈重复(备选)
OdigoseBPF + OTel agent 注入半侵入(改 Pod)取决于注入的语言 agentOTLP 到任意后端由后端决定是采集控制面,非数据源;仍需逐语言 agent❌ 定位不同
OTel SDK / Operator语言级 agent改代码/注入 init 容器,逐语言接入最精细(可自定义 span/属性)OTLP 到任意后端由后端决定接入与版本对齐成本高,存量服务推不动❌ 侵入性
Service Mesh(Istio)sidecar 代理注入 sidecarL4/L7 流量指标(限 mesh 内)Prometheus可复用为观测引入整个 Mesh 数据面,代价过高❌ 杀鸡用牛刀

1.2 我们的约束与决策

uat1 的现实约束决定了答案:

  1. 已有完整监控栈:rancher-monitoring(Prometheus + Grafana + Alertmanager + 飞书路由)在役——要的是采集器,不是再造一套平台。这一条直接排除自带存储/UI/告警的 Pixie、DeepFlow、Coroot(它们的价值在"全家桶",与现有栈功能重复)。
  2. 数据不出内网 + 长期保留:Pixie 的数据存在节点内存里滚动覆盖,保留只有小时级,长期保留必须导出到外部系统或接 New Relic Cloud——与"复用 Prometheus/Tempo 长期存储"的目标相悖。
  3. 存量服务多、语言杂(Go/Java/C/Python 混部):SDK 逐语言接入推不动,必须零侵入。
  4. 厂商中立:Beyla 已捐赠 OpenTelemetry(OBI),产出标准 OTLP/Prometheus 数据,后端可任意替换(Tempo → Jaeger/OTel Collector → 商业 APM),无锁定。

一句话:Beyla 是唯一"只补采集层、不碰现有栈"的零侵入方案;Pixie 适合开发态实时调试(全量请求体),DeepFlow/Coroot 适合没有监控栈、想要一体化平台的团队,SDK 适合对业务自定义 span 有刚需的核心服务(可与 Beyla 共存,后续按需补)。

二、总体架构

text
┌──────────────────────── 每个节点(6×)────────────────────────┐
│ 业务进程(Knative/Redis/ES/Kibana/自研…,任何语言)           │
│        ▲ eBPF uprobes/kprobes 自动埋点(零侵入)              │
│ Beyla v3.30(hostPID,仅 BPF/PERFMON/NET_ADMIN/SYS_PTRACE)   │
│     ├── :9090 Prometheus export(RED 指标,带 k8s_* 标签)   │
│     └── OTLP/gRPC ─────────────────────────┐                │
└────────────────────────────────────────────┼────────────────┘
              ▼(ServiceMonitor 拉取)          ▼
   rancher-monitoring Prometheus      Tempo v2.10.7(monolithic)
        ▲  ▲                          ├── WAL+blocks(NFS PVC,保留 48h)
        │  └──── remote_write ────────┴── metrics-generator
        │      traces_spanmetrics_* / traces_service_graph_*

   Grafana(数据源:Prometheus + Tempo 双向联动)
     ├── RED 看板(uid ebpf-apm-red)+ Explore Traces
     ├── exemplar(trace_id)── 指标一键跳 trace
     └── Node Graph(servicegraph,服务拓扑)
   Alertmanager ──► 飞书(5xx 错误率 / P99 / 组件 down)

设计决策:

  1. 不部署 OTel Collector:Beyla 直发 Tempo,少一跳;后续要采样/脱敏/多租户再插入 Collector,架构不用变。
  2. Tempo 单实例 + local backend(UAT):生产换对象存储(S3/MinIO)并升 distributed。
  3. 服务拓扑走 metrics-generator 回写:spanmetrics/servicegraph 聚合成指标 remote_write 回 Prometheus——Node Graph 查指标而非 trace,秒开;拓扑数据也随 Prometheus 长期保留。
  4. 复用 rancher-monitoring 全家桶:不新建 Prometheus/Grafana/Alertmanager,告警直接进现有飞书路由。

三、数据链路与排障动线

方案的核心价值在于三条数据流在 Grafana 里闭环,排障动线固定为三步:

  1. 发现:飞书收到 AppHighErrorRate(5xx>2%)或 AppHighLatencyP99(>1s)告警 → 打开 RED 看板,按 命名空间/服务 分线定位到问题服务。
  2. 定位:Explore 查该服务的延迟 histogram,曲线上的 exemplar 点(每次采样的真实请求)点"查看 Trace" → Tempo 展开该请求的 span 树:in queue / processing / 下游调用各占多少毫秒。
  3. 归因:span 属性带完整 k8s_* 标签(pod/node/container),配合 K8s 观测方案(节点/网络层指标)判断是应用慢、数据库慢还是底层网络/节点问题。

服务拓扑(Node Graph)回答另一个高频问题——"这个服务故障会牵连谁":client/server 边带调用率与错误率,爆炸半径一屏可见。

四、落地要点与踩坑(uat1 实测)

完整部署手册见 eBPF 全链路观测中间件文档,此处只列最痛的四个坑:

  1. Beyla v3 的 k8s_namespace 选择器是 glob 不是正则。写 .+^(a|b)$静默匹配 0 个进程——不报错、不告警,只是永远不埋点。诊断口径:debug 日志 processes matching selection criteria len=0
  2. RED 指标正常 ≠ trace 管线正常。v3 起指标走内核 eBPF map 聚合,trace 走 ring buffer 事件,两条路独立。验证 trace 必须看内部指标 :9099beyla_ebpf_tracer_flushes_countbeyla_otel_trace_exports_total
  3. 配置键名静默忽略。trace 导出 YAML 键是 otel_traces_export,误写 otlp_traces_export 无任何报错。
  4. Prometheus remote-write 开关已改名。新版是 --web.enable-remote-write-receiver,旧的 --enable-feature=remote-write-receiver 直接 Unknown option 拒绝启动。

其余(Grafana 数据源 provisioning 只读、distroless 镜像无法 exec 自测、Knative 缩零干扰验证等)共 10 条,见部署文档踩坑表。

五、实测效果(uat1)

  • 自动埋点范围:Knative 全链路(activator → queue-proxy → user-container,Go)、redis、proxysql、kibana/logstash(Java 通用模式)、k8sgpt 等,零配置。
  • 数据规模:单节点 Beyla 数小时导出 2 万+ span;spanmetrics 124 条 series、servicegraph 15 条拓扑边。
  • 资源开销:Beyla 每节点约 100Mi 内存级,无感。
  • 已知限制(UAT 可接受,生产有解):跨进程 trace 在进程边界断链(需加 CAP_SYS_ADMIN 开启 Go context propagation);Java TLS 加密流量不可见;Tempo 单实例无 HA。

六、与 K8s 观测方案的关系

本方案是 Kubernetes 全链路观测与告警方案应用层补完:

方案回答
基础设施层K8s 全链路观测告警方案集群健不健康(节点/DNS/CNI/控制面)
应用层(本文)eBPF 零侵入观测(Beyla+Tempo)请求健不健康(谁慢、谁错、谁调谁)

两层共用同一套 Prometheus/Grafana/Alertmanager,告警统一进飞书,排障时从应用层 trace 一路下钻到基础设施层指标,动线完整。

七、文档索引