上个月我们组上线了一款新业务模块,上线前大家忙着改代码、调参数,上线后半小时,线上反馈订单量异常。几个人对着日志文件一通翻,翻了快四十分钟才定位到是下游服务超时,而那段时间监控面板上一片空白——不是没数据,是我们压根没来得及搭完整的可观测性体系。这件事之后,我把“新业务上线前必须完成可观测性构建”写进了团队的上线检查清单,也整理出了这一套落地实施方案。今天就把这套方案完整地拆给大家,覆盖日志、指标、链路追踪三大支柱的选型思路、具体部署步骤、上线前后的实操细节,以及我踩过的那些坑。无论你是后端开发、运维、SRE,还是带团队的技术负责人,这篇文章都值得你收藏,下次新业务上线直接照着做就行。
1. 新业务上线为什么必须先搭可观测性——设计方案的核心思路
先说一个我观察到的普遍现象:大部分团队的新业务上线,把大量精力花在功能测试和性能压测上,但可观测性建设往往被推到“上线后再说”。这个顺序看起来合理,实际上特别危险。
1.1 上线前搭和上线后补,成本完全不是一个量级
上线前搭可观测性,业务流量小、接口路径少、改动成本低,你可以从容地给日志加字段、给核心接口埋指标、给调用链加上下文。上线后再补这些东西,你面对的是真实流量下的线上系统,每一次改动都意味着重新发布,风险成倍增加。更麻烦的是,上线初期没有监控数据积累,出了问题连对比的基线都没有,根本无法判断当前的表现是正常波动还是已经异常。
我打个比方。装修房子的时候布线,和住进去之后再凿墙走线,花的钱和精力不在一个数量级。可观测性就是给系统提前“布好线”,上线那一刻就能看到全局。等到线上出事才想起看监控,那只能算亡羊补牢,而且大概率连羊跑了多少都数不清。
所以我的观点很明确:可观测性构建不是“上线后可选项”,而是“上线前必须项”。它应该作为新业务研发流程的一部分,和功能开发、测试同等对待,写进上线检查清单里。
1.2 可观测性的三大支柱,一个都不能少
业内常说可观测性有三大支柱:Metrics(指标)、Logs(日志)、Traces(链路追踪)。这三者解决的是完全不同的问题,互相之间无法替代。
指标告诉你“系统现在好不好”,比如每秒请求数、错误率、P99延迟、CPU使用率。它适合做告警和趋势分析。指标的问题在于,它只告诉你“病了”,不告诉你“哪里病了”。
日志告诉你“系统里具体发生了什么”,比如某次请求打印的错误信息、异常堆栈、业务关键日志。它适合做问题定位。但日志是分散的,一个请求经过多个服务,会生成多条日志,如果字段不规范、没有统一标识,你很难把这些日志串起来。
链路追踪告诉你“一个请求经过了哪些服务、每段花了多长时间”。它适合做性能瓶颈分析和调用关系梳理。有了它,你才能在分布式系统里把请求的完整路径还原出来。
这三者的关系,我用一句话概括:指标负责“报警”,日志负责“解释”,链路负责“找路”。真正有效的可观测性体系,必须把这三者打通,尤其是用统一的请求标识(trace_id)把日志和链路关联起来。这样收到告警之后,你能一键从指标下钻到链路,再从链路关联到具体日志,十分钟内定位问题。
1.3 选型时先想清楚三个问题
市面上可观测性工具非常多,开源的有 Prometheus、Grafana、ELK、Jaeger、SkyWalking,商业的有 Datadog、New Relic。选型之前,我建议团队先回答三个问题,而不是直接冲进工具对比的细节里。
第一个问题:自建还是用商业方案。自建的优势是数据不出内网、安全可控、长期成本低,但需要投入维护人力。商业方案的优势是开箱即用、省心,但数据在别人平台上,而且用户量上来之后费用不便宜。我的建议是:团队有专职运维或 SRE 角色,优先自建;否则可以先从商业方案起步,等规模大了再评估迁移。
第二个问题:统一采集还是各服务各搞。新业务上线时,可能不同小组用自己的方式上报日志和指标,短期看效率挺高,长期维护起来特别痛苦。最好一开始就统一采集方案、统一日志格式、统一指标命名规范,哪怕先做得粗糙一点,也比各搞一套强。这件事不值得让步,后期统一成本高到你怀疑人生。
第三个问题:数据要存多久。日志和指标数据的存储成本是大头。有些数据需要保留长期做趋势分析,有些数据只需要短期诊断。规划存储策略要趁早,不要等到磁盘爆了才去清理。具体做法,后面讲实操时我详细说。
想清楚这三个问题之后,再去看具体工具,思路就会清晰很多。接下来我把三大支柱的具体落地要点逐个拆开讲。
2. 可观测性建设的核心细节解析:三大数据支柱的落地要点
光知道“要有日志、指标、链路”是不够的,落地的时候有很多细节,这些细节直接决定了这套体系上线之后好不好用。我按三大支柱分别展开。
2.1 指标监控:别一上来就堆大盘,先把 RED 和 USE 定下来
我见过不少团队搭监控,上来就在 Grafana 里拉一堆面板,CPU、内存、磁盘、网络全放上去,看起来特别全,真出了问题却不知道看哪里。这就是典型的“有监控,无可观测性”。
正确做法是先确认要盯哪些指标。对于新业务的核心服务,我通常从 RED 和 USE 两个方法论出发。
RED 方法面向服务维度,关注三个指标:Rate(每秒请求数)、Errors(每秒错误请求数)、Duration(请求延迟分布)。这套指标主要回答“用户请求服务时体验怎么样”。USE 方法面向资源维度,关注 Utilization(利用率)、Saturation(饱和度)、Errors(错误数),主要回答“底层资源是否够用、是否快撑不住了”。
新业务刚上线时,我建议优先盯这么一套清单:
| 维度 | 指标 | 来源 | 作用 |
|---|---|---|---|
| 业务流量 | QPS、日活、订单量 | 业务埋点 | 判断业务是否正常运行 |
| 业务错误 | 下单失败率、支付失败率 | 业务埋点 | 捕捉业务异常 |
| 服务性能 | 接口 P50/P95/P99 延迟 | 中间件采集 | 发现性能劣化 |
| 服务错误 | 5xx 比例、4xx 比例 | 框架层采集 | 判断错误是否在合理范围 |
| 资源利用率 | CPU、内存、磁盘、网络 | 节点采集 | 发现资源瓶颈 |
| 依赖健康 | 下游服务 QPS、错误率、延迟 | 客户端采集 | 快速定位依赖问题 |
指标数据采集有几个参数直接影响数据质量。抓取间隔(scrape_interval)一般设 15 秒,太短会造成数据冗余,太长则在出问题时丢失细节。PromQL 里计算错误率时,推荐用 rate 函数而不直接用请求数相除,因为 rate 能平滑掉毛刺。计算 P99 这类分位数时,如果用的是 Histogram 类型,bucket 的划分需要根据业务实际延迟范围来设。比如大部分请求在 50ms 以内,那就把 10ms、25ms、50ms、100ms、250ms、500ms、1s 这几档设置好,否则算出来的分位数误差很大,连参考价值都没有。
这里有个很典型的坑:有人想统计 P99,直接把 bucket 设成 100ms、200ms、300ms……结果大部分请求落在 100ms 以内的 bucket,算出来的 P99 严重失真,看起来系统性能特别好,实际上 P99 已经飙到 800ms。排查半天,最后发现是 bucket 设置不合理。
2.2 日志系统:规范化日志字段比选型更重要
日志是排查问题的第一手材料。在实际操作中,我发现很多团队的日志系统用得很痛苦,问题不在工具本身,而在日志内容不规范。
常见的情况是:有的服务打的是纯文本,有的服务打的是 JSON,有的日志带 trace_id,有的不带,有的时间戳是本地时间,有的是 UTC 时间。等真出了问题,想把多个服务的日志按时间排序、关联分析,简直像拼拼图。所以日志规范一定要统一,字段一定要结构化。
我推荐日志统一使用 JSON 格式,并至少包含以下字段:
timestamp:ISO8601 格式,统一使用 UTC 时间,避免时区混乱level:INFO、WARN、ERRORservice:服务名,必须有且统一trace_id:链路追踪的请求标识,没有链路体系也要先留出这个字段message:日志内容user_id(可选):业务上下文,方便回溯单个用户的问题duration_ms(可选):耗时,方便做日志级别的性能分析
日志采集链路,我用得比较多的方案是 Filebeat + Kafka + Logstash + Elasticsearch。Filebeat 采集日志文件,发送到 Kafka 做缓冲削峰,Logstash 做字段解析和清洗,最终写入 Elasticsearch,然后通过 Kibana 检索。如果团队规模不大、日志量没到百万级每秒,也可以简化成 Filebeat + Elasticsearch,少一层 Kafka 和 Logstash 也能跑得很稳。
日志系统里一个容易被忽视的细节是多行日志的处理。异常堆栈通常跨多行,如果采集器不做合并处理,一条异常会被拆成很多条日志,检索分析时非常痛苦。Filebeat 有multiline配置,可以按时间戳或者关键词合并多行日志,这个一定要配好。
还有存储策略。Elasticsearch 的索引生命周期管理(ILM)建议从第一天就启用。按时间维度做索引切分,热数据保留 3 到 7 天,温数据保留 30 天,冷数据可以压缩后归档到对象存储。这样既能保证最近的日志查询速度快,又不会让磁盘无限膨胀。
2.3 链路追踪:用 trace_id 串起整个调用链
链路追踪的技术方案,我对比过 Jaeger 和 SkyWalking。Jaeger 是基于 OpenTelemetry 标准的,接入方式灵活,适合技术栈杂、需要定制化的团队。SkyWalking 自带 Java Agent,接入方便,对 Java 技术栈很友好,但跨语言支持相对弱一些。如果你的团队以 Java 为主,SkyWalking 上手快;如果服务是多种语言混编,Jaeger 更合适。
链路追踪最核心的一点是上下文传递。一个请求进来,生成 trace_id,然后在每个跨服务调用时,通过 HTTP Header、MQ 消息头、异步线程上下文一路传下去。任何一个环节漏传,链路就断在这,后面的服务会生成新的 trace_id,导致整条链路对不上。
实际项目里常见的问题有三个。第一,调用下游 HTTP 服务时,只传了业务参数,没传 trace_id 相关的 Header。第二,通过消息队列异步处理的场景,发送消息和消费消息时没有把 trace_id 放到消息头里,导致消费链路对不上。第三,异步线程池执行任务时,子线程里丢失了主线程的上下文,解决办法是用装饰器或者手动传参把 trace_id 带进去。
采样策略也要提前想好。全量采集数据量太大,对存储和性能都有压力。常见的做法是头部采样(Head-based Sampling),即请求进来时按比例决定这条链路是否采样,比如默认 10%。这样能控制总体数据量。但如果某条请求出错,你可能希望它必须被采样。这时候可以配合尾部采样(Tail-based Sampling),根据最终结果决定是否补充采样,不过实现比较复杂,新业务上线初期可以先不做。最简单的做法是固定采样率 10%,排查问题时如果某个 trace_id 没采到,再针对那个服务临时调高采样率。
链路追踪和日志的联动是个加分项。日志里带上 trace_id,检索日志时看到 trace_id,直接复制到链路追踪系统,就能看到这条请求的完整调用链。反过来,在链路追踪系统里发现某个 span 特别慢,也能用 trace_id 去检索对应的日志,看具体发生什么。两套系统打通之后,定位问题的效率会提升一倍不止。
3. 从零到一搭建新业务可观测性体系的实操全过程
理论说完了,来讲实操。这一节我按时间线走一遍完整流程,时间段以代码冻结前的倒数天数为参考,你们根据自己团队的节奏调整。
3.1 上线前第 T-7 天:梳理业务链路与关键指标
新业务上线前一周,我会把相关研发叫到一起,做一次链路梳理。目标是画清楚三张清单。
第一张是核心调用链清单。新业务对外暴露了哪些接口,每个接口经过哪些服务,依赖哪些下游(HTTP、RPC、数据库、缓存、消息队列)。不需要画得特别细,能理清核心链路的上下游关系就行。这张清单决定了后续链路追踪需要覆盖哪些服务。
第二张是关键指标清单。从业务价值角度出发,列出三到五个“如果这个指标异常,就说明业务出问题”的核心指标。比如电商业务是下单成功率、支付成功率、订单量;内容业务是首屏加载成功率、播放成功率、人均播放时长。这些指标需要业务埋点,建议在开发阶段就把埋点代码写进去。
第三张是 SLO 初稿。给核心指标定一个可量化的目标,比如下单成功率 99.9%、P99 延迟小于 300ms。SLO 不需要一开始定得很精细,但必须有,有一个粗糙的目标,比没有目标盲人摸象强得多。
梳理完之后,把这些内容同步给全组,作为可观测性验收的标准。到时候上线检查时,逐条对照看是否都做到了。
3.2 上线前第 T-3 天:部署可观测性基础设施
基础设施部署是相对标准化的过程。以自建方案为例,我按三大支柱分别说明部署要点。
指标监控这套,核心组件是 Prometheus + Grafana + Alertmanager。Prometheus 负责采集和存储指标,Grafana 负责可视化,Alertmanager 负责告警通知。实际部署时,Prometheus 用 Kubernetes 部署或者裸机部署都可以,重要的是确认它能够动态发现服务。Kubernetes 环境里用 Prometheus Operator 配合 ServiceMonitor 自动发现目标,比手动配置 Targets 省心很多。
本地快速验证时,可以用 docker-compose 起一套最小环境,检查组件之间是否连通。下面是一个最简配置参考:
version: "3" services: prometheus: image: prom/prometheus ports: - "9090:9090" volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml grafana: image: grafana/grafana ports: - "3000:3000" alertmanager: image: prom/alertmanager ports: - "9093:9093"global: scrape_interval: 15s alerting: alertmanagers: - static_configs: - targets: ["alertmanager:9093"] rule_files: - "/etc/prometheus/rules.yml" scrape_configs: - job_name: "demo-app" static_configs: - targets: ["demo-app:8080"]日志系统部署时,重点检查采集器配置。比如 Filebeat 需要确认日志路径、文件编码、多行合并规则。采集器部署完之后,把测试日志打进文件里,确认能正常进入 Elasticsearch,再去配 Kibana 的索引模式。
链路追踪系统部署相对简单。Jaeger 直接提供全链路部署,包括 Agent、Collector、Query、UI 几个组件。网关接入 Jaeger Agent 后,确认能够上报数据,然后在 UI 里能看到链路数据,就算通了。
基础设施部署的验证标准,我建议定成这样:从任何一个服务发起一次请求,指标里能看到 request 计数变化,日志里能看到对应日志落盘,链路追踪里能看到完整调用链。三个系统单独通了不算完,还要用同一个请求验证三套数据能对得上,大概率会在这里发现配置问题。
3.3 上线前第 T-1 天:埋点联调与仪表盘验收
上线前一天,做完整的联调和验收。这个环节其实是在回答一个问题:这套可观测性体系真正能用吗?
埋点联调的步骤是这样的。先让测试或者开发手动发一批真实请求,数量不用多,但要覆盖核心链路的所有接口。然后去 Prometheus 里查指标,确认每个接口的 QPS 都有数据。再随机挑一个请求的 trace_id,去日志系统里搜索,确认能搜到这条请求全链路的日志。最后去 Jaeger 里查看这个 trace_id 的完整调用链,确认每个 span 的耗时都是合理区间。
凡是能走完这一条链路,说明三大支柱的串联是通的。凡是中间断在哪,当场修,不要拖到上线后。
仪表盘验收的时候,重点不是看面板好不好看,而是看几个核心场景是否一打开就能回答关键问题。我会检查这些页面:服务总览页(QPS、错误率、P99)、依赖监控页(下游服务健康状态)、业务指标页(订单量、成功率)、资源监控页(CPU、内存)。每一个面板都要能回答“当前系统处在一个什么状态”这个问题,而不是一堆数字摆在那儿,还要人自己去分析。
告警规则测试也放在这一天。注意,这里说的“测试”不是看一眼配置就完事,而是要真正触发一条告警,验证通知能不能发出去、路由到正确的接收人。我见过太多团队,配置了告警规则,结果告警从来没响过,真出问题时才发现邮件服务器的配置早就失效了。这种事最好别等到线上环境去发现。
3.4 上线当天:灰度期间的可观测性运营
新业务上线当天,可观测性体系要进入“实战模式”。这个阶段我会重点做几件事。
灰度或金丝雀发布期间,核心关注三个指标:错误率是否正常、P99 延迟是否符合预期、业务量是否符合预期。这三个指标任何一个出现明显异常,都应该立刻触发人工介入。顺带说一句,灰度期间的告警静默策略要提前定好。新业务上线初始阶段,告警可能比较频繁,尤其是依赖尚未完全稳定的场景。给告警设一个上线窗口期的临时静默规则,比如上线后 2 小时内只接收 P0 和 P1 级别的告警,避免告警轰炸导致团队麻木。
另一个建议是做好新旧服务的数据对比。如果这次上线是替换老服务,需要在监控面板上同时展示新老两个服务的核心指标,方便现场对比。如果这次上线是全新业务,没有历史数据可对比,那就重点观察指标的绝对值是否偏离预期,以及随时间变化的趋势是否正常。
上线当天结束后,我还会让值班的同事把当天看到的指标截图、告警记录、定位过程整理成一份简报,作为新业务的初始基线数据。这份基线后续用处的确很大,后面版本迭代做性能对比、容量规划,都靠它。
4. 上线后常见问题与排查技巧实录
上线之后,可观测性体系会陆续暴露一些问题。我整理了一份高频问题速查表,都是我在项目里实际踩过的坑。
| 问题现象 | 可能原因 | 排查思路 |
|---|---|---|
| 日志查询不到某条请求 | trace_id 未写入日志 | 检查日志字段,确认日志框架里打印了 trace_id |
| 链路追踪断在某处 | 上下文传递丢失 | 检查 HTTP Header、MQ 消息头、线程池上下文传递 |
| 告警风暴 | 规则阈值设置不合理 | 调整告警规则,增加持续时间条件,合并告警通知 |
| 指标出现尖刺 | 采集间隔、聚合函数问题 | 看原始数据,区分是真实流量波动还是采集问题 |
| P99 很高但平均延迟正常 | 存在少数慢请求,bucket 设置不合理 | 检查 histogram bucket 划分,增加慢请求尾部分析 |
| 容器环境下指标互相干扰 | 采集了错误的 targets | 检查 Prometheus 标签,确认 service 隔离 |
这里挑几个典型问题,讲一讲我的排查思路。
日志丢了,从哪里查起?先看 Filebeat 采集日志的进度。Filebeat 有registry文件记录每个日志文件的采集位置,如果这个文件的位点前进缓慢,说明读取有问题,可能是权限不足或者文件被文件切分。再看 Kafka 消费组的 lag,如果 Logstash 消费不过来了,说明下游处理能力不足。层层往下查,总能找到断点。值得注意的是,不要一上来就怀疑架构,很多时候是采集配置的小毛病,比如日志文件路径写错了,或者文件被 logrotate 切走后采集器没有正确处理。
链路追踪数据串了,怎么定位?先直接看链路的 trace_id 是否一致。如果同一个请求在不同服务里 trace_id 不一样,说明上下文传递断了。排查 HTTP 场景时,重点检查是否统一设置了traceparent或x-trace-idHeader;排查 MQ 场景时,检查消息头是否透传了 trace_id;排查线程池场景时,检查是否用ThreadLocal的包装类做了上下文拷贝。这个问题在异步化程度高的业务里特别常见,团队在做代码评审时就要留意。
PromQL 里怎么抓 P99?用 histogram_quantile 函数。假设指标名是http_request_duration_seconds,那么计算 P99 的 PromQL 语句如下:
histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))这里的le标签是 histogram bucket 的上限,Prometheus 内部会按 bucket 分布插值计算分位数。如果你发现 P99 的数值很怪,比如长时间不变、或者明显不合理,大概率是 bucket 设置不合理。把 bucket 的分布区间和业务实际的延迟分布对上号,这个数值才有参考价值。
告警风暴怎么治理?告警风暴的本质是告警太灵敏,规则设计有问题。我推荐从几个方向调整。第一,给告警规则加“持续时间”,比如持续 5 分钟才触发,避免瞬时抖动误报。第二,使用 Alertmanager 的 group_wait 和 group_interval 做告警分组聚合,把同类告警合并成一条通知。第三,设置 inhibition 规则,比如某个服务整体不可用,就不需要同时发出它的子服务告警,后者只会造成噪音。告警治理是持续优化的过程,上线后每月应该回顾一次告警规则,把从未触发的规则删掉,把频繁误报的规则改严,让告警真正有参考价值。
5. 新业务可观测性的一些额外经验和补充
前面讲的都是三大支柱和流程,最后再补充几点偏实战的体会,可能对你们团队落地更有帮助。
5.1 业务指标与技术指标要配合使用
很多团队的可观测性体系建设到技术指标就停了,觉得 QPS、P99、CPU 都监控了,就万事大吉。但技术指标正常,不代表业务没问题。我经历过一次线上事故,技术指标都非常正常,QPS 稳定,错误率几乎为零,P99 也低于目标线,但业务侧反馈“下单一直失败”。最后排查下来是业务逻辑层的一个规则配置错误,所有下单请求都走了异常分支,但异常被框架吞掉了,没有产生技术错误指标。
这个教训让我明白,业务指标在可观测性体系里的地位完全不亚于技术指标。每个新业务上线时,至少要有三到五个核心业务指标进监控,比如支付成功率、下单量、活跃用户数。这些指标在 Grafana 里单独做一栏,和技术指标并列展示。它们和技术指标配合使用,才能做到完整覆盖:技术层面出问题,技术指标能发现;业务逻辑层面出问题,业务指标能兜底。
像 Alibaba 的 Sentinel 这类流量治理框架通常也内置了业务埋点能力,可以配合使用,但更通用的做法还是在业务代码里主动埋点。
5.2 数据成本与性能损耗,要心里有数
可观测性做多了,数据成本会成为一个不容忽视的问题。日志如果全量采集、全量存储、长期不清理,Elasticsearch 的磁盘消耗速度快过你想象。指标数据如果全量上报、全量保留,Prometheus 的存储也会吃紧。
实操中的做法是分层管理。日志按级别和重要性分层,DEBUG 日志只在本地开发环境输出,线上只保留 INFO 及以上级别;链路追踪按采样率控制总量,默认 10%,出问题时再对目标服务临时调高;指标数据按用途保留,高频实时指标保留 15 天,低频趋势指标可以聚合后压缩长期存。定期用curl查一下 Elasticsearch 的索引状态和 Prometheus 的 TSDB 使用量,做到心里有数,别等磁盘告警响了才做清理。
还要注意采集 Agent 对业务服务的性能损耗。Filebeat 和 Jaeger Agent 的 CPU 占用通常在 1% 到 3% 之间,基本可忽略,但遇到高并发日志量极大的服务,Filebeat 也有可能成为瓶颈。上线前后最好做一次简单的压测,观察采集 Agent 对业务服务的性能影响,超过 5% 就要优化配置了。
5.3 再分享一个我个人的经验
最后讲一个我印象很深的小事。有一次新业务上线后十五分钟,运营反馈某个新上线的页面打不开。当时我打开 Grafana,看到该服务的 QPS 从 200 掉到了 20,错误率上升了不少。点进某个 trace_id,发现慢的 span 集中在一个下游搜索服务上。再去日志系统里搜这个 trace_id 对应的日志,看到一堆连接池超时的异常堆栈。整个定位过程不到三分钟,后面修复就很快。
要知道,这要是放在没有可观测性体系的年代,十五分钟的页面故障,至少需要几个人一起翻日志,翻一两个小时都不一定能理出头绪。一套完整可观测性体系,在新业务上线时带来的价值几乎是立竿见影的。它能做到让团队快速感知线上风险,让问题的定位时间从小时级压缩到分钟级。
这些经验总结起来就是一句话:可观测性不是工具堆叠,而是一种贯穿研发流程的方法论。工具选得再好,如果不同步到流程规范里,最后还是会变成摆设。希望这篇文章能帮你们团队少走一些弯路,新业务上线时心里更有底气。