1. 为什么我们绕不开SkyWalking这套链路追踪系统
做后端微服务时间稍微长一点的人,大概都经历过这种场景:线上某个接口突然变慢,用户投诉不断,你打开日志系统一顿翻,发现A服务调B服务超时,B服务调C服务又正常,C服务自己查数据库慢得离谱,但日志里只有一行“query cost 3200ms”,具体是哪个SQL、哪个实例、哪次请求触发的,全靠猜。服务一多,调用链一深,这种排查方式基本等于大海捞针。
SkyWalking就是来解决这个问题的。它是一套开源的应用性能监控(APM)与分布式链路追踪系统,核心能力是把一次请求在多个服务之间的完整调用路径串起来,让你能直观看到每个环节的耗时、状态、依赖关系。它支持Java、Go、Python、Node.js、.NET等多语言探针,对业务代码基本无侵入,同时提供指标聚合、拓扑图、慢查询分析、告警等一整套能力。
这篇文章要聊的是SkyWalking的搭建,也就是从零把服务端跑起来,让探针能把数据上报进来,最终在UI上看到链路。适合谁看?如果你正在做微服务架构的落地,或者团队里没人搭过APM,你被安排来搞这件事,那这篇内容基本可以照着抄。我会把版本选型、存储选型、配置参数、探针接入、常见坑都讲清楚,尤其是那些官方文档一笔带过、但实际部署时一定会卡住的地方。
搭建这件事看起来简单,下载解压启动就完事,但真正落地时会遇到一堆问题:存储用H2还是Elasticsearch?端口冲突怎么处理?探针版本和服务端版本对不上怎么办?UI打开一片空白是什么原因?这些我都会在下面逐个拆开讲。
2. 搭建前的整体设计与选型思路
2.1 先搞清楚SkyWalking的组件构成
在动手之前,得先明白SkyWalking到底由哪几块组成,不然搭起来也是糊里糊涂。整套系统核心分三部分:
- OAP(Observability Analysis Platform):服务端核心,负责接收探针上报的数据、做流式分析、聚合指标、写入存储。它是整个系统的大脑,通常以集群方式部署。
- Storage:存储层,OAP分析完的数据要落盘。可选Elasticsearch、H2、MySQL、TiDB、BanyanDB等。生产环境基本就是ES或BanyanDB。
- UI:Web界面,从存储里查数据展示拓扑图、链路、指标。它本身不存数据,只做查询和渲染。
另外还有一个容易被忽略的角色:Agent(探针),它跑在业务应用进程里,负责采集数据并通过gRPC上报给OAP。探针和服务端是分开部署、分开升级的,这一点很关键。
理解了这个结构,你就知道搭建其实分两步:先把OAP+Storage+UI这套服务端跑起来,再把探针挂到业务应用上。很多人一上来就纠结探针怎么配,结果服务端都没通,白折腾。
2.2 存储选型:为什么生产环境不建议用H2
SkyWalking默认用的是H2内存数据库,开箱即用,下载完直接启动就能看到数据。但我必须提醒一句:H2只适合本地体验和功能验证,绝对不能上生产。原因有三个:
第一,H2是嵌入式数据库,数据存在本地文件里,OAP一重启数据就可能丢,而且不支持多OAP实例共享存储,集群部署直接废掉。第二,H2的写入性能有限,探针数据量一上来就扛不住,查询也慢。第三,H2没有副本和容灾能力,磁盘坏了数据就没了。
生产环境主流选择是Elasticsearch,原因是它天然支持水平扩展、有副本机制、写入吞吐高,而且SkyWalking对ES的支持最成熟,社区案例最多。如果你的团队已经在用ES,那直接复用现有集群就行,只需要注意版本兼容性。另一个新选择是BanyanDB,这是SkyWalking社区自研的时序数据库,专门为可观测性数据设计,写入性能比ES更好,资源占用更低,但生态和运维经验相对少一些,适合愿意尝新的团队。
我的建议是:第一次搭建、团队没有ES运维经验,就用ES 7.x系列,稳定、资料多、踩坑少。等跑顺了再考虑要不要换BanyanDB。
2.3 版本选择:别盲目追最新
SkyWalking的版本迭代挺快,但我不建议一上来就用最新版。原因很简单:探针和服务端有版本兼容矩阵,业务应用里挂的探针版本如果和服务端差太多,可能出现数据上报失败或者字段解析异常。稳妥的做法是:
- 服务端选一个近半年内的稳定版,比如9.x系列的某个小版本。
- 探针版本尽量和服务端保持同一大版本,小版本可以略有差异。
- 升级时先升服务端再升探针,或者灰度升级,别一次性全换。
另外要注意JDK版本。SkyWalking 9.x的OAP需要JDK 11或17,UI需要JDK 11+。如果你服务器上还是JDK 8,那得先装个新JDK,或者用Docker镜像省事。这一点很多人会忽略,启动报错才发现JDK不对。
2.4 部署方式:物理机、Docker还是K8s
部署方式取决于你的环境。如果是本地验证或者小规模测试,直接下载tar包解压启动最直观,能看到所有配置文件。如果团队已经在用容器化,那用Docker Compose或者K8s部署更规范,也方便后续扩缩容。
我个人的经验是:第一次搭建一定先用tar包手动跑一遍。因为手动跑你会被迫去读配置文件,理解每个参数的含义,遇到问题也知道去哪查。等手动跑通了,再改成Docker或K8s,心里有底。直接上K8s的话,一旦Pod起不来,排查链路太长,容易劝退。
3. 核心细节解析与实操要点
3.1 环境准备与依赖检查
动手之前先把环境理清楚。假设我们用Elasticsearch 7.x + SkyWalking 9.x + JDK 11这套组合,服务器配置建议至少4核8G起步,因为OAP和ES都比较吃内存。如果只是测试,2核4G也能跑,但数据量大了会卡。
需要提前确认的几件事:
- 端口占用:SkyWalking OAP默认监听11800(gRPC,探针上报用)和12800(HTTP,UI查询用),UI默认8080。ES默认9200。这些端口如果被占用,启动会失败。用
netstat -tlnp | grep 端口号检查一下。 - 时间同步:所有节点的时间必须一致,否则链路时间戳会乱,排查问题时对不上。建议开NTP。
- 文件句柄数:ES和OAP都会打开大量文件,
ulimit -n建议调到65535以上。 - 内存:OAP默认JVM堆是2G左右,ES默认1G,加起来至少3G,加上系统开销,8G内存比较稳。
提示:如果你在云服务器上部署,注意安全组要放行11800、12800、8080、9200这几个端口,否则探针连不上、UI打不开,会浪费很多时间排查。
3.2 Elasticsearch的安装与关键配置
ES是存储层,先把它跑起来。下载对应版本的tar包,解压后重点改config/elasticsearch.yml几个参数:
cluster.name: skywalking-es node.name: node-1 network.host: 0.0.0.0 http.port: 9200 discovery.type: single-node如果是单节点测试,加上discovery.type: single-node可以跳过集群发现配置,省事。生产环境要多节点,那就得配discovery.seed_hosts和cluster.initial_master_nodes。
还有一个必须改的地方:ES默认不允许用root用户启动,得建个普通用户,并且把数据目录和日志目录的权限给它。另外jvm.options里把堆内存设成物理内存的一半,但不要超过31G(压缩指针限制)。
启动ES后,用curl http://localhost:9200验证,返回JSON就说明通了。如果返回拒绝连接,看日志,大概率是内存不够或者权限问题。
3.3 SkyWalking服务端的下载与目录结构
SkyWalking的tar包解压后,目录结构是这样的:
bin/:启动脚本,oapService.sh启动OAP,webappService.sh启动UI。config/:核心配置,application.yml是OAP主配置,alarm-settings.yml是告警规则。oap-libs/:OAP依赖的jar包。webapp/:UI相关文件。agent/:探针目录,里面是agent的jar和配置。
先别急着启动,重点看config/application.yml。这个文件决定了OAP连哪个存储、监听哪个端口、集群怎么配。默认配置是H2,我们要改成ES。
3.4 探针接入的核心参数
探针接入业务应用时,核心就是几个启动参数。以Java应用为例,在启动命令里加-javaagent:
java -javaagent:/path/to/skywalking-agent/skywalking-agent.jar \ -Dskywalking.agent.service_name=your-service-name \ -Dskywalking.collector.backend_service=oap-host:11800 \ -jar your-app.jar这里有两个参数最关键:service_name是服务名,会显示在UI上,命名要规范,建议用应用名-模块名的格式;backend_service是OAP地址,多个OAP用逗号分隔。
探针的config/agent.config里还有很多可调参数,比如采样率、日志级别、忽略的URL等。默认采样率是-1,表示全量采集,生产环境如果流量大,建议调成具体数值比如1000,表示每1000条采1条,降低开销。
4. 实操过程与核心环节实现
4.1 第一步:启动Elasticsearch并验证
先把ES跑起来。假设装在/opt/elasticsearch,用普通用户启动:
su - esuser cd /opt/elasticsearch/bin ./elasticsearch -d-d是后台启动。等十几秒,然后验证:
curl -X GET "http://localhost:9200/_cluster/health?pretty"返回的status如果是green或yellow都算正常,yellow是因为单节点副本没分配,不影响使用。如果连不上,去logs/目录看日志,常见错误是max virtual memory areas vm.max_map_count太小,需要改系统参数:
sysctl -w vm.max_map_count=262144这个参数要写进/etc/sysctl.conf持久化,否则重启失效。
4.2 第二步:配置OAP连接ES
打开config/application.yml,找到storage部分,把默认的H2改成ES:
storage: selector: ${SW_STORAGE:elasticsearch} elasticsearch: namespace: ${SW_NAMESPACE:""} clusterNodes: ${SW_STORAGE_ES_CLUSTER_NODES:localhost:9200} protocol: ${SW_STORAGE_ES_HTTP_PROTOCOL:"http"} user: ${SW_ES_USER:""} password: ${SW_ES_PASSWORD:""} indexShardsNumber: ${SW_STORAGE_ES_INDEX_SHARDS_NUMBER:1} indexReplicasNumber: ${SW_STORAGE_ES_INDEX_REPLICAS_NUMBER:0}几个关键点:clusterNodes填ES地址,多个用逗号分隔;indexShardsNumber是分片数,单节点设1就行,生产环境根据数据量调大;indexReplicasNumber是副本数,单节点设0,生产环境至少1。
如果ES开了认证,user和password要填上。改完保存。
4.3 第三步:启动OAP并观察日志
启动OAP:
cd /opt/skywalking/bin ./oapService.sh启动过程会输出大量日志,重点看有没有Elasticsearch client connected之类的字样,以及有没有报错。如果看到Connection refused,说明ES地址不对或者ES没起来。如果看到index not found,别慌,OAP首次启动会自动创建索引,等一会儿就好。
OAP启动成功后,会监听11800和12800端口。用netstat确认一下:
netstat -tlnp | grep -E "11800|12800"两个端口都在监听,说明OAP正常。
4.4 第四步:启动UI并访问
启动UI:
./webappService.shUI默认监听8080。浏览器打开http://服务器IP:8080,应该能看到SkyWalking的界面。如果打不开,检查防火墙和端口。如果打开了但一片空白,大概率是UI连不上OAP,去看webapp/logs/下的日志,通常是backend_service配错了。
UI的配置文件在webapp/webapp.yml,里面有个collector.path指向OAP的12800端口,默认是http://127.0.0.1:12800。如果OAP和UI不在同一台机器,这里要改成OAP的实际地址。
4.5 第五步:接入探针并验证链路
服务端跑通后,找个测试应用挂上探针。最简单的办法是用SkyWalking自带的agent目录,把它拷到业务服务器上,然后在启动命令里加参数。启动应用后,随便访问几个接口,然后回到UI,在“拓扑图”里应该能看到服务节点,在“追踪”里能看到具体的链路。
如果UI里什么都没有,按这个顺序排查:探针日志有没有报错(在agent/logs/下)、backend_service地址对不对、OAP的11800端口通不通、服务名有没有配。这几个点查完,基本都能解决。
5. 常见问题与排查技巧实录
5.1 启动类问题速查表
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| OAP启动报端口占用 | 11800/12800被占 | netstat -tlnp查占用进程,杀掉或改端口 |
| OAP连不上ES | 地址错/ES没起/认证失败 | curl测ES,检查application.yml配置 |
| UI打开空白 | UI连不上OAP | 看webapp日志,检查webapp.yml的collector.path |
| 探针无数据 | backend_service错/端口不通 | 看agent日志,telnet测11800 |
| 链路时间乱 | 服务器时间不同步 | 检查NTP,统一时间 |
5.2 几个我踩过的坑
第一个坑:ES的index模板冲突。如果ES里之前有同名索引或者模板,OAP启动时创建索引会失败。解决办法是先把相关索引删掉,或者换个namespace。namespace这个参数就是给索引加前缀的,多套SkyWalking共用一个ES时特别有用。
第二个坑:探针版本和服务端不匹配。我有次用9.4的探针连9.0的服务端,数据能上报但部分字段解析不出来,UI上链路显示不全。后来把探针换成9.0就好了。所以探针和服务端大版本一定要一致。
第三个坑:JVM内存不够导致OAP频繁GC。OAP默认堆内存可能偏小,数据量大了之后GC频繁,表现为UI查询卡顿、数据延迟。解决办法是改bin/oapService.sh里的JAVA_OPTS,把-Xms和-Xmx调大,比如4G。但别超过物理内存,要给ES留够。
第四个坑:采样率没调导致业务变慢。默认全量采集,高并发场景下探针本身会消耗CPU和网络。生产环境一定要根据流量调采样率,比如agent.sample_n_per_3_secs设成几百,既能反映整体情况,又不至于压垮系统。
注意:改完任何配置都要重启对应组件,OAP改配置重启OAP,探针改配置重启业务应用。别改完不重启然后纳闷为什么没生效。
5.3 性能调优的几个方向
搭起来只是第一步,跑得稳才是关键。几个调优方向:
- OAP水平扩展:多个OAP实例通过集群模式共享存储,探针可以配多个backend_service做负载均衡。
- ES索引优化:调整分片数和副本数,定期清理过期索引(SkyWalking有TTL配置)。
- 探针降噪:忽略健康检查、静态资源等无意义请求,减少数据量。
- 告警配置:在
alarm-settings.yml里配好慢响应、错误率等规则,让系统主动通知你,而不是等用户投诉。
6. 搭建完成后的验证与日常维护
6.1 怎么确认整套系统真的通了
搭建完成后,别只看UI能打开就完事。我一般会做三层验证:
第一层,服务端自检。OAP日志里没有ERROR,ES的_cluster/health是green或yellow,UI能正常加载。
第二层,探针上报验证。挂一个测试应用,访问几个接口,UI的“服务”列表里能看到这个服务,“追踪”里能看到链路,链路的耗时和实际接口耗时对得上。
第三层,数据持久化验证。重启OAP,之前的数据还在,说明存储配置正确,不是用的内存。
这三层都过了,才算真正搭好。
6.2 日常维护要盯的几个点
SkyWalking跑起来之后,日常维护主要盯这几件事:
- 磁盘空间:ES数据会持续增长,要配TTL或者定期清理,不然磁盘满了整个系统就挂了。
- OAP和ES的GC情况:GC频繁说明内存不够,要及时调整。
- 探针版本一致性:业务应用升级时,探针版本要跟着规划,别出现版本碎片化。
- 告警规则有效性:定期回顾告警规则,避免误报太多导致大家麻木。
6.3 后续可以扩展的方向
搭好基础链路追踪后,还能往上叠不少能力。比如接入日志系统,把链路和日志关联起来,点一条链路就能看到对应的日志;比如接入指标系统,把JVM、系统指标也纳入监控;再比如做全链路压测,用SkyWalking的数据分析瓶颈。这些都是在基础搭建之上逐步演进的,不用一次到位。
我个人在实际操作中的体会是,SkyWalking搭建本身不难,难的是把配置理解透、把坑提前避开。很多人卡在存储选型和探针接入这两步,其实只要记住“生产用ES、探针和服务端版本一致、采样率按流量调”这三条,大部分问题都能绕过去。另外,第一次搭建一定要手动跑一遍,别直接上容器编排,手动跑通了你才知道每个组件在干什么,后面出问题也能快速定位。