ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

SkyWalking实战:从零搭建微服务分布式链路追踪与性能排障

SkyWalking实战:从零搭建微服务分布式链路追踪与性能排障 半夜十二点线上告警群里有人甩了一句“下单很慢”我打开各服务的监控面板挨个看CPU正常、内存正常、单接口平均耗时也不离谱。可用户就是在转圈而且是偶发性的十次里有两三次明显卡顿。这类问题最磨人因为任何一项孤立指标都看不出毛病而真正的瓶颈藏在一条横跨五六个微服务的调用链路上——订单服务调库存、库存调商品、商品又去调促销任何一个环节慢上两秒整条链路就会被无限放大。后来我用Apache SkyWalking把整条链路的数据拉出来问题才现出原形订单服务调用库存服务时连接池等待了整整八秒而库存服务自身CPU几乎闲置。这种“跳一跳才能看见”的问题就是分布式链路追踪存在的意义。这篇文章是我从零开始把SkyWalking接进生产环境、又持续调了大半年的实战总结不是官方文档的复述。内容覆盖SkyWalking的核心架构、Java服务接入步骤、采样与告警等生产级配置以及我实际踩过的坑。适合正在做微服务可观测性建设、或者被线上疑难问题折磨到想给每个请求装个摄像头的开发者参考。1. 分布式链路追踪到底在解决什么问题1.1 传统监控的死角指标正常体验却很差在做链路追踪之前很多团队的可观测性基建长这样Prometheus采集CPU、内存、QPS、RT这些指标ELK收集日志再配一堆阈值告警。这套组合拳在单体应用时代够用但进入微服务之后出现了一个非常尴尬的场景——每个服务单独看都是健康的但用户的整体请求就是慢。原因很好理解。一个请求从入口到最终返回要经过Gateway、认证服务、业务服务、缓存、数据库等七八个节点。期间任何一环抖动哪怕只有几百毫秒汇总到用户端就是几秒的延迟。而指标监控只能告诉你“哪个服务平均耗时高了”很难告诉你“这一次请求具体走了哪条路径、卡在哪个环节、耗了多少时间”。我之前遇到过一个经典案例A服务调用B服务经常超时但B服务的平均响应时间完全正常。后来查了半天才发现B服务只有少数几个接口慢而其内部又调用了C和D两个外部依赖。日志里能看到的只有B服务记录的超时异常却看不到完整的调用路径。没有链路数据这类跨服务问题排查起来基本靠猜。链路追踪的核心价值正是把一次请求的完整路径串起来记录每个环节的耗时、状态、调用关系并以拓扑图和Trace视图的形式呈现。遇到“整体慢但局部正常”的问题时直接顺着链路看哪个Span耗时异常问题定位效率完全不是一个量级。1.2 Trace、Segment、Span先啃下这三个核心概念用SkyWalking之前我建议先把三个基础概念吃透不然后面看Trace视图会一头雾水。Trace追踪一条完整的调用链从用户请求进入系统到最终响应的全过程。一个Trace对应一次业务请求全局唯一Trace ID贯穿整条调用链日志系统里关联这个ID就能把一次请求涉及的所有日志捞出来。Segment片段一次请求在某个服务进程内的完整处理过程一个Trace由多个Segment组成。比如A服务调B服务再调C服务A、B、C各自产生一个Segment。Span跨度Segment内部的最小单位代表一次具体的操作比如一个HTTP调用、一次数据库查询、一个方法执行。Span之间通过父子关系形成树状结构直观展示调用层次。用生活化的例子类比Trace是你从家到公司的一次通勤全程Segment是你走过的每一段路家门口到地铁站、地铁上、地铁站到公司Span则是每一步动作刷卡进站、等车、上车。SkyWalking的UI界面里Trace视图展示的是整条链路的瀑布流时间线每个Span的耗时、开始时间、标签信息都清晰可见。初次上手时建议先在测试环境造一个跨服务调用的请求然后点开Trace视图逐层看比对着文档啃概念入门快得多。2. SkyWalking核心架构拆解为什么选它2.1 Agent、OAP、UI三件套各司其职SkyWalking的整体架构用一句话概括Agent负责采集数据OAP负责处理数据UI负责展示数据存储层则作为OAP的底层依赖承接数据落地。**Agent探针**是部署在业务服务里的轻量级组件目前最常用的是Java Agent。它基于Java的字节码增强技术在应用启动时通过-javaagent参数挂载不需要修改任何业务代码就能自动拦截HTTP请求、数据库操作、RPC调用等行为并采集对应的Span数据。这是SkyWalking最大的卖点之一——零侵入接入。我之前评估过埋点SDK方案业务代码里需要手动埋点的地方太多改造周期按周算而SkyWalking的Java Agent接入按小时算。**OAPObservability Analysis Platform可观测性分析平台**是核心处理引擎负责接收Agent上报的数据完成链路数据聚合、指标计算、告警判断等逻辑然后写入存储。Agent与OAP之间通过gRPC协议通信默认端口是11800同时OAP还开放了12800端口用于HTTP通信。UI是SkyWalking的可视化控制台提供仪表盘、拓扑图、Trace查询、告警管理等功能。从UI上你能直观看到服务间的调用关系、服务健康状态、链路耗时分布这也是日常排查问题的主战场。部署层面OAP和UI都是Java进程官方提供了源码包和Docker镜像两种方式。单机测试环境可以一台机器跑完所有组件生产环境则建议OAP集群部署、独立存储避免单点故障。2.2 同赛道对比SkyWalking、Zipkin、Jaeger怎么选社区里经常有“链路追踪方案选型”的讨论我在选型阶段对比过Zipkin和Jaeger最终还是选了SkyWalking理由如下对比维度SkyWalkingZipkinJaeger接入方式Java Agent字节码增强零代码侵入Brave SDK侵入式埋点为主主流语言SDK侵入式埋点语言生态Java、.NET、Node.js、PHP、Python、Go等Java为主Go、Java、Python等功能维度链路追踪指标监控Topology拓扑告警链路追踪为主链路追踪指标监控告警能力内置告警规则支持Webhook等弱需配合其他系统支持基本告警配置二次开发成本插件体系完善社区活跃相对单薄更注重云原生场景单看链路追踪本身三者都能干但SkyWalking把“链路指标拓扑”整合在一个平台里对中小团队尤其友好。我见过很多团队用Zipkin做链路Prometheus做指标Grafana做展示告警再单独接一套每个系统独立维护光是告警事件的关联就够喝一壶。SkyWalking一个平台全搞定虽然单点深度不一定比专用系统强但整体使用成本低不少。更关键的是SkyWalking的插件机制覆盖面极广。Spring Cloud、Dubbo、gRPC、MySQL、Redis、Kafka、MQ等主流中间件全都有现成插件意味着接入后无需人工埋点就能拿到绝大多数调用链数据。这一点在“老系统改造”场景特别吃香。2.3 存储选型H2、MySQL、Elasticsearch还是BanyanDBSkyWalking的存储层默认使用H2内存数据库开箱即用但只适合本地开发环境一重启数据就没了。生产环境必须换掉我在不同项目里用过Elasticsearch和MySQL两种方案。Elasticsearch是SkyWalking历史上最主流的存储方案适合海量链路数据场景。按天创建索引的机制让TTL管理很方便但运维成本不低——集群的堆内存、分片数、索引生命周期都要维护。如果你本就有ES集群直接复用最省事。MySQL适合数据量不大日链路数据千万级以下且不想额外维护ES的团队配置简单但链路数据量上来后写入容易成为瓶颈查询Trace详情时也明显偏慢。8.0版本之后SkyWalking推出了自研的BanyanDB存储引擎专为可观测性数据设计官方推荐新项目优先考虑。测试环境下同量级数据BanyanDB的查询响应比ES快不少。但考虑到它相对年轻我建议生产环境先在测试环境充分验证后再启用。我的选型建议是日链路量低于千万级的项目直接用MySQL过渡数据量大再平滑切到ES或BanyanDB如果公司已有成熟的ES集群直接复用ES省去额外存储组件的运维负担。3. 接入实操让Java服务产生第一条链路数据3.1 环境准备与版本确认开始之前先把版本搞清楚。SkyWalking主要拆成两个组件版本OAP/UI服务端版本和Java Agent版本。一个经常踩的坑是Agent和服务端版本跨度太大导致上报数据协议不兼容UI上看不到数据或报错。我的经验法则是Agent版本尽量与服务端大版本保持一致比如服务端用的9.xAgent也选9.x的最新版。下载地址直接去Apache SkyWalking官网的Downloads页面需要获取三个东西apache-skywalking-apm-xxx.tar.gz内含OAP和UI、skywalking-agent-xxx.tar.gzJava Agent包。这里提醒一句Agent包里有skywalking-agent.jar和一个plugins目录plugins目录里是各种中间件的拦截插件正常情况下不需要手动动它。我本地的测试环境配置如下供参考组件版本说明JDK11业务服务与Agent均要求SkyWalking9.7.0OAP UI 单机部署Java Agent9.7.0与OAP同版本Elasticsearch7.17生产存储方案业务服务Spring Boot 2.7两个服务模拟调用链3.2 部署OAP Server与UI解压服务端包后进入config目录核心配置文件是application.yml。单机快速验证时OAP默认使用H2存储几乎不需要改任何配置就能启动。启动OAPcd apache-skywalking-apm-bin/bin ./oapServer.sh启动成功后再启动UI./webappService.shUI默认端口是8080浏览器访问http://localhost:8080应该能看到SkyWalking的登录页9.x默认账号密码是admin/admin初次部署后建议立刻改掉。需要注意如果本机8080端口已被其他服务占用可以修改webapp/application.yml里的server.port。生产环境部署前一定要修改application.yml里的存储配置。用Elasticsearch的话把storage.selector改成elasticsearch并配置ES的节点地址、命名空间等。命名空间建议每个环境单独设置如skywalking-prod防止多环境数据混在一个ES索引里。提示单机测试环境也可以直接配MySQL。修改storage.selector: mysql并把mysql节点下的连接地址、账号密码配置好即可。首次启动会自动建表不用手动执行SQL。3.3 Java服务挂载AgentAgent接入的核心就是把skywalking-agent.jar通过JVM参数挂载到业务服务上。假设我的两个微服务分别是order-service和stock-service启动命令java -javaagent:/opt/skywalking-agent/skywalking-agent.jar \ -Dskywalking.agent.service_nameorder-service \ -Dskywalking.collector.backend_service127.0.0.1:11800 \ -jar order-service.jar这里三个关键参数的作用我拆开解释-javaagent指定Agent包的绝对路径。这是字节码增强入口JVM启动时加载Agent并完成对目标类的插桩。-Dskywalking.agent.service_name定义当前服务在SkyWalking里的展示名称。我见过不少团队忽略这个参数导致所有服务在拓扑图上都显示成默认的your_application_name排查问题完全对不上号——这个名称务必每个服务单独设置。-Dskywalking.collector.backend_service指定OAP的gRPC地址默认是127.0.0.1:11800如果OAP在别的机器上就改成对应IP。Spring Boot应用的另一种配置方式是把JVM参数写进启动脚本或环境变量。我习惯放在JAVA_OPTS环境变量里这样部署平台启动服务时自动带上Agent避免人工遗漏export JAVA_OPTS-javaagent:/opt/skywalking-agent/skywalking-agent.jar -Dskywalking.agent.service_nameorder-service -Dskywalking.collector.backend_service192.168.1.10:118003.4 验证链路是否打通两个服务都挂上Agent后在order-service里写一个调用stock-service的接口比如通过RestTemplate或OpenFeign然后发起几次请求。打开SkyWalking UI切到“拓扑图”页面正常情况下能看到两个服务节点以及它们之间的调用连线。再切到“追踪”页面按时间范围查询刚才的请求应该能看到完整的Trace记录。点开一条Trace瀑布流视图里能看到两个Segment每个都用Span标注了HTTP调用的耗时。这一刻你就算是“见到”分布式链路了。我第一验证的时候做了个粗心操作两个服务挂上了Agent但调用请求只发了一次UI上怎么都查不到Trace。后来才发现真正的问题是我请求的接口是静态资源路径根本走不到业务代码自然没有Span产生。验证时一定要打真正的业务接口别拿静态页面测试。4. 生产环境必配的进阶操作4.1 采样率省钱但不盲目的艺术链路数据是“量大且重复”的典型同一接口每秒成百上千次调用产生的Span结构高度相似。全量上报在数据量小时无所谓但每天几亿条Span写进存储磁盘和查询性能都会吃紧。这时候就要设置采样率。SkyWalking的采样配置在Agent端核心参数是-Dskywalking.agent.sample_n_per_3_secs20这个参数的含义是每3秒最多采样上报20条链路到OAP超出部分只记录指标不采集链路详情。数值越小越省资源但能查到的链路越少。默认值是负数表示全量采集。我实际调参的心得是指标数据Service/Endpoint的RT、QPS等不受采样影响采样只影响链路明细。所以就算采样率调得很低监控面板的指标依然准确只是细节链路变少了。对于绝大多数业务系统每3秒采样几十条链路足够支持问题定位但如果某个接口出现偶发异常且样本量太小可能正好没采到建议对该类接口单独放开全量采样。SkyWalking也支持动态采样配置在生产环境通过Agent配置文件或OAP端的配置中心动态调整不过这个玩法对新手不友好初期用启动参数固定采样率即可。4.2 日志与链路ID关联排障效率翻倍的关键动作链路追踪做好了日志却是另一套体系这就出现了“链路视图里看到某段慢却不知道这段日志打了什么”的割裂感。解决思路很朴素把Trace ID写进日志按ID关联查询。SkyWalking的做法是Agent会把Trace ID写入一个线程上下文里。在日志配置中引入SkyWalking提供的logback/log4j2扩展组件后就可以用占位符把Trace ID输出到日志里。logback的配置示例appender nameCONSOLE classch.qos.logback.core.ConsoleAppender encoder classch.qos.logback.core.encoder.LayoutWrappingEncoder layout classorg.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout pattern%d{yyyy-MM-dd HH:mm:ss.SSS} [%tid] [%thread] %-5level %logger{36} - %msg%n/pattern /layout /encoder /appender配置里加粗的%tid就是SkyWalking的Trace ID占位符。启用后日志里每一行都会带上一个类似1.2.3.4.xxxx的ID。排查问题时先从SkyWalking UI找到慢请求的Trace ID再去日志平台按这个ID一搜这一条请求在所有服务上的日志就全串起来了。这个配置看起来不起眼但我实战中的体会是它直接改变排障节奏——以前是先看日志猜链路再回UI核对来回切换很累现在是UI定位到Trace ID一把梭式查日志效率提升非常明显。4.3 告警规则别让平台变成数据孤岛链路追踪平台如果只用于事后排查价值就少了一半。生产环境强烈建议把告警接上SkyWalking的告警规则在OAP的config/alarm-settings.yml里配置支持按服务、端点等维度设置阈值。我常用的几个告警规则模板服务响应时间告警某服务平均RT超过阈值持续N分钟触发告警。成功率告警某服务的调用成功率低于阈值比如小于80%持续3分钟。慢链路告警单条链路总耗时超过某值如5秒直接告警这类告警在捕捉偶发慢请求时尤其管用。配置要点是expression的语法要和OAP版本匹配比如rules: endpoint_slow: expression: sum(endpoint_resp_time) / sum(endpoint_calls) 1000 period: 3 count: 2 message: 端点响应时间超过1000ms告警通知渠道支持Webhook可以接到企业微信、钉钉、飞书或自研告警平台。我一般把链路告警和原有的基础设施告警合并到一个群但带不同的标题前缀这样基础设施抖动和业务链路慢两个维度能分开收敛。5. 常见问题与排查技巧实录5.1 Agent挂载后服务启动失败或请求报错我在接入初期遇到过几次类似情况最典型的是Java Agent与业务服务所在JDK版本不兼容。SkyWalking 9.x的Agent要求JDK 8及以上但某些老项目用的JDK 8小版本过旧字节码增强时抛异常导致启动失败。排查步骤建议按顺序来查看业务服务启动日志定位是否Agent相关异常。确认Agent版本与服务端版本大版本一致。确认JDK版本满足要求必要时升级JDK小版本。使用-Dskywalking.agent.force_tlsfalse等参数排除HTTP上报问题少见但遇到过。另外要特别注意Agent加载顺序-javaagent参数必须放在-jar之前否则JVM不识别。这个顺序错误很隐蔽因为启动日志里甚至不会有明显报错但Agent压根没加载。5.2 UI上能看到服务但查不到Trace数据这个问题的典型场景拓扑图上有服务节点指标也正常但“追踪”页面怎么查都查不到链路。我总结了三个最常见的原因采样率配得太低链路明细被采样丢弃但指标照常上报。检查Agent启动参数里的sample_n_per_3_secs调大或用默认全量配置再测试。查询时间范围不对SkyWalking的Trace查询默认是最近15分钟如果链路写入比较慢或时区有问题很容易查不到。把时间范围扩大到30分钟或1小时再查。存储写入异常OAP日志里能直接看到写入存储的报错。如果用了ES检查索引是否创建成功健康状态是否正常。5.3 OAP高并发下吞吐下降、GC频繁OAP本身是Java进程在高吞吐链路上报场景下压力会传导到GC和内存配置上。OAP默认的JVM内存参数偏保守我碰到过一次OAP频繁Full GC导致链路数据大量丢失排查后发现是堆内存给小了。解决方式修改OAP启动脚本里的JVM参数把-Xms、-Xmx调大。我的经验是单机OAP处理每秒上万条Segment的规模堆内存至少给4GB以上。如果多语言Agent混用连接数很多还需要注意OAP机器的文件描述符上限。另外还有一个容易忽略的点Agent与OAP之间的gRPC是长连接如果OAP重启或网络闪断Agent会自动重连但短暂掉线期间的链路会丢失。生产环境OAP集群化部署能有效规避这个问题。5.4 快速排查速查表现象大概率原因处理手段服务列表为空Agent未挂载或上报地址错误检查启动参数、OAP的11800端口连通性拓扑图缺节点该服务未通过实际业务请求调用触发真实业务请求后再查看有指标无Trace采样率过低调整sample_n_per_3_secs参数Trace跨服务断链下游服务未接入Agent或版本不兼容检查所有服务Agent配置与版本UI页面白屏UI端口被占用或前端资源加载失败检查webapp配置与浏览器控制台报错写在最后Star
返回列表