聊分布式系统的可观测性Skywalking是我落地链路追踪时经常会用到的开源APM项目。它最吸引人的地方在于JavaAgent无侵入接入SpringBoot应用加一个启动参数就能看到完整的服务调用拓扑这个优势让很多团队从其他方案迁过来。这篇文章围绕Skywalking 9.4把安装过程和SpringBoot集成完整讲一遍适合正在做微服务拆分、或者想给现有服务加链路追踪的读者。我会从组件结构、存储选型、部署步骤、Agent集成到生产调优按真实落地的顺序一个个讲清楚尽量少说空话多给可以直接抄作业的命令和参数。1. Skywalking是什么为什么微服务都离不开它1.1 定位与核心功能Skywalking是一款开源的APMApplication Performance Monitoring系统核心能力是分布式链路追踪、服务拓扑自动生成、服务指标监控和告警。它最早是一个个人开源项目后来逐步成为Apache顶级项目在国内的技术社区、互联网公司里被大量使用。你可以把它简单理解成一张“服务调用地图”哪个接口调了哪个服务、走了多长时间、哪一段耗时最高、哪里报错都能在Web UI上一眼看清楚。它解决的问题很典型。一个请求从浏览器打到网关网关再调订单服务订单服务查数据库、调库存服务、调支付服务如果其中一环变慢你很难靠人工日志拼出完整链路。Skywalking做的事情就是通过埋点自动记录一次请求经过的所有服务节点把每个节点的时间消耗、执行状态串成一条完整的Trace数据。有了这条Trace你定位慢接口、排查超时、分析服务依赖就不再靠猜了。在功能上它也覆盖了比较完整的可观测性面板服务列表、实例列表、端点列表、拓扑图、Trace查询、性能对比、告警中心以及一些非侵入式的线程分析、缓慢SQL定位能力。对大多数团队的研发运维场景来说这一套基本够用。1.2 和Zipkin、Pinpoint相比我为什么留它很多人选型时会在Zipkin、Pinpoint、Skywalking之间纠结。Zipkin是链路追踪领域的经典方案模型轻量和Spring Cloud Sleuth配合也很成熟但它的短板是只解决“链路追踪”没有完整的拓扑分析、告警规则、持久化聚合能力你要做二次开发的话工作量大。Pinpoint是另一款优秀APMUI体验和调用链分析都做得很细但它的Agent对业务代码的字节码增强范围非常深接入后遇到版本冲突概率相对高而且部署运维对技术栈的要求不低。Skywalking在我这里的胜出点很直接JavaAgent无侵入、功能完整、社区活跃。无侵入意味着业务代码一行都不用改。它是通过JavaAgent技术对HttpClient、JDBC、SpringMVC、Dubbo、gRPC等常见组件做自动增强拦截装好Agent就能采集数据这对于一个已经上线的老系统来说是最友好的接入方式。功能完整则体现在UI上开箱即用服务拓扑、Trace检索、端点监控、告警、慢SQL都有默认页面不需要自己搭Grafana拼一堆指标。再加上它原生支持gRPC协议上报数据延迟低很多基础组件也都有官方插件省心。当然Zipkin在一些对重量级功能没有要求的场景下更适合比如只是临时排查一次调用问题。但如果你考虑的是长线运维、故障发现、服务治理我建议直接走Skywalking。2. Skywalking 9.4安装部署从下载到UI可访问2.1 安装包里的组件先弄懂它们的关系Skywalking 9.4版本解压之后你会看到agent、bin、config、oap-libs、webapp、logs等目录。这里面涉及三个核心角色OAP Server后端分析服务负责接收Agent上报的链路数据、做指标聚合、写入存储同时提供查询接口给UI。Web UI前端展示层负责把OAP中聚合好的数据渲染成拓扑图、Trace页、仪表盘。Agent部署在业务应用里的探针采集调用链数据并通过gRPC协议上报给OAP Server。还有一个角色是StorageOAP本身不存储数据它需要一个外部存储来持久化链路和指标数据。9.4支持H2、Elasticsearch、BanyanDB、MySQL等存储方式其中H2是内置的适合快速体验但生产环境几乎不会用它因为数据量一大就扛不住了。所以一个完整的链路是这样的业务应用挂AgentAgent把Trace和指标发到OAP Server端口11800OAP在内存中聚合后写入Storage用户打开WebUI端口8080从OAP查询数据。理解了这个数据流向你后面排查“看不到服务”“没有链路数据”这类问题会容易很多。2.2 存储选型H2、Elasticsearch、BanyanDB怎么选9.4版本默认配置文件里的存储selector指向H2这个配置可以直接跑起来适合第一次安装做功能验证。但H2只能存少量数据重启还可能丢数据所以在正式使用前我建议至少换成Elasticsearch或BanyanDB。Elasticsearch是Skywalking最常见的存储方案成熟稳定资料多。如果你所在团队本来就维护了一套ES集群直接复用很划算。缺点是ES本身吃内存、吃磁盘部署一套集群对一些小团队来说成本偏高。BanyanDB是Skywalking社区推动的专用存储设计目标就是更好地匹配Skywalking的数据模型。9.4版本对BanyanDB的支持已经开始集成将来它很可能会成为官方推荐的首选存储。不过目前生产使用例子还不够多谨慎起见大部分团队仍会选择ES。这里给一个比较实用的选型建议生产环境数据量不大、服务实例数在几十以内的直接用单节点ES7就够了数据量很大、团队有ES运维能力的优先用ES集群如果你接受新技术、愿意踩点坑可以试试BanyanDB。下面我按Elasticsearch模式来讲解因为这最贴近大多数人的实际环境。2.3 安装和启动OAP与UI的完整命令先准备好基础环境。Skywalking基于Java开发OAP和WebUI都需要JDK建议安装JDK11或JDK17Agent端则要求业务应用运行在JDK8及以上。机器配置最低2核4G体验模式还能更低一点但要做数据测试建议是4核8G。下载Skywalking 9.4安装包时注意选择apache-skywalking-apm-9.4.0.tar.gz这个完整包。包里自带Agent也能满足后续SpringBoot集成需要。下载完成后解压到指定目录比如/opt/skywalkingtar -zxvf apache-skywalking-apm-9.4.0.tar.gz mv apache-skywalking-apm-9.4.0 /opt/skywalking cd /opt/skywalking打开config/application.yml把存储相关配置改一下。下面是关键几点storage: selector: ${SW_STORAGE:elasticsearch7} elasticsearch7: nameSpace: ${SW_NAMESPACE:} clusterNodes: ${SW_STORAGE_ES_CLUSTER_NODES:localhost:9200} indexShardsNumber: ${SW_STORAGE_ES_INDEX_SHARDS_NUMBER:2} indexReplicasNumber: ${SW_STORAGE_ES_INDEX_REPLICAS_NUMBER:0}这里SW_STORAGE环境变量可以用来切换存储模式。我建议把selector显式写成elasticsearch7或者通过环境变量传入避免别人拿到配置后还停留在H2模式。接下来启动服务。Skywalking提供了统一启动脚本在bin目录下执行startup.sh就能同时拉起OAP和WebUIcd /opt/skywalking/bin ./startup.sh如果你想分别控制这两个进程可以拆开执行./oapService.sh ./webappService.sh启动顺序上建议先启动OAP再启动WebUI因为WebUI启动时会检查后端OAP地址是否可用。虽然两个进程一起启动通常也能跑通但分开启动更容易定位启动失败的问题。2.4 验证安装端口、日志和索引三项检查进程启动后直接用三个方法验证安装结果。第一是端口检查。OAP的gRPC端口是11800UI的HTTP端口是8080OAP还提供一个HTTP端口12800主要给一些非gRPC客户端使用。确认端口正常监听netstat -tlnp | grep -E 11800|8080|12800第二是接口连通性。在浏览器访问http://localhost:8080能打开WebUI页面就说明前端没问题。如果想在命令行确认可以curl一下OAP的HTTP端口curl http://localhost:8080 curl http://localhost:12800第三是检查ES索引是否创建。OAP启动成功后会向ES写入索引模板并创建系统索引你可以通过ES的索引API查看curl http://localhost:9200/_cat/indices | grep sw_这里有一个常见的坑如果你看到logs目录下的skywalking-oap-server.log里报错“Create index failed”或者“NoNodeAvailableException”大概率是OAP连不上Elasticsearch。检查ES是否启动、clusterNodes地址是否写对、ES的内存是否够用。OAP在写入大量索引时对ES的内存要求不低本地测试时如果ES堆内存只有512M经常会出现索引创建一半失败的情况。3. SpringBoot集成SkywalkingAgent接入与链路验证3.1 JavaAgent的无侵入原理先看它怎么“偷”到调用链SpringBoot项目接入Skywalking本质上不是引入一个SDK而是挂载一个JavaAgent。JavaAgent是JVM提供的一种预加载机制允许在应用主方法执行之前通过javaagent参数加载一个代理jar包这个jar包可以在类加载时对目标方法做字节码增强。Skywalking-Agent在应用启动时会接管诸如SpringMVC的DispatcherServlet、RestTemplate的请求发送、JDBC的Statement执行等关键逻辑。它不是靠你去改动这些框架而是通过字节码增强在这些组件的最终执行点前后插入Skywalking的逻辑数据记录当前Span、统计耗时、采集上下文信息。这就是为什么说“零侵入”你的代码一行没改框架还是那些框架只是在类加载过程中被“插了一脚”。理解这个原理对你后续排查很重要。如果你发现某个框架的调用链没断、某个中间件没有出现在Trace中绝大多数情况不是代码问题而是这个组件没有被Agent插件覆盖或者版本不在支持范围。Skywalking的插件机制遵循“互不干扰”原则它会对每个目标类的增强做隔离理论上不会因为Agent的字节码修改破坏业务逻辑。3.2 SpringBoot服务接入的三种启动方式在Skywalking安装包的agent目录里已经自带了一个完整的JavaAgent。接入方式就是在JVM启动参数里加上-javaagent并指定服务名和上报地址。假设你的SpringBoot服务交付物是app.jar那么一条最标准的启动命令是这样java -javaagent:/opt/skywalking/agent/skywalking-agent.jar \ -Dskywalking.agent.service_nameorder-service \ -Dskywalking.collector.backend_service192.168.10.20:11800 \ -jar app.jar这里面有三个参数最关键skywalking.agent.service_name这个服务在UI里的名称多个实例如果同一个服务名会被聚合到同一个逻辑服务下。skywalking.collector.backend_serviceOAP Server的gRPC地址格式是ip:11800默认值是127.0.0.1:11800。如果你Agent和服务不在同一台机器这个参数必须改成OAP所在机器的地址。javaagent后面的agent jar路径注意是skywalking-agent.jar不是别的子模块jar。如果你的SpringBoot应用是用IDEA本地调试可以在Run/Debug Configurations的VM options里直接填这行参数效果和在命令行启动一样。这种方式特别适合本地联调改完配置直接就能看到链路。很多团队会选择把Agent参数固化到环境变量里这样部署脚本不用写死路径。比如export SW_AGENT_NAMEorder-service export SW_AGENT_COLLECTOR_BACKEND_SERVICES192.168.10.20:11800 java -javaagent:/opt/skywalking/agent/skywalking-agent.jar -jar app.jar这里有一个优先级要注意命令行-D参数会覆盖环境变量。也就是说配置中心或启动脚本里显式指定的-Dskywalking.agent.service_name优先级高于SW_AGENT_NAME环境变量。3.3 打通一个真实链路从Controller到MySQL调用接入之后也像什么都没发生一样启动此时我们要做的第一件事不是看UI而是确认Agent日志。正常情况下Agent会在启动时输出类似这样的日志Skywalking Agent [order-service] start successfully.如果Agent配置错误比如连不上OAP的11800端口日志里会有连接失败或重试提示。在日志里看到“start successfully”之后再发起一个测试请求然后回头去WebUI刷新页面。这里我建议你做一个小实验在SpringBoot工程里写一个Controller这个Controller调用一个ServiceService里执行一次基于Spring Data JPA或MyBatis的数据库查询再通过RestTemplate调用一个第三方HTTP接口。这样一个简单的接口里就囊括了Web入口、本地方法调用、JDBC查询、HTTP调用几种常见的Span类型。请求一次之后打开Skywalking UI进入“追踪”页面按服务名和时间范围搜索应该能看到一条完整的Trace记录。展开Trace可以看到这段调用的完整大事记Controller的耗时、Service层的耗时、SQL执行耗时、RestTemplate请求耗时每段都有独立的Span ID和父Span ID。如果数据库查询比较慢性能分析的SQL列表里也会出现这条慢SQL。UI里的“拓扑”页面则会把order-service和它调的下游依赖画成一张图。箭头上的数字是吞吐和延迟颜色代表健康状态。一般绿色代表正常红色代表错误率超过阈值。看到这张拓扑图基本就说明链路已经全面打通了。4. 生产环境关键配置采样、存储与告警一个都不能少4.1 采样率和服务名规范先保证数据质量Skywalking默认会采集全部请求也就是全量采样。在开发环境这没什么问题但在生产环境高并发服务一秒成百上千个请求全量采集意味着OAP、ES的写入压力很直接。特别是那些核心入口服务Trace数据量可能大得惊人。Agent有一个采样参数叫agent.sample_n_per_3_secs表示每3秒中采集多少条请求。默认值是-1表示全量采集。如果你把它配成3就表示每3秒只采样3条请求。它的计数按单个实例维度算不是集群维度。-Dskywalking.agent.sample_n_per_3_secs3不过我自己不太建议一上来就把采样率调得很低RocketMQ、Kafka这类中间件链路本身数据量并不大真正的量主要来自HTTP入口。比较稳健的做法是先全量跑几天看ES的磁盘增长速度和写入吞吐再根据情况调整到一个既能覆盖绝大多数问题、又不至于撑爆存储的采样率。除了采样还有一类数据要提前处理就是健康检查、静态资源、探活接口这类没有分析价值的请求。如果这些请求都进到链路里你会发现一个服务90%的Trace都是健康检查在刷屏。Agent提供了忽略后缀的参数-Dskywalking.agent.ignore_suffix.js,.css,.png,.ico,.txt更合适的做法是用ignore_path配置按路径匹配器来忽略特定URL。这样既能减少无效数据又能保持核心业务链路的完整性。服务名规范是很多人忽略但非常重要的一点。一个服务名对应UI里的一个逻辑节点如果你把测试环境和生产环境都叫同一个名字或者把两个不同业务的服务都配成同一个名字拓扑图会串得不成样子。我建议采用“环境名-业务名-服务名”的组合规则比如prod-order-core这种格式同时在配置中心统一管理Agent参数避免每个实例各自乱配。4.2 Elasticsearch索引参数与数据保留策略存储这块在安装配置里讲过基础项生产调优时需要关注的更多。Skywalking在Elasticsearch中会建大量以天为维度的索引例如service_traffic、segment、endpoint_traffic等。每个索引默认会分片和副本分片数越多并行查询越快但ES集群资源消耗也越大。对中小规模系统来说分片设置默认值微调一下即可不必追求很夸张的配置。比较值得关注的是OAP的批量写入参数。OAP向ES写数据不是单条同步写而是攒批写入相关参数在config/application.yml中core: default: # 批量聚合周期 topNReportPeriod: 10 storage: elasticsearch7: # 批写请求大小 bulkActions: ${SW_STORAGE_ES_BULK_ACTIONS:2000} # 批量攒批大小 flushInterval: ${SW_STORAGE_ES_FLUSH_INTERVAL:10} # 并发请求数量 concurrentRequests: ${SW_STORAGE_ES_CONCURRENT_REQUESTS:2}如果你发现OAP日志中大量时间花在等待ES响应可以适当降低bulkActions增大concurrentRequests平衡写入压力。ES端的JVM堆内存建议至少分配4G否则索引段的合并和查询很容易把节点拖垮。数据保留策略也需要早做规划。Skywalking的索引默认会自动删除过期数据相关配置在OAP环境变量SW_STORAGE_ES_RETENTION或配置文件里。保留天数越多存储占用越大。链路追踪数据通常保留7到15天就够了指标类数据可以适当放长一点。很多人会遇到“磁盘满了”的告警多数就是没设置保留周期或者设置的保留天数远超实际需要。4.3 告警规则和消息通知配置Skywalking自带了一套告警引擎默认配置文件在config/alarm-settings.yml。里面有服务响应时间告警、服务错误率告警、实例心跳告警、慢Trace告警等规则。默认规则比较粗略比如服务成功率低于一定比例、响应时间超过一定阈值就会触发你可以直接复制修改。告警动作可以配置webhook调用也就是说一旦有规则命中OAP会向一个HTTP地址发送JSON格式的告警内容。我们通常会在后端写一个接收告警的接口它把告警内容转发到聊天工具或自建平台。webhook配置在config/alarm-settings.yml里rules: - name: service_resp_time_rule metrics-name: service_resp_time op: threshold: 1000 period: 10 count: 3 message: 服务响应时间在最近10分钟内平均超过1秒 webhooks: - http://alert-platform.example.com/skywalking/webhook需要注意的是Skywalking告警基于OAP内部聚合的分钟级指标并不是每条Trace实时触发。这意味着告警天然有一点延迟适合做趋势发现和值班通知不适合做实时限流拦截。如果你需要实时告警还是要靠日志监控系统或网关侧指标来补充。5. 常见问题与排查技巧实录5.1 问题速查表集成Skywalking过程中真正容易出问题的其实就那么几类我整理成一张速查表方便你遇到问题时直接对号入座。问题现象常见原因处理办法UI上完全看不到服务Agent没成功启动或11800端口不通检查Agent日志是否有start successfully检查OAP地址和端口服务出现在UI但没有Trace数据请求没走Agent插件支持的组件或采样率被调成0发一个HTTP请求到SpringBoot Controller确认采样参数合理拓扑图只有孤零零一个节点JDBC、HTTP等插件未生效或调用发生在Agent不支持的范围确认对应组件版本是否在Skywalking插件支持列表内Agent启动时报版本不兼容Agent和OAP版本不一致保持Agent和OAP大版本一致尽量用同一版本号OAP启动后ES索引创建失败ES地址配置错误或ES内存不足检查ES集群状态和堆内存修改clusterNodes多个服务串成同一个节点不同服务用了同一个service_name逐个检查Agent参数规范服务名WebUI能开但页面无图表查询时间范围不对或OAP还没有完成指标聚合把时间范围设为最近15分钟等待1到2分钟后再刷新接口变慢怀疑是Agent影响Agent增强逻辑有开销有些场景开销较大初步判断可关闭部分插件通过agent.plugin排除列表控制5.2 从零到通的排查顺序如果你在接入过程中发现链路不通我强烈建议你按这个顺序排查而不是盲目改配置重启动。第一步看Agent日志。Skywalking Agent在启动时会输出框架增强日志、连接OAP的日志、插件加载列表。只要Agent没有打印启动成功后面一切都有可能是不通的。日志地址通常在Agent目录的logs文件夹下。第二步看端口连通性。从业务应用所在机器执行telnet OAP_IP 11800确认这台机器真的能访问OAP。很多团队卡在“我本地能查到数据测试环境却啥都没有”这个阶段最后定位出来是测试环境的服务器防火墙没放行11800端口。第三步看OAP日志。OAP启动过程会打印存储初始化、索引创建、监听端口等信息。如果OAP日志里有异常堆栈基本就是存储没连上或配置写错。OAP日志通常比Agent日志更有价值因为它能直接反映数据写入链路是否正常。第四步看ES索引。链路数据最终都要落到存储里。如果你在ES里看不到任何Skywalking相关的索引说明OAP还没成功初始化存储如果索引存在但数据量不增长说明Agent上报或者OAP处理链路有问题。这个判断方法能帮助快速缩小排查范围。这几步走下来大多数问题都能定位。我见过太多人一上来就怀疑版本、怀疑镜像、怀疑网络结果把整个环境翻了个底朝天最后只是防火墙没开。养成按数据流方向排查的习惯链路可观测性这份活你就算是真正上手了。如果你也是第一次给SpringBoot服务加链路追踪建议先在一台机器上把单机版OAP跑通确认能在一个固定服务上看到Trace再扩展到多服务集群。把基础链路走顺了以后不管是换存储、调采样率还是加告警心里都会更有底。