系统慢成狗,开发甩锅网络?手把手教你搭建SkyWalking全链路监控,让性能瓶颈无处遁形!
前两天凌晨三点,手机又是这熟悉的夺命连环call。
爬起来一看,业务群里炸锅了。客服在吼:“用户登录不上去!一直在转圈!” 开发在喊:“我看日志了,没报错啊,服务都活着,CPU 也是绿的,是不是网络抖动了?运维查查交换机?”
那一刻,我手里的保温杯差点没捏碎。网络抖动?每次系统慢查不出原因就赖网络,网络招谁惹谁了?
这种场景,咱干运维的兄弟应该太熟悉了。特别是在现在微服务架构满天飞的年代,一个请求进来,可能要经过网关、A服务、B服务、缓存、数据库、消息队列……中间任何一个环节卡顿,整个请求就崩了。
传统的监控,Zabbix 看看 CPU 内存,ELK 搜搜日志,这时候基本就在抓瞎。因为你不知道这一笔请求,到底死在了哪一步。
这时候,你就需要一把“上帝之眼”,也就是我们要聊的主角——APM(Application Performance Management,应用性能管理)。
今天咱们不整那些虚头巴脑的概念,我就带大家从头捋一遍,APM 到底是啥,市面上有哪些能打的开源工具,最后我会手把手教大家搭建一套目前最火的 Apache SkyWalking,让你下次再遇到“系统慢”,直接把证据甩开发脸上:看清楚了,是你这条 SQL 跑了 5 秒,别特么赖网络!
APM 到底是干啥的?
说白了,APM 就是给你的应用程序做“核磁共振”。
以前单体应用时代,代码都在一个包里,哪慢查哪。现在微服务拆得七零八落,服务之间调用关系像一团乱麻。
APM 核心就干三件事:
- 链路追踪(Tracing): 就像给每个请求打个“电子标签”(Trace ID)。这个请求从网关进来,经过了哪些服务,调了哪些数据库,每一步花了多少毫秒,全给你记录下来,画成一张瀑布图。
- 指标监控(Metrics): 服务吞吐量(CPM)、响应时间(P99/P95)、错误率。这些是宏观数据,告诉你系统健不健康。
- 日志关联(Logging): 光知道慢不行,还得知道当时报了啥错。好的 APM 能通过 Trace ID 把上下文日志串起来。
这就好比送快递。没有 APM,你只知道快递发了,最后没收到。有了 APM,你能看到快递几点几分在哪个转运中心,是不是卡在某个仓库(数据库)里出不来了。
开源界的神仙打架:选谁?
市面上开源的 APM 工具其实不少,早些年我也折腾过好几个。
Zipkin:
这算是鼻祖了,Twitter 开源的。早几年用的挺多,Spring Cloud 早期官方推荐。但说实话,现在看有点简陋了,界面比较原始,功能也比较单一,基本只能做简单的链路追踪,对代码侵入性虽然不大,但维护起来有点没劲。
Pinpoint:
韩国人搞的,基于 Java Agent,如果你全是 Java 技术栈,这玩意儿其实挺强。它的调用链路图画得特别漂亮,粒度非常细。但它有个致命缺点:存储依赖 HBase。兄弟们,维护过 HBase 的都知道,那就是个爹。加上它数据量一大,对服务性能影响比较明显,我们就遇到过装了 Pinpoint 导致服务吞吐量下降 10% 的情况。
Jaeger:
CNCF 旗下的,Go 语言写的,云原生亲儿子。如果你是全套 K8s + Istio,用它很顺手。但它的 UI 还是偏极客风,很多运维想要的报表功能它默认没有,得二次开发。
Apache SkyWalking:
这是今天要推的主角。国产之光(吴晟大佬主导),现在已经是 Apache 顶级项目。
为啥选它?理由很简单:
- 无侵入:Java 应用启动加个参数就行,一行代码不用改。
- 多语言:Java, .NET, Node.js, Go, Python 都支持。
- 后端灵活:默认用 Elasticsearch 存数据,这玩意儿咱运维都熟,不用去啃 HBase。
- 界面炫酷且实用:拓扑图、各种热力图、慢 SQL 排名,老板和开发都爱看。
- 社区活跃:文档中文友好,出了 bug 哪怕去 GitHub 提 issue,回复都很快。
所以,这几年我也就基本锁死 SkyWalking 了。
实战:搭建 SkyWalking 全链路监控
光说不练假把式。下面咱们找台机器,实际跑起来。
假设你手头有一台 Linux 服务器(CentOS/Ubuntu 都行),装好了 Docker 和 Docker Compose。如果你还在用源码编译安装,那我建议你赶紧弃暗投明,Docker 部署这东西太香了,版本管理方便,还不污染宿主机环境。
我们这次部署的是 SkyWalking OAP(后端服务) + UI(前端界面),存储使用 Elasticsearch 7.x。
1. 准备 docker-compose.yml
找个目录,比如 /opt/skywalking,建个 docker-compose.yml 文件。
注意啊,这里有个坑。SkyWalking 的版本和 Elasticsearch 的版本是有对应关系的。别瞎配,容易报错。我这里用的是 SkyWalking 9.x 版本,配合 ES 7.10,非常稳。
version: '3.8'
services:
# 1. 存储层:Elasticsearch
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:7.10.2
container_name: elasticsearch
restart: always
ports:
- 9200:9200
environment:
- discovery.type=single-node
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- ./es_data:/usr/share/elasticsearch/data
# 2. 初始化脚本:负责在ES里建表
oap-init:
image: apache/skywalking-oap-server:9.4.0
container_name: oap-init
restart: on-failure
entrypoint: /bin/sh
command: >
-c "/skywalking/bin/oapServiceInit.sh && exit 0"
depends_on:
- elasticsearch
environment:
SW_STORAGE: elasticsearch
SW_STORAGE_ES_CLUSTER_NODES: elasticsearch:9200
# 3. 核心后端:OAP Server
oap:
image: apache/skywalking-oap-server:9.4.0
container_name: oap
restart: always
ports:
- 11800:11800 # gRPC端口,Agent发数据用这个
- 12800:12800 # HTTP端口,UI查数据用这个
depends_on:
oap-init:
condition: service_completed_successfully
environment:
SW_STORAGE: elasticsearch
SW_STORAGE_ES_CLUSTER_NODES: elasticsearch:9200
TZ: Asia/Shanghai
# 4. 前端界面:SkyWalking UI
ui:
image: apache/skywalking-ui:9.4.0
container_name: skywalking-ui
restart: always
ports:
- 8080:8080
depends_on:
- oap
environment:
SW_OAP_ADDRESS: http://oap:12800
TZ: Asia/Shanghai这里多嘴一句,oap-init 这个 service 是 9.x 之后推荐的做法,专门用来初始化 ES 索引的,跑完就退出了。以前是 OAP 自己启动时检查,但容器化环境下有时候会有时序问题,独立出来更稳。
2. 启动服务
在目录下执行:
docker-compose up -d这时候你可以去冲杯咖啡。回来后,用 docker-compose logs -f 看看日志,如果没看到 Exception,Elasticsearch 也没报错,那就稳了。
打开浏览器,访问 http://服务器IP:8080。
如果你看到了那个蓝色的、充满科技感的登录界面(默认没有密码),恭喜你,地基打好了。现在里面是空的,因为还没接入应用。
3. 接入 Java 应用(Agent 埋点)
这是最关键的一步。
SkyWalking 的强大之处在于 Java Agent。它像一个寄生虫(褒义的),附着在你的 Java 进程上,拦截方法的调用,把数据发给刚才搭建的 OAP Server。
我们需要下载 skywalking-java-agent。去官网下载页面,找 "Java Agent" 的包,下载解压。你会得到一个 skywalking-agent 目录。
这个目录里有个 skywalking-agent.jar,这就是核心。还有一个 config/agent.config,是配置文件。
通常为了省事,我都不改配置文件,直接通过启动命令行的参数来覆盖配置。
假设你的应用叫 user-service,以前的启动命令是:
java -jar user-service.jar现在,你要改成这样:
java -javaagent:/path/to/skywalking-agent.jar \
-Dskywalking.agent.service_name=user-service \
-Dskywalking.collector.backend_service=服务器IP:11800 \
-jar user-service.jar看懂了吗?就加了三行东西:
-javaagent:指定探针 jar 包的位置。service_name:给你这个服务起个名,这名字以后会在 UI 上显示。backend_service:指定数据发到哪去,就是刚才 docker 部署的那个 OAP 的 11800 端口。
这里有个大坑要注意!
如果你是在 K8s 或者 Docker 容器里跑应用,记得把这个 agent 目录打进你的镜像里,或者通过 Volume 挂载进去。而且 backend_service 的地址一定要保证容器内部能访问通。
我建议先拿个测试环境的服务试刀。重启应用,观察启动日志,如果没有报错,并且应用正常运行,这时候再去 SkyWalking UI 上刷新一下。
见证奇迹的时刻到了。
如何用它揪出性能瓶颈?
一旦数据进来了,你会看到 Dashboard 上的数字开始跳动。咱们来看看怎么用这玩意儿来“打脸”。
1. 拓扑图:上帝视角
点开【Topology】菜单。你会看到一张网状图。
如果你的系统是微服务架构,这里会非常壮观。你会看到 User 服务调了 Order 服务,Order 服务调了 Redis 和 MySQL。
这时候,如果某条连线变成了红色,不用想,那条链路出问题了。可能是报错多,也可能是响应太慢。鼠标放上去,直接显示平均耗时。以前开发老问“是不是数据库挂了?”,现在你指着屏幕说:“看,数据库这儿是绿的,但是你调第三方支付接口这根线是红的,耗时 5 秒,是你代码逻辑在等回调,懂?”
2. 链路追踪:显微镜分析
这是最实用的功能。点开【Trace】菜单。
如果你接到了用户投诉,说“刚刚点了一次保存,卡了半天”。
如果用户能提供报错时间,或者你有日志里的 TraceID,直接搜。如果没有,就在右边的时间轴上找那个耗时特别长的请求。
点开那个长条,你会看到一个瀑布流。
这个瀑布流详细到了什么程度?
它会显示:
- Spring Controller 接收请求(0ms)
- Service 业务逻辑处理(5ms)
- JDBC Execute Statement(2000ms)
- Return(2ms)
看到那个 2000ms 的红条了吗?点开它。
SkyWalking 会直接把当时执行的那条 SQL 语句展示给你看! 甚至连参数都能通过配置开启显示。
这时候你就可以截图发群里了:“来来来,谁写的这条 SQL?全表扫描,没走索引,跑了 2 秒。赶紧优化去,别在这怀疑服务器 CPU 负载高了。”
这就叫有理有据,令人信服。
3. 性能剖析(Profile):代码级的深究
有时候,不是 SQL 慢,是代码逻辑慢。比如写了个死循环,或者正则匹配效率太低。这时候瀑布图只显示“Service 方法耗时 2 秒”,但不知道哪行代码慢。
SkyWalking 有个高级功能叫【Profile】。
你可以新建一个任务,指定监控某个 Endpoint(接口)。当这个接口再被调用时,它会把线程栈抓下来。
分析结果会精确地告诉你:com.company.service.OrderService.calculatePrice() 这个方法里的第 45 行,消耗了 CPU 500ms。
这简直就是远程 Debug 神器,开发看了都得给你递烟。
生产环境落地的几个“坑”
虽然 SkyWalking 很爽,但在生产环境大规模铺开,我有几条血泪经验得嘱咐你:
1. 采样率设置
默认情况下,Agent 可能会采集所有请求。如果你的业务量是几万 QPS,全量采集会把你的 ES 存爆,带宽也会吃紧。
在 agent.config 里有个配置 agent.sample_n_per_3_secs。意思是每 3 秒采集多少条。或者配置采样率比例。
通常生产环境,我们需要的是趋势和异常,不需要每一条都留底。建议开启采样,只留个 10%-20%,或者配置成只采集慢请求和错误请求。
2. 数据清理(TTL)
ES 里的数据是海量的。OAP 有个配置叫 recordDataTTL 和 metricsDataTTL。
Trace 数据(那张瀑布图)最占空间,一般保留 3-7 天就够了,没人会去查上个月的慢请求。Metrics 指标数据可以留长点,比如 30 天,用来做月度报表。
别贪多,否则你的磁盘报警会让你夜不能寐。
3. 忽略心跳接口
很多服务都有 /health 或者 Eureka/Nacos 的心跳包,一秒钟好几次。这些数据毫无价值,还会弄脏拓扑图。
记得在 agent 配置里把这些路径加入 trace.ignore_path,眼不见心不烦。
4. 报警规则
SkyWalking 自带报警功能(Alarm)。你可以配置规则,比如“过去 3 分钟内,某个服务的平均响应时间超过 500ms”。它支持 Webhook。
我一般的做法是写个简单的中间件,接收这个 Webhook,然后转成钉钉或飞书消息发到运维群里。这样一旦有慢服务,我们比用户先知道。
总结
运维这行,做到最后其实就是比谁手里的工具更锋利。
以前我们是“背锅侠”,系统一慢就是我们的锅。有了 APM,我们变成了“裁判员”。
SkyWalking 不仅仅是一个监控工具,它打通了开发和运维之间的那堵墙。当大家都看着同一张拓扑图,看着同一个 Trace 详情时,沟通成本会直线下降。
搭建这一套东西,快的话半小时,慢的话半天,但它能为你节省的排查时间,可能是以后几年的无数个通宵。
这波干货如果不收藏,下次系统崩了可别怪我没提醒你啊。
兄弟们,如果你在搭建过程中遇到啥奇怪的报错,或者对 ES 的调优拿不准,欢迎在评论区留言。咱们一起探讨,绝不藏私。
最后,码字不易,全是实战里摸爬滚打出来的经验。觉得有用的话,点个关注,转发给身边的运维兄弟和开发同事(特别是那个爱甩锅的)。
公众号:运维躬行录
个人博客:躬行笔记