☰
SkyWalking链路追踪从零搭建:架构、部署与生产调优实战
2026/10/14 19:48:16 网站建设 项目流程

1. 为什么我们最终选了SkyWalking这套链路追踪方案

第一次接触SkyWalking是在一个微服务拆分到二十多个模块的项目里,那会儿排查一个跨服务调用超时的问题,基本靠人肉串日志,一个请求经过网关、用户服务、订单服务、库存服务,每个服务日志格式还不一样,时间戳对不齐,查一次问题少说半小时起步。后来团队里有人提议上链路追踪,对比了几套方案之后,最终落地了SkyWalking。这篇文章就把我当时从零搭建SkyWalking的完整过程、踩过的坑、以及后续调优的经验,原原本本梳理一遍。

SkyWalking本质上是一套分布式系统的应用性能监控(APM)与链路追踪平台,它最核心的能力是:把一次用户请求在多个服务之间的完整调用链路串起来,让你能直观看到每个环节的耗时、状态、异常。它支持Java、Go、Python、Node.js、.NET等多种语言的探针接入,对业务代码基本零侵入,这一点是它相比很多同类方案最大的优势。适合谁看?如果你是后端开发、运维、SRE,或者正在做微服务架构落地,需要一套能快速定位性能瓶颈的工具,那这篇内容基本可以照着抄。

我搭建的环境是Linux服务器(CentOS 7),SkyWalking版本用的是8.x系列,后端存储选的是Elasticsearch 7.x。为什么不用H2或者MySQL?H2是内存数据库,重启数据就没了,只适合本地跑Demo;MySQL在数据量大了之后查询性能会明显下降,而Elasticsearch天生适合时序数据的存储和聚合查询,这是生产环境的标配选择。下面我会把整个搭建过程拆成几个部分,从架构理解到环境准备,再到具体部署和验证,最后是常见问题排查。

2. SkyWalking整体架构与核心概念拆解

2.1 四大核心组件到底各干什么

很多人第一次看SkyWalking的架构图会觉得组件有点多,其实拆开看就四个东西,各司其职。

探针(Agent):挂在你的业务应用上,负责采集调用数据。Java应用就是在启动参数里加一个-javaagent指向探针jar包,不需要改一行业务代码。探针会把采集到的数据通过gRPC协议上报给后端。

后端(OAP Server):全称Observability Analysis Platform,是整个系统的核心。它接收探针上报的数据,做流式分析、聚合计算,然后把结果写入存储。OAP Server可以集群部署,多个节点之间通过协调机制保证数据不重复处理。

存储(Storage):负责持久化数据。支持Elasticsearch、H2、MySQL、TiDB等多种后端。生产环境强烈建议用Elasticsearch,原因前面说过了。

界面(UI):就是那个Web控制台,默认端口8080,用来展示拓扑图、链路详情、指标仪表盘等。UI本身不存数据,它通过GraphQL查询OAP Server拿数据。

提示:探针和后端之间是gRPC通信,默认端口11800;后端和UI之间是HTTP通信,默认端口12800。这两个端口别搞混,防火墙规则要分别放行。

2.2 数据是怎么流转的

理解数据流转对后面排查问题特别重要。一次完整的链路数据流转是这样的:用户发起请求,请求经过服务A,服务A的探针生成一个TraceContext(包含TraceId和SpanId),当服务A调用服务B时,探针会把TraceContext通过请求头传递过去,服务B的探针接收到之后继续在这个TraceId下生成新的Span。每个Span记录了操作的开始时间、结束时间、状态、标签等信息。

这些Span数据被探针批量上报到OAP Server,OAP Server按照不同的维度做聚合:比如按服务维度算平均响应时间、按端点维度算P99耗时、按服务间调用关系构建拓扑图。聚合后的数据写入Elasticsearch,UI查询时直接从ES读取聚合结果,所以UI的响应速度取决于ES的查询性能。

这里有个关键点:SkyWalking默认会对数据进行采样,不是每一个请求都会完整记录链路。采样率通过探针配置里的agent.sample_n_per_3_secs参数控制,默认是-1表示全量采集。生产环境如果流量很大,建议设置一个合理的采样率,否则存储压力会很大。

2.3 为什么选Elasticsearch做存储

这个问题值得单独说一下。SkyWalking的存储选型直接决定了整套系统的稳定性和查询性能。我整理了一个对比表格,是我当时选型时的实际考量:

存储类型适用场景优点缺点
H2本地Demo、功能验证零配置,开箱即用内存存储,重启丢数据,不支持集群
MySQL小规模测试运维熟悉,部署简单大数据量下查询慢,聚合能力弱
Elasticsearch生产环境分布式、高可用、聚合查询快需要额外维护ES集群,资源占用较高
TiDB大规模生产水平扩展能力强运维复杂度高,社区案例相对少

我当时选ES的理由很直接:链路数据本质上是时序数据,写入量大、查询以聚合为主,ES在这方面的能力是经过大量生产验证的。而且SkyWalking对ES的版本兼容性做得不错,7.x系列基本都能用。

3. 搭建前的环境准备与规划

3.1 服务器资源怎么估算

这一步很多人容易拍脑袋,我当时的经验是按数据量倒推。假设你的系统每天有100万次请求,每次请求平均产生5个Span,每个Span大约1KB数据,那一天的数据量大概是5GB。ES默认会保留一份副本,所以实际存储需求翻倍,就是10GB/天。如果你要保留30天的数据,那就是300GB。这还没算索引开销和ES自身的元数据。

基于这个估算,我当时的配置是:OAP Server单独一台机器,4核8G;ES集群三台机器,每台8核16G,SSD硬盘500G。UI可以和OAP Server部署在一起,因为它本身不怎么吃资源。当然这是中等规模的配置,如果你的请求量更大,ES集群的节点数和配置都要相应往上加。

注意:ES对内存特别敏感,JVM堆内存建议设置为物理内存的一半,但不要超过31GB(超过之后JVM会关闭指针压缩,反而浪费内存)。剩下的内存留给操作系统的文件缓存,这对ES的查询性能至关重要。

3.2 软件版本兼容性确认

SkyWalking的版本和ES版本之间有兼容性要求,不是随便哪个版本都能搭配。我整理了一下常见的对应关系:

SkyWalking版本推荐ES版本JDK要求
8.9.x7.10 - 7.17JDK 8/11
9.x7.17 - 8.xJDK 11/17
10.x8.xJDK 17

我当时用的是SkyWalking 8.9.1配ES 7.17.0,JDK用的11。这里要特别提醒:OAP Server和探针的JDK要求可能不一样。OAP Server从9.x开始要求JDK 11以上,但探针支持JDK 8的应用,这个不冲突,因为探针是跑在业务应用进程里的,用的是业务应用的JDK。

3.3 端口规划与防火墙配置

SkyWalking涉及的端口比较多,提前规划好能省很多事。默认端口清单如下:

  • 11800:探针gRPC上报端口
  • 12800:UI查询OAP的HTTP端口
  • 8080:UI Web访问端口
  • 9200:ES HTTP端口
  • 9300:ES集群内部通信端口

如果服务器开了防火墙,这些端口都要放行。我当时的做法是只对内部网段开放11800和9200,8080和12800通过反向代理对外暴露,这样安全性更好。

# 查看端口是否被占用 netstat -tlnp | grep -E "11800|12800|8080|9200" # 开放防火墙端口(以firewalld为例) firewall-cmd --zone=public --add-port=11800/tcp --permanent firewall-cmd --zone=public --add-port=12800/tcp --permanent firewall-cmd --zone=public --add-port=8080/tcp --permanent firewall-cmd --reload

4. 分步实操:从零把SkyWalking跑起来

4.1 Elasticsearch的安装与关键配置

ES是整套系统的地基,地基不稳后面全是问题。我当时的安装步骤是这样的:

# 下载ES 7.17.0 wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.17.0-linux-x86_64.tar.gz # 解压 tar -zxvf elasticsearch-7.17.0-linux-x86_64.tar.gz -C /opt/ # 创建专用用户(ES不允许root用户启动) useradd esuser chown -R esuser:esuser /opt/elasticsearch-7.17.0/

接下来是配置文件config/elasticsearch.yml的关键修改:

cluster.name: skywalking-es node.name: node-1 path.data: /data/es/data path.logs: /data/es/logs network.host: 0.0.0.0 http.port: 9200 discovery.seed_hosts: ["10.0.0.1", "10.0.0.2", "10.0.0.3"] cluster.initial_master_nodes: ["node-1", "node-2", "node-3"]

JVM配置在config/jvm.options里,我设置的是:

-Xms8g -Xmx8g

为什么是8G?因为机器是16G内存,按一半给堆,剩下一半留给文件缓存。这个比例在实际使用中表现最稳。

注意:ES启动前一定要检查vm.max_map_count参数,默认值太小会导致ES启动失败。执行sysctl -w vm.max_map_count=262144,并写入/etc/sysctl.conf永久生效。这个坑我踩过,当时ES日志里报的是"max virtual memory areas vm.max_map_count [65530] is too low",找了半天才发现是这个参数的问题。

4.2 SkyWalking OAP Server的部署

OAP Server的部署相对简单,下载解压之后主要改一个配置文件。

# 下载SkyWalking 8.9.1 wget https://archive.apache.org/dist/skywalking/8.9.1/apache-skywalking-apm-8.9.1.tar.gz # 解压 tar -zxvf apache-skywalking-apm-8.9.1.tar.gz -C /opt/ cd /opt/apache-skywalking-apm-bin/

核心配置文件是config/application.yml,需要修改存储部分:

storage: selector: ${SW_STORAGE:elasticsearch} elasticsearch: nameSpace: ${SW_NAMESPACE:""} clusterNodes: ${SW_STORAGE_ES_CLUSTER_NODES:10.0.0.1:9200,10.0.0.2:9200,10.0.0.3:9200} protocol: ${SW_STORAGE_ES_HTTP_PROTOCOL:"http"} user: ${SW_ES_USER:""} password: ${SW_ES_PASSWORD:""} indexShardsNumber: ${SW_STORAGE_ES_INDEX_SHARDS_NUMBER:2} indexReplicasNumber: ${SW_STORAGE_ES_INDEX_REPLICAS_NUMBER:1} bulkActions: ${SW_STORAGE_ES_BULK_ACTIONS:2000} flushInterval: ${SW_STORAGE_ES_FLUSH_INTERVAL:10} concurrentRequests: ${SW_STORAGE_ES_CONCURRENT_REQUESTS:2}

这里有几个参数值得解释一下。indexShardsNumber是索引分片数,默认是1,我改成了2,因为分片数一旦设定就不能改(除非重建索引),所以要根据数据量提前规划。bulkActions是批量写入的条数,2000是一个比较均衡的值,太小会导致写入频繁,太大则内存占用高。flushInterval是刷新间隔,单位秒,10秒意味着数据最多延迟10秒可见。

启动OAP Server:

# 启动 bin/oapService.sh start # 查看日志确认启动成功 tail -f logs/oap.log

日志里看到"OAP starts up successfully"就说明起来了。如果启动失败,大概率是ES连接问题,先检查ES是否正常、网络是否通、认证信息是否正确。

4.3 UI界面的启动与访问

UI的配置在webapp/webapp.yml里,主要改OAP的地址:

server: port: 8080 spring: cloud: gateway: routes: - id: oap-route uri: lb://oap-service predicates: - Path=/graphql/**

如果OAP和UI在同一台机器,默认配置基本不用改。启动UI:

bin/webappService.sh start

浏览器访问http://服务器IP:8080,能看到SkyWalking的界面就说明搭建成功了。默认没有登录认证,生产环境建议在前面加一层Nginx做Basic Auth或者接入统一的认证网关。

4.4 业务应用接入探针的完整步骤

后端跑起来了,接下来就是让业务应用把数据上报上来。以Java应用为例,步骤是这样的:

第一步,把探针目录拷贝到业务服务器上。探针在SkyWalking包的agent/目录下,整个目录拷过去就行。

第二步,修改探针配置agent/config/agent.config:

# 服务名,这个很重要,UI上就是按这个名来区分服务的 agent.service_name=${SW_AGENT_NAME:user-service} # OAP Server地址 collector.backend_service=${SW_AGENT_COLLECTOR_BACKEND_SERVICES:10.0.0.1:11800} # 采样率,-1表示全量采集 agent.sample_n_per_3_secs=${SW_AGENT_SAMPLE:-1} # 忽略特定后缀的请求 agent.ignore_suffix=${SW_AGENT_IGNORE_SUFFIX:.jpg,.jpeg,.png,.css,.js}

第三步,在应用启动参数里加上javaagent:

java -javaagent:/opt/skywalking-agent/skywalking-agent.jar \ -Dskywalking.agent.service_name=user-service \ -Dskywalking.collector.backend_service=10.0.0.1:11800 \ -jar user-service.jar

这里有个小技巧:service_name和backend_service既可以在配置文件里写,也可以通过-D参数传,-D参数的优先级更高。我习惯用-D参数,因为这样不同环境可以用同一份探针配置,启动脚本里区分就行。

提示:探针的service_name命名要有规范,建议用"应用名-模块名"的格式,比如"order-service-api"、"order-service-job"。如果命名太随意,UI上的拓扑图会乱成一团,后期维护很痛苦。

5. 搭建后的验证与核心功能体验

5.1 怎么确认数据真的上报成功了

应用启动之后,访问几个接口产生一些流量,然后打开UI界面。如果搭建正确,你会在几个地方看到数据:

拓扑图(Topology):能看到服务之间的调用关系,节点之间的连线代表调用,连线上会显示平均响应时间。如果拓扑图是空的,说明探针没有上报数据,先检查探针日志agent/logs/skywalking-api.log里有没有报错。

追踪(Trace):能看到具体的调用链路,每个Span的耗时、状态、标签都列得很清楚。我一般会按耗时排序,快速找到最慢的那个Span。

仪表盘(Dashboard):有服务、端点、实例等多个维度的指标,包括响应时间、吞吐量、成功率等。这些指标是OAP聚合计算出来的,不是原始数据。

5.2 链路追踪界面到底怎么看

链路追踪界面是平时用得最多的。一次请求的链路会以树形结构展示,根Span是入口,子Span是下游调用。每个Span上会显示几个关键信息:

  • Duration:这个Span的耗时,单位是毫秒
  • Status:成功还是失败,失败会标红
  • Span Type:是本地方法调用还是远程调用
  • Tags:附加信息,比如HTTP状态码、数据库语句等

我排查问题时有个习惯:先看根Span的总耗时,然后找耗时占比最大的子Span,一层层往下钻,基本能定位到瓶颈在哪个服务、哪个方法、甚至哪条SQL。这个效率比翻日志高太多了。

5.3 告警功能的基本配置

SkyWalking内置了告警功能,可以基于指标设置规则。配置文件在config/alarm-settings.yml,我配置了几条常用的规则:

rules: service_resp_time_rule: metrics-name: service_resp_time op: ">" threshold: 1000 period: 10 count: 3 silence-period: 5 message: "服务 {name} 响应时间超过1秒,连续3次" service_sla_rule: metrics-name: service_sla op: "<" threshold: 9500 period: 10 count: 2 silence-period: 5 message: "服务 {name} 成功率低于95%"

这个配置的意思是:服务响应时间连续3次(每次统计周期10秒)超过1秒就告警,告警后静默5分钟避免重复告警。告警可以通过Webhook推送到钉钉、企业微信等平台,配置在alarm-settings.yml的webhooks部分。

6. 常见问题排查与避坑经验实录

6.1 探针不上报数据的排查思路

这是搭建过程中最高频的问题。我的排查顺序是这样的:

第一步,看探针日志。探针的日志在agent/logs/目录下,重点看skywalking-api.log。如果里面有"connect refused"之类的错误,说明探针连不上OAP Server,检查网络和端口。

第二步,确认backend_service配置是否正确。这个地址是OAP Server的gRPC端口,默认11800,不是UI的8080,也不是HTTP的12800。我见过有人填错端口排查了半天的。

第三步,确认服务名是否配置。如果service_name没配或者配成了默认值,数据可能上报了但UI上找不到。

第四步,检查OAP Server日志。如果探针显示发送成功但UI没数据,问题可能在OAP这边,看oap.log里有没有写入ES失败的报错。

6.2 ES索引膨胀导致磁盘打满

这个问题在生产环境很常见。SkyWalking会在ES里创建大量索引,按天分索引,如果没设置生命周期管理,索引会一直堆积。我当时的解决方案是配置ES的ILM(Index Lifecycle Management)策略,或者用SkyWalking自带的TTL配置。

在application.yml里可以设置数据保留天数:

storage: elasticsearch: recordDataTTL: ${SW_STORAGE_ES_RECORD_DATA_TTL:3} metricsDataTTL: ${SW_STORAGE_ES_METRICS_DATA_TTL:7}

recordDataTTL是链路明细数据的保留天数,metricsDataTTL是指标数据的保留天数。明细数据量大但查询频率低,保留3天就够了;指标数据量小但需要看趋势,保留7天。这个要根据实际磁盘容量来调。

6.3 OAP Server启动慢或频繁GC

OAP Server默认的JVM堆是2G,如果数据量大或者ES响应慢,很容易出现GC频繁甚至OOM。调整方式是在bin/oapService.sh里修改JAVA_OPTS:

JAVA_OPTS=" -Xms4g -Xmx4g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 "

用G1垃圾回收器,并且设置最大GC停顿时间200毫秒,这对在线服务的响应时间影响最小。堆大小根据实际负载调整,一般4G到8G之间。

6.4 常见问题速查表

问题现象可能原因排查方向解决方案
UI拓扑图空白探针未上报查探针日志、网络连通性检查backend_service配置和端口
链路数据不完整采样率设置过低查agent.sample配置调高采样率或设为-1
OAP启动报ES连接失败ES地址或认证错误查oap.log核对clusterNodes和账号密码
查询界面很慢ES查询性能差查ES集群状态和索引分片增加ES节点、优化分片数
磁盘快速增长数据保留策略未配置查ES索引列表配置TTL或ILM策略
探针导致应用启动变慢探针初始化阻塞查应用启动日志检查探针版本兼容性

6.5 几个我踩过的坑

坑一:探针版本和OAP版本不匹配。有一次升级了OAP Server但没升级探针,结果数据上报格式对不上,UI上数据错乱。后来我养成了习惯,升级时探针和后端一起升,版本号保持一致。

坑二:ES的indexReplicasNumber设成了0。当时为了省磁盘把副本数设成0,结果ES节点挂了一个之后数据直接不可用。生产环境副本数至少是1,这是底线。

坑三:忽略了时钟同步。链路追踪依赖时间戳来串联Span,如果服务器之间时钟不同步,链路会错乱甚至断裂。所有节点都要配NTP同步,这个在分布式系统里是基本要求。

坑四:探针的ignore_suffix没配。静态资源请求也被采集了,导致大量无意义的Span,既浪费存储又干扰排查。把图片、CSS、JS这些后缀加到忽略列表里,数据量能降不少。

7. 生产环境的一些调优建议

7.1 采样策略怎么定

全量采集只适合流量小的场景。流量大了之后,采样是必须的。SkyWalking支持两种采样方式:一种是固定采样率,通过agent.sample_n_per_3_secs设置每3秒采集的请求数;另一种是自定义采样,通过实现SamplingService接口来做更精细的控制。

我的经验是:核心链路(比如下单、支付)全量采集,非核心链路(比如查询、列表)按10%采样。这样既保证了关键业务的可观测性,又控制了整体数据量。自定义采样需要写一点代码,但收益很明显。

7.2 OAP Server集群部署要点

单节点OAP Server存在单点故障风险,生产环境建议至少两个节点。集群部署时,多个OAP节点之间需要通过协调机制来避免重复处理数据。SkyWalking支持多种协调方式,默认是Standalone(单机模式),集群模式需要配置为Kubernetes或者Zookeeper。

cluster: selector: ${SW_CLUSTER:zookeeper} zookeeper: hostPort: ${SW_CLUSTER_ZK_HOST_PORT:10.0.0.1:2181} sessionTimeout: 100000

集群部署之后,探针可以配置多个OAP地址,用逗号分隔,探针会自动做负载均衡和故障转移。

7.3 数据备份与恢复

ES里的数据是链路追踪的全部家当,备份很重要。ES提供了Snapshot API,可以把索引快照到对象存储或者共享文件系统。我当时的做法是每天凌晨做一次增量快照,保留最近7天的快照。恢复的时候通过Snapshot API恢复指定索引。

这个操作虽然不复杂,但一定要提前演练。我见过有团队配了快照但从来没验证过恢复流程,真出问题的时候发现快照是坏的,那就尴尬了。

8. 写在最后的一点个人体会

SkyWalking这套东西,搭建本身其实不难,官方文档写得也算清楚,真正花时间的是调优和排错。我最大的体会是:监控系统本身也需要被监控。OAP Server的JVM状态、ES集群的健康度、探针的上报成功率,这些指标都要纳入监控,否则监控系统自己挂了你还不知道。

另外一点,链路追踪的价值不在于搭建,而在于团队真的用它来排查问题。我见过不少团队搭了SkyWalking但没人看,出了问题还是翻日志。工具再好,不用就是摆设。建议搭建完成之后,组织一次团队内的分享,把常用的查询技巧、排查思路讲清楚,让大家都用起来,这套系统的价值才能真正发挥出来。

最后分享一个实用小技巧:SkyWalking的UI支持自定义仪表盘,可以把团队最关心的几个指标(比如核心接口的P99耗时、错误率)做成一个面板,每天早会的时候看一眼,有异常能第一时间发现。这个习惯坚持下来,很多问题在用户反馈之前就能被主动发现。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询