前言:优化之后,我们成了“盲人”

大家好,很高兴能继续这个系列。

经过前三轮的“浴血奮戰”,我们的系统在性能上确实脱胎换骨了。但我们很快发现自己陷入了一个新的窘境:我们对系统的掌控力变弱了

在单体应用时代,排查问题很简单:tail -f a.log,所有线索都在一个文件里。而现在,一个“下单失败”的反馈,其请求链路可能跨越了订单服务、库存服务、用户服务、风控服务……日志分散在四五台服务器上,时间戳还可能因为时钟不同步而有偏差。

当测试同学跑来问我:“这个接口为什么超时了?”

我无法像以前那样自信地回答,只能弱弱地说:“我……得挨个服务查查日志。”

这种感觉,就像一个医生给病人做完了大手术,病人身体指标很好,但医生却失去了听诊器和CT机,无法再洞悉病人体内的真实情况。我们意识到,性能优化之后,构建一套强大的“医疗诊断”体系——也就是可观测性平台,迫在眉-睫

痛点一:断裂的调用链,消失的“第一现场”

最典型的痛点就是排查一个慢请求。用户反馈某个API响应需要5秒,按照链路 A -> B -> C,我们分别查看三个服务的日志:

  • 服务A日志:显示处理耗时20ms。

  • 服务B日志:显示处理耗时30ms。

  • 服务C日志:显示处理耗时50ms。

加起来总共才100ms!那剩下的4.9秒去哪了?是服务A到B的网络延迟?还是B到C的RPC框架出了问题?传统的日志完全无法回答这个问题。我们需要一个能将整条调用链串起来的“上帝视角”。

解决方案:为请求装上GPS——分布式链路追踪 (SkyWalking)

为了解决这个问题,我们引入了分布式链路追踪系统。其核心原理很简单:
当一个请求进入系统时,我们为它生成一个全局唯一的 TraceID。这个 TraceID 会随着请求的传递,在所有经过的服务间透传(通常放在HTTP Header或RPC的上下文中)。每个服务在处理自己的那部分逻辑时,会生成一个 SpanID,并记录下开始和结束时间。

最终,将同一个 TraceID 下的所有 Span 收集起来,按照父子关系和时间顺序排列,就能清晰地还原出完整的调用链路图。

我们选择了 Apache SkyWalking 作为实现工具。选择它的理由很简单:

  1. 无侵入性:通过Java Agent技术,对应用代码几乎零侵入,只需要在启动脚本里加一个JVM参数。

  2. 功能强大:社区活跃,支持丰富的中间件(如Dubbo, gRPC, Spring Cloud等),UI界面直观。

  3. 生态完善:集成了追踪、指标和日志,是一个全面的APM(应用性能管理)系统。

实施过程:
部署SkyWalking的OAP(Observability Analysis Platform)和UI非常简单,这里不赘述。关键是在我们的微服务启动脚本中加入:

code Bash

    java -javaagent:/path/to/skywalking-agent/skywalking-agent.jar \
     -Dskywalking.agent.service_name=your-service-name \
     -Dskywalking.collector.backend_service=oap-server:11800 \
     -jar your-app.jar
  

效果:
上线后,我们再次面对那个5秒的慢请求,SkyWalking的UI界面给了我们答案。我们可以清晰地看到一条瀑布流,展示了请求从入口网关,到订单服务,再到库存服务的完整过程。每个环节的耗时都被精确地记录下来。

我们很快就从图上一目了然地发现,服务B在调用服务C之后,自身进行了一个长达4.8秒的内部处理,其中一次SELECT * FROM huge_table的数据库调用耗时4.7秒!“真凶”瞬间就被揪了出来。

痛点二:沉默的“亚健康”,爆发的“大危机”

链路追踪解决了“点”上的问题,但我们还需要“面”上的监控。系统有时候并没有明显的错误,但就是感觉“不太对劲”。比如:

  • 为什么下午三点应用的CPU使用率会周期性飙升?

  • 某个服务的JVM老年代内存是不是在缓慢增长,有内存泄漏的风险?

  • 数据库连接池的活跃连接数是不是快要被打满了?

这些问题,链路追踪无法回答,它们是系统层面的“健康指标”。

解决方案:打造系统健康仪表盘——指标监控 (Prometheus + Grafana)

我们引入了业界监控的“黄金搭档”:Prometheus + Grafana

  • Prometheus:一个开源的时间序列数据库,负责定期从我们的应用中“拉取”(pull)指标数据并存储。

  • Grafana:一个开源的可视化平台,负责将Prometheus中枯燥的数据,以酷炫、直观的图表展示出来。

实施过程:
我们在应用中引入了micrometer库和prometheus-client,通过/actuator/prometheus端点暴露应用的各项指标,包括但不限于:

  • JVM指标:堆内存、GC次数与耗时、线程数等。

  • Tomcat线程池指标:活跃线程、排队任务数等。

  • 数据库连接池(HikariCP)指标:活跃连接、空闲连接、等待连接数等。

效果:
我们在Grafana中为每个核心服务都定制了一个Dashboard,上面布满了各种实时跳动的曲线图和仪表盘。

通过这个仪表盘,我们很快就发现了之前那个CPU飙升问题的根源:原来是后台一个定时任务,在下午三点会执行一个非常消耗CPU的报表计算。而在另一个服务的JVM内存监控曲线上,我们也发现老年代内存(Old Gen)呈现出“只涨不跌”的锯齿状,成功预警了一次潜在的内存泄漏。

总结:从“救火”到“防火”的进化

搭建可观测性平台的过程,是我们将团队从被动的“救火队员”,转变为主动的“健康管理员”的过程。

  • SkyWalking 给了我们深入到每一次请求内部的“显微镜”。

  • Prometheus + Grafana 给了我们俯瞰整个系统健康状况的“作战指挥室”。

当这两者结合,我们便拥有了快速发现、定位、解决问题的闭环能力。在微服务的世界里,这种能力不是“锦上添花”,而是“安身立命”的根本。希望这次的分享,能为大家在微服务实践的道路上,提供一些有价值的参考。

更多推荐