主题
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/告警/存储,与现有栈重复 | ❌ 栈重复(备选) |
| Odigos | eBPF + OTel agent 注入 | 半侵入(改 Pod) | 取决于注入的语言 agent | OTLP 到任意后端 | 由后端决定 | 是采集控制面,非数据源;仍需逐语言 agent | ❌ 定位不同 |
| OTel SDK / Operator | 语言级 agent | 改代码/注入 init 容器,逐语言接入 | 最精细(可自定义 span/属性) | OTLP 到任意后端 | 由后端决定 | 接入与版本对齐成本高,存量服务推不动 | ❌ 侵入性 |
| Service Mesh(Istio) | sidecar 代理 | 注入 sidecar | L4/L7 流量指标(限 mesh 内) | Prometheus | 可复用 | 为观测引入整个 Mesh 数据面,代价过高 | ❌ 杀鸡用牛刀 |
1.2 我们的约束与决策
uat1 的现实约束决定了答案:
- 已有完整监控栈:rancher-monitoring(Prometheus + Grafana + Alertmanager + 飞书路由)在役——要的是采集器,不是再造一套平台。这一条直接排除自带存储/UI/告警的 Pixie、DeepFlow、Coroot(它们的价值在"全家桶",与现有栈功能重复)。
- 数据不出内网 + 长期保留:Pixie 的数据存在节点内存里滚动覆盖,保留只有小时级,长期保留必须导出到外部系统或接 New Relic Cloud——与"复用 Prometheus/Tempo 长期存储"的目标相悖。
- 存量服务多、语言杂(Go/Java/C/Python 混部):SDK 逐语言接入推不动,必须零侵入。
- 厂商中立: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)设计决策:
- 不部署 OTel Collector:Beyla 直发 Tempo,少一跳;后续要采样/脱敏/多租户再插入 Collector,架构不用变。
- Tempo 单实例 + local backend(UAT):生产换对象存储(S3/MinIO)并升 distributed。
- 服务拓扑走 metrics-generator 回写:spanmetrics/servicegraph 聚合成指标 remote_write 回 Prometheus——Node Graph 查指标而非 trace,秒开;拓扑数据也随 Prometheus 长期保留。
- 复用 rancher-monitoring 全家桶:不新建 Prometheus/Grafana/Alertmanager,告警直接进现有飞书路由。
三、数据链路与排障动线
方案的核心价值在于三条数据流在 Grafana 里闭环,排障动线固定为三步:
- 发现:飞书收到
AppHighErrorRate(5xx>2%)或AppHighLatencyP99(>1s)告警 → 打开 RED 看板,按命名空间/服务分线定位到问题服务。 - 定位:Explore 查该服务的延迟 histogram,曲线上的 exemplar 点(每次采样的真实请求)点"查看 Trace" → Tempo 展开该请求的 span 树:in queue / processing / 下游调用各占多少毫秒。
- 归因:span 属性带完整
k8s_*标签(pod/node/container),配合 K8s 观测方案(节点/网络层指标)判断是应用慢、数据库慢还是底层网络/节点问题。
服务拓扑(Node Graph)回答另一个高频问题——"这个服务故障会牵连谁":client/server 边带调用率与错误率,爆炸半径一屏可见。
四、落地要点与踩坑(uat1 实测)
完整部署手册见 eBPF 全链路观测中间件文档,此处只列最痛的四个坑:
- Beyla v3 的
k8s_namespace选择器是 glob 不是正则。写.+或^(a|b)$会静默匹配 0 个进程——不报错、不告警,只是永远不埋点。诊断口径:debug 日志processes matching selection criteria len=0。 - RED 指标正常 ≠ trace 管线正常。v3 起指标走内核 eBPF map 聚合,trace 走 ring buffer 事件,两条路独立。验证 trace 必须看内部指标
:9099的beyla_ebpf_tracer_flushes_count与beyla_otel_trace_exports_total。 - 配置键名静默忽略。trace 导出 YAML 键是
otel_traces_export,误写otlp_traces_export无任何报错。 - 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 一路下钻到基础设施层指标,动线完整。