系统一多,为什么这么难查
单体时代排查问题很简单:一个进程,一份日志,一条堆栈基本就能说清发生了什么。等系统拆成十几个服务、调用链跨了三四跳,同样的报错可能来自上游、中间件、数据库,甚至一次超时重试。
可观测性要解决的就是这件事:系统内部的状态,能不能从外部推出来。它的三根支柱各管一段——日志记录细节、指标反映趋势、链路追踪还原一次请求的完整路径。
监控回答「系统挂了没有」,可观测性回答「为什么挂、卡在哪一步」。
三根支柱各看什么
- 日志某一次事件的具体细节。
- 指标一段时间里的数字变化。
- 追踪一次请求跨服务的完整路径。
日志:结构化的基础
日志是排查的第一现场。可观测性对日志的第一个要求是结构化:别把关键信息拼在字符串里,而是用键值对输出,机器才好在海量日志里检索和聚合。
# 不要这样打日志
log.info("用户 " + userId + " 下单失败,原因是 " + reason)
# 要这样打日志:字段是字段,值归值
log.info({"event":"order_failed","user_id":12345,"reason":"stock_insufficient","cost_ms":312})
结构化之后,还要带上请求标识、时间、服务名、环境等公共字段,让同一次请求的日志能被捞出来排成一行。
指标:用数字看趋势
日志太多没法逐条看,指标负责把系统状态压缩成数字:每秒请求量、错误率、延迟分位、队列长度。看到错误率爬坡,再去查日志,方向就有了。
| 方法 | 关注对象 | 典型指标 |
|---|---|---|
| RED | 服务请求 | 请求速率、错误率、延迟 |
| USE | 基础设施资源 | 使用率、饱和度、错误 |
RED 看用户体验,USE 看资源是否顶到天花板,两套一起用,基本能覆盖服务层和基础设施层。
链路追踪:一次请求走全链路
指标说「下单接口变慢了」,可它慢在网关、订单服务、库存服务还是数据库?链路追踪给每次请求一个全局标识,沿途每个服务都记录自己这段的耗时,最后拼出完整路径。
# 一个 trace 由多个 span 组成
trace_id = "a1b2c3"
span_a = {service:"api_gateway", span:"POST /order", cost_ms:320}
span_b = {service:"order_svc", span:"create_order", cost_ms:180}
span_c = {service:"inventory_svc",span:"check_stock", cost_ms:95, error:"timeout_retry"}
# 从 span_b 的 180 毫秒里,能看到大部分时间花在了调库存上
实现的关键是上下文传递:调用下游时把追踪标识塞进请求头,下游再透传给更下游,一整条链才能对上。
三根支柱怎么串起来
三根支柱单独用都有盲区:日志有细节但不成图景,指标有趋势但没有具体请求,追踪有路径但看不到业务数据。串起来的方法是让它们共享同一个关联键。
| 数据 | 关联字段 | 能回答的问题 |
|---|---|---|
| 指标 | 服务、接口 | 哪个接口错误率上升 |
| 追踪 | 请求标识 | 这条请求卡在哪个服务 |
| 日志 | 请求标识、用户标识 | 失败时的业务上下文是什么 |
从告警到定位的路径就通了:指标报警,拉出对应时段的追踪,再顺着请求标识翻日志,三步直达根因。
落地节奏与工具选型
可观测性不必一步到位,按成本从低到高铺:
- 先把日志结构化、集中采集,让日志可搜可聚合。
- 再上指标:接入服务请求量、错误率、延迟与资源使用率。
- 最后做链路追踪:先覆盖核心链路,再逐步铺开。
宁可先把核心链路的三根支柱打通,也不要一百个服务各打各的日志。
从能看见到能定位
可观测性的终点不是一块大屏,而是缩短从故障发生到根因定位的时间。
- 结构化日志让细节可检索。
- 指标让异常趋势提前暴露。
- 链路追踪让慢请求现出原形。
- 三者关联,让定位路径可以一路点下去。
当系统里每一次异常都能被看见、被关联、被定位,出故障就不再是摸着黑救火,而是按图索骥。