Appearance
可观测性:从事件到可验证证据
专题索引 / 上一篇:持久化存储:PVC 到 Linux VFS
可观测性不是“系统有日志”。它是一组证据契约:某个动作发生后,哪些状态变化会留下什么记录;记录由谁采集、会保留多久、能否与同一次请求关联,以及它究竟能证明到哪一步。
text
应用 / 内核 / Kubernetes 组件发生事件
-> 生成日志、metric sample、span、Event 或 tracepoint
-> SDK、runtime 或 agent 采集
-> collector 做批处理、重试、采样或聚合
-> 存储系统索引、压缩、保留
-> 查询、告警、关联与故障结论前面页面中的 PVC=Bound、CSI mount、Service endpoint、NetworkPolicy drop、fsync,都不是同一种事件。把它们塞进一条无结构日志,会丢掉时间、归属和查询能力。
1. 五种证据各自回答什么
| 证据 | 主要回答 | 不能单独证明 |
|---|---|---|
| 结构化日志 | 某组件在某时刻做了什么、看到什么错误 | 全局发生率、完整调用链或用户已看见结果 |
| metrics | 一段时间内的次数、速率、分位数、资源使用 | 某个具体请求为何失败 |
| trace / span | 一次同步或异步工作跨组件的因果与耗时 | 所有请求都已保存,或业务结果一定正确 |
| Kubernetes Event / status | 控制器观察到的资源生命周期与条件 | 高保真审计日志或数据面逐包结果 |
| kernel tracepoint / profiler | 调度、I/O、网络、系统调用等底层执行证据 | 应用业务语义 |
它们不是互相替代关系。指标发现“错误率上升”,trace 缩小到一类请求,日志给出错误细节,内核 trace 再判断是调度、I/O 还是网络路径造成的等待。
2. 相关性是数据契约,不是检索技巧
一个 HTTP 请求跨网关、应用、数据库和异步队列时,必须有能传递的关联身份:
text
request_id:业务或入口层的稳定请求关联
trace_id:一次分布式 trace 的全局身份
span_id:trace 内单个操作
causation_id:异步任务由哪个动作触发
attempt_id:同一业务动作的第几次执行HTTP 常用 W3C Trace Context 的 traceparent 传递 trace/span 上下文。异步消息不能只复制“当前线程变量”:生产者、消费者、重试和批处理必须定义父子 span、span link 或 causation ID 的语义,否则时间线看似连续,实际会把不同尝试混在一起。
关联 ID 应进入日志字段和 trace 属性;但不应把 user_id、request_id、完整 URL 或订单号直接作为 Prometheus metric label。metrics 的 label 组合会形成时序基数,任意请求 ID 会让内存、索引和查询成本失控。
3. 数据从哪里来,在哪些地方会丢
日志
容器常把 stdout/stderr 交给 runtime,runtime 写 Node 本地的容器日志文件;日志 agent tail 文件或读取 runtime 接口,再向后端发送。应用崩溃、Node 磁盘满、日志轮转、agent backpressure、采集配置错误都可能让日志不完整。
日志格式至少应包含时间、级别、组件、事件名、关联 ID 和经过脱敏的错误上下文。把长堆栈、请求体、密钥或个人数据默认全量采集,通常会让检索、安全和成本一起失控。
Metrics
Prometheus 风格的 metrics 通常由目标暴露一个 scrape endpoint,采集端定时拉取并写成时间序列;也可经 collector remote write 到长期存储。counter、gauge、histogram 是不同数据模型:例如延迟分位数必须从 histogram bucket 或等价分布数据计算,不能从任意平均值还原。
采集失败、scrape 间隔、target 重启、样本保留与 downsampling 都会影响结论。监控图上没有数据,可能是系统空闲、采集失败、标签筛选错误或保留期已过,不能直接读成“没有发生”。
Trace
trace 由多个 span 组成。span 需要开始/结束时间、服务与操作名、状态、关联上下文和有限的属性。高吞吐系统会采样:未采样请求可能只有 metrics 或日志,因此“查询不到 trace”只能说明当前采集策略下没有这条 trace,不等于请求不存在。
Kubernetes Event 与 status
Event 适合说明 controller 或 kubelet 观察到的调度、拉镜像、挂载、探针等资源动作,但它有聚合和保留限制。status.conditions 是资源当前观察状态,适合自动化判断收敛;两者都不是替代应用审计日志的长期事实库。
内核证据
Linux tracepoint、ftrace、perf、eBPF profiler 能在低层说明线程何时被唤醒、是否等待 I/O、发生了哪些网络或调度事件。它们通常是按需打开且有开销,不能把所有低层事件长期无差别存储;要先由应用和指标定义问题窗口,再抓取足够窄的系统证据。
4. 一次“请求超时”的证据链
text
t0 网关收到 request_id / trace_id
t1 应用 span 开始,记录依赖调用
t2 数据库或下游 span 变慢,或系统线程进入 I/O wait
t3 超时计数与延迟 histogram 增加
t4 网关写入最终状态;用户端是否收到响应另有客户端证据正确的结论应逐段限定:
| 观察 | 能先得出的结论 | 还缺什么 |
|---|---|---|
| P99 上升 | 某类操作的尾延迟变差 | 哪个请求、哪一段依赖 |
| trace 显示 DB span 长 | 该请求在 DB 调用上等待 | DB 是慢还是连接池、网络或锁在等待 |
| 应用日志有 timeout | 应用按超时路径处理了 | 服务端动作是否最终成功或晚到完成 |
| kernel trace 有 block I/O 等待 | 线程确实受 I/O 路径影响 | 业务操作和具体存储资源的对应关系 |
这和客户端渲染的 t0..t8 是同一方法:不跨过中间完成点,不用单一工具替整个链路下结论。
5. 架构上的分层与成本控制
text
应用语义层:事件名、错误分类、业务关联 ID、SLO
采集层:SDK、runtime、agent、collector、采样和脱敏
存储层:时序库、日志索引、trace backend、对象存储
查询层:仪表盘、告警、追踪查询、排障工作流每层都需要明确 owner。开发者拥有业务语义和错误分类;平台团队拥有采集可靠性、容量和访问控制;SRE 或服务 owner 共同定义 SLO、告警阈值和响应手册。把这些责任混成“平台会自动监控”,最后通常得到大量仪表盘和很少可行动结论。
成本也按信号类型分别管理:metrics 控制 label 基数与保留;logs 控制字段大小、采样、脱敏和索引;traces 控制采样率与属性;内核采集限制时间窗口和目标进程。先定义故障时必须回答的问题,再决定采多少,而不是反过来。
6. 源码与资料入口
- Kubernetes:System Logs、Metrics for Kubernetes System Components、Events,访问于 2026-08-03。
- Kubernetes 源码:
staging/src/k8s.io/component-base/metrics/、pkg/kubelet/events/,访问于 2026-08-03。 - OpenTelemetry:Specification、W3C Trace Context,访问于 2026-08-03。
- Prometheus:Metric and Label Naming、Histograms and Summaries,访问于 2026-08-03。
- Linux:ftrace、trace events,访问于 2026-08-03。
本文给出的是证据模型,不承诺某个采集器或后端的实现。字段、采样、保留、访问控制和脱敏策略应在目标系统中作为版本化的数据契约维护。