SkyWalking
SkyWalking 不是传统意义上的中间件,但属于分布式追踪系统,主要用于监控微服务架构中的服务调用链路和性能分析。它提供分布式追踪、服务网格遥测分析、度量聚合和可视化一体化解决方案,支持微服务、云原生架构,提供了总览、拓扑、应用、服务视图及链路追踪、告警等功能,能够串联用户请求到后端各系统节点的处理流程,帮助快速定位问题。
参考文章:
SkyWalking
应用监控和链路跟踪
随着微服务架构的流行,开发的运维压力增大,经常需要面临这些问题:
- 链路较长:在微服务场景下,整个链路会变得很长,服务出问题时,往往不能第一时间排查出问题。
 - 缺少监控:缺少对于服务器,应用组件的实时运行信息,做到心中有数。
 - 预警不及时,粒度较大:经常在服务器响应延迟甚至宕机后,才能发现问题,同时粒度较大,无法在接口层面进行预警。
 
基于Agent技术,SkyWalking提供了例如吞吐量,QPS,JVM信息等丰富的指标供参考,做到有效同时地告警,利用其丰富的插件,能帮助我们跟踪Dubbo,ElasticSearch,Redis等这些组件的调用链路。 通过SkyWalking做链路跟踪,系统监控,异常告警的落地,解决了开发过程中问题定位慢的痛点。
整个分布式追踪的目的是为了最终在页面上、UI上、和数据上能够复现分布式系统中服务调用的整个过程。在做分布式追踪时需要拿到完整的信息,包括精确的响应时间,访问的方法、访问的 circle,访问的 Redis 的 key等,最终展现出一个完整的链路。
一个请求完整的调用链路: 那么在业务规模不断增大,服务不断增多以及频繁变更的情况下,面对复杂的调用链路就带来一系列问题:
- 如何快速发现问题?
 - 如何判断故障影响范围?
 - 如何梳理服务依赖以及依赖的合理性?
 - 如何分析链路性能以及实时容量规划?
 - 吞吐量,根据拓扑可计算相应组件,平台,物理设备的实时吞吐量
 - 响应时间,包括整体调用的响应时间和各个服务的响应时间等。
 - 错误记录,根据服务返回统计单位时间异常次数。
 
全链路性能监控从整体维度到局部维度展示各个指标,将跨应用的所有调用链路性能信息集中展现,可方便度量整体和局部性能,并且方便找到故障产生的源头,生产上可极大缩短故障排查时间。 有了全链路监控工具,能够达到:
- 请求链路跟踪,故障快速定位:可以通过调用链路结合业务日志快速定位错误信息。
 - 可视化:各个阶段耗时,进行性能分析
 - 依赖优化:各个调用环节的可用性,梳理服务依赖关系以及优化
 - 数据分析,优化链路:可以得到用户的行为路径,汇总分析应用在很多业务场景。
 
APM
APM(Application Performance Management)应用性能管理,通过各种探针采集并上报数据,收集关键指标,同时搭配数据展示以实现对应用程序性能管理和故障管理的系统化解决方案。
目前主要的一些 APM 工具有:Cat、Zipkin、Pinpoint、SkyWalking,这里主要介绍 SkyWalking ,它是一款优秀的国产 APM 工具,包括了分布式追踪、性能指标分析、应用和服务依赖分析等。
Zabbix、Premetheus、open-falcon等监控系统主要关注服务器硬件指标与系统服务运行状态等,而APM系统则更重视程序内部执行过程指标和服务之间链路调用情况的监控,APM更有利于深入代码找到请求响应“慢”的根本问题,与 Zabbix 之类的监控是互补关系。
Apache SkyWalking(Incubator)
Apache SkyWalking:
分布式系统的应用程序性能监视工具,专为微服务、云原生架构和基于容器(Docker、K8s、Mesos)架构而设计。
Apache Skywalking(Incubator) 专门为微服务架构和云原生架构系统而设计并且支持分布式链路追踪的APM系统。Apache Skywalking(Incubator)通过加载 探针-非侵入式 的方式收集应用调用链路信息,并对采集的调用链路信息进行分析,生成应用间关系和服务间关系以及服务指标。
Apache Skywalking (Incubating)目前支持多种语言,其中包括Java,.Net Core,Node.js和Go语言。
Skywalking已经支持从6个可视化维度剖析分布式系统的运行情况。
- 总览视图(
Global view)是应用和组件的全局视图,其中包括组件和应用数量,应用的告警波动,慢服务列表以及应用吞吐量; - 拓扑图(
topology view)从应用依赖关系出发,展现整个应用的拓扑关系; - 应用视图则是从单个应用的角度,展现应用的上下游关系,TopN的服务和服务器,JVM的相关信息以及对应的主机信息。
 - 服务视图关注单个服务入口的运行情况以及此服务的上下游依赖关系,依赖度,帮助用户针对单个服务的优化和监控;
 - 调用链(
trace)展现了调用的单次请求经过的所有埋点以及每个埋点的执行时长; - 告警视图(
alarm)根据配置阈值针对应用、服务器、服务进行实时告警。 
什么是 SkyWalking
- 是观察性分析平台和应用性能管理系统。
 - 提供分布式追踪、服务网格遥测分析、度量聚合和可视化一体化解决方案
 - 支持Java, .Net Core,PHP,NodeJS,Golang,LUA语言探针
 - 支持
Envoy + Istio构建的 Service Mesh 
javaAgent探针技术使用场景
- 无入侵 链路跟踪
 - 无入侵 动态线程池
 - 无入侵  
TransmitThreadLocal - 无入侵的 命令行交互模式JVM诊断Arthas
 
SkyWalking 原理架构图

SkyWalking支持三种探针:
- Agent:基于ByteBuddy字节码增强技术实现,通过jvm的agent参数加载,并在程序启动时拦截指定的方法来 收集数据。 (最推荐)
 - SDK:程序中显式调用SkyWalking提供的SDK来收集数据,对应用有侵入。
 - Service Mesh:通过Service mesh的网络代理来收集数据。
 
后端(Backend)
接受探针发送过来的数据,进行度量分析,调用链分析和存储。后端主要分为两部分:
OAP(Observability Analysis Platform):进行度量分析和调用链分析的后端平台,并支持将数据存储到各种数据库中,如:ElasticSearch,MySQL,InfluxDB等。
OAL(Observability Analysis Language):用来进行度量分析的DSL,类似于SQL,用于查询度量分析结果和警报。
SkyWalking 核心模块
SkyWalking采用组件式开发,易于扩展,主要组件作用如下:
- Skywalking Agent:链路数据采集tracing(调用链数据)和metric(指标)信息并上报,上报通过HTTP或者 gRPC 方式发送数据到Skywalking Collector
 - Skywalking Collector : 链路数据收集器,对agent传过来的
tracing和metric数据进行整合分析通过Analysis Core模块处理并落入相关的数据存储中,同时会通过Query Core模块进行二次统计和监控告警 - Storage: Skywalking的存储,支持以
ElasticSearch、Mysql、TiDB、H2等主流存储作为存储介质进行数据存储,H2仅作为临时演示单机用。 - SkyWalking UI: Web可视化平台,用来展示落地的数据,目前官方采纳了
RocketBot作为SkyWalking的主UI 
SkyWalking UI组件视图
仪表盘:查看全局服务基本性能指标 仪表盘主要包含Service Dashboard和Database Dashboard
Service Dashboard:有Global、Service、Endpoint、Instance面板,展示了全局以及服务、端点、实例的详细信息
Database Dashboard:展示数据库的响应时间、响应时间分布、吞吐量、SLA、慢SQL等详细信息,便于直观展示数据库状态
拓扑图:展示分布式服务之间调用关系:
SkyWalking 能根据获取的数据自动绘制服务之间的调用关系图,并识别常见的服务显示在图标上,如 tomcat、CAS 服务
每条连线的颜色反应了服务之间的调用延迟情况,可以非常直观的看到服务与服务之间的调用状态,连线中间的点能点击,可显示两个服务之间链路的平均响应时间、吞吐率以及SLA等信息,还可以展示服务的性能数据。
链路追踪:可以根据需求,查看链路调用过程
- 显示请求的响应内部执行情况,一个完整的请求都经过了哪些服务、执行了哪些代码方法、每个方法的执行时间、执行状态等详细信息,快速定位代码问题。
 
- 告警提示
 - 指标数据对比
 
SkyWalking的特点
- 性能好:针对单实例5000tps的应用,在全量采集的情况下,只增加10%的CPU开销
 - 支持多语言探针
 - 无入侵,支持自动以及手动探针
 
自动探针:java支持的中间件,框架与类库列表
手动探针:OpenTrackingApi,@Trace注解,traceId集成到日志中
SkyWalking三大架构模式
- AOP架构模式
 - 插件式架构模式
 - 微内核架构模式
 
一个组件具有高扩展架构的话,需要具有微内核架构/插件式架构/无入侵架构,例如:
1  | 高扩展架构  | 
SkyWalking 安装部署
存储到ES需要先安装 ElasticSearch
SkyWalking 安装
下载 压缩包
解压安装包
1
2
3
4
5
6
7[root@example apache-skywalking-apm-bin]# tar -xvf apache-skywalking-apm-6.6.0.tar.gz -C /opt/
# ll 查看详细列表
agent # 探针客户端,Java -jar启动时参数指向agent里面的skywalking探针jar包
bin # 启动脚本
config # skyWalking 配置目录
logs # 日志目录
webapp # skyWalking ul配置UI端口
config:配置文件,主要修改application.yml里的agent采集的信息要存存储到哪里,默认H2,现改为ES。修改namespace为ES集群名,clusterNodes为ES集群各节点URL即可,其他暂时默认即可。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19storage:
selector: ${SW_STORAGE:elasticsearch7}
elasticsearch7:
namespace: ${NAMESPACE:"elasticsearch"}
clusterNodes: ${SSW_STORAGEE_ES_CLUSTER_NODES:localhost:9200}
protocol: ${SSW_STORAGE_ES_HTTP_PROTOCOL:"http"}
trustStorePath: ${SISW_STORAGE_ES_SSL_JKS_PATH:""}
trustStorePass: ${SISW_STORAGE_ES_SSL_JKS_PASS:""}
# Represent the number of days in the one minute/hour/day index.
dayStep: ${SW_STORAGE_DAY_STEP:l}
user: ${SW_ES_USER:""}
password: ${SW_ES_PASSWORD:""]
# segmentQueryMaxSize: ${SW_STORAGE_ES_QUERY_SEGMENT_SIZE:200}
h2:
driver: ${SW_STORAGE_H2_DRIVER:org.h2.jdbcx.JdbcDataSource}
url: ${SW_STORAGE_H2_URL:jdbc:h2:mem:skywalking-oap-db}
user: ${SW_STORAGE_H2_USER:sa}
metadataQueryMaxSize: ${SW_STORAGE_H2_QUERY_MAX_SIZE:5000}webapp:将ES里的数据展示出来的UI项目基本配置,修改一下webapp.yml的server.port端口,默认8080
1
2
3
4
5
6
7
8server:
port: 8080 # 最好是改掉,因默认8080端口经常被占用,比如 8888
collector:
path: /graphql
ribbon:
ReadTimeout: 10000
# Point to all backend's restHost:restPort, split by
listofservers: 127.0.0.1:12800bin启动脚本,startup.sh同时启动 oap(主要是将探针采集的数据上传到ES)和webapp(相当于zipkin-ui)两个服务,也可单独启动。注意:.bat 为windows 启动脚本;.sh为Linux 启动脚本;
1
2
3
4
5
6
7
8
9
10
11
12[root@example apache-skywalking-apm-bin]# ll bin
total 40
-rwxr-xr-x. 1 nginx 1002 1352 Dec 24 01:10 oapService.bat
-rwxr-xr-x. 1 nginx 1002 1364 Dec 24 01:10 oapServiceInit.bat
-rwxr-xr-x. 1 nginx 1002 1597 Dec 24 01:10 oapServiceInit.sh
-rwxr-xr-x. 1 nginx 1002 1367 Dec 24 01:10 oapServiceNoInit.bat
-rwxr-xr-x. 1 nginx 1002 1616 Dec 24 01:10 oapServiceNoInit.sh
-rwxr-xr-x. 1 nginx 1002 1599 Dec 24 01:10 oapService.sh # oapService 服务启动脚本
-rwxr-xr-x. 1 nginx 1002 941 Dec 24 01:10 startup.bat
-rwxr-xr-x. 1 nginx 1002 934 Dec 24 01:10 startup.sh # 启动oap 和UI 服务
-rwxr-xr-x. 1 nginx 1002 1426 Dec 24 01:10 webappService.bat
-rwxr-xr-x. 1 nginx 1002 1630 Dec 24 01:10 webappService.sh # Web UI 启动脚本默认使用H2存储,启动SkyWalking的UI控制台,出现如下则证明启动成功,即可通过http://localhost:8080 访问Web UI。如果启动失败,查询apache-skywalking-apm-bin/logs目录下日志skywalking-oap-server.log和SkyWalking UI日志webapp.log,跟进错误提示进行分析。
1
2
3[root@example apache-skywalking-apm-bin]# bin/startup.sh
SkyWalking OAP started successfully!
SkyWalking Web Application started successfully!配置后端存储
JavaAgent 部署
通过操作 Instrumentation 的 API 就可以实现不重启服务对单个类进行简单的修改。 通常有两种方式拿到 Instrumentation 对象:
- 在 JVM 启动时指定 agent,Instrumentation 对象会通过 agent 的 premain 方法传递。
 - 在 JVM 启动后通过 JVM 提供的机制加载 agent,Instrumentation 对象会通过 agent 的 agentmain 方法传递。
 
Skywalking 就是通过在 JVM 启动时指定 agent,这样其实对于业务来说会减少一些不确定性,如果在运行期间侵入,至少在启动的过程中能预判一些不确定性,具体详情代码请参考:org.apache.skywalking.apm.agent.SkyWalkingAgent。
业务应用在 Skywalking 中如何被零侵入,配置属性文件 env.properties,内容如下,注意将 skywalking-agent.jar 放到指定的路径上。
1  | JAVA_HOME="/data/java/jdk1.8.0_161"  | 
部署 JavaAgent 探针流程:
1  | # 1.Agent 用于JDK1.6-12  | 
Agent包:
1  | +-- agent  | 
高级功能:
1  | # 1.默认日志输出到 logs 目录下。  | 
在Tomcat 上部署 JavaAgent
上传Agent目录到指定的Tomcat 器
1  | [root@localhost opt]# ll  | 
配置Agent配置文件,conf/agent.conf 设置agent.service_name、collector.backend_service;
1  | [root@localhost opt]# vim /opt/agent/config/agent.config  | 
启动Tomcat服务。
在远程SkyWalking 服务器通过端口查看:
1  | [root@example ~]# netstat -natpl| grep java  | 
启动顺序
- 先启动 
ElasticSearch - 再启动 
SkyWalking - 最后启动加入探针的微服务程序
 
其他配置案例
SpringCloud集成SkyWalking
下载解压apache-skywalking-apm-bin,比如安装解压在 D:/IDEA/skywalking/apache-skywalking-apm-bin
更新SpringBoot启动参数,可以在IDEA里面直接添加
1
2
3-javaagent:D:/IDEA/skywalking/apache-skywalking-apm-bin/agent/skywalking-agent.jar
-Dskywalking.agent.service_name=test-demo-eureka # 名称自定义,一般和application.name一致
-Dskywalking.collector.backend_service=localhost:11800 # 端口IP指向部署skywalking,skywalking-oap重新启动应用,再Skywalking管理台查看服务和应用探针是否正常
在Java服务中配置 Agent
参考文章skywalking的接入微服务、推荐文章通过SkyWalking上报Java应用数据
1.配置
将apache-skywalking-apm-bin/agent下文件copy到Java服务器上,放到指定目录下,配置agent/config/agent.config,设置skywalking服务地址,见下:
1  | # The service name in UI  | 
在agent.service_name配置你的服务名称,用于在skywalking UI显示,配置collector.backend_service选项,配置skywalking服务地址和端口,用于agient上报数据。
2.启动
在java启动命令里加上 -javaagent:[jar包目录]/agent/skywalking-agent.jar
启动完成后,可以观察 Web UI看数据是否上报OK
Docker部署Agent
下载镜像:我本地下载的镜像打了tag
1
2docker pull registry.cn-hangzhou.aliyuncs.com/anoy/skywalking-ui
docker pull registry.cn-hangzhou.aliyuncs.com/anoy/skywalking-oap运行镜像:账户密码(admin/admin,密码自己定义)
1
2docker run -d --name skywalking-oap -p 11800:11800 -e TZ=Asia/Shanghai skywalking-oap
docker run -d --name skywalking-ui --link skywalking-oap:skywalking-oap -p 8088:8080 -e TZ=Asia/Shanghai skywalking-ui --collector.ribbon.listOfServers=skywalking-oap:12800 --security.user.admin.password=admin查看应用是否正常启动
SkyWalking 透传 kafka的 Agent
安装Kafka和Zookeeper
Kafka和Zookeeper是SkyWalking使用Kafka进行数据传输所必需的。
移动Kafka插件
将Kafka插件移动到plugins目录:将SkyWalking agent的optional-reporter-plugins目录下的kafka-reporter-plugin-x.x.x.jar(x.x.x代表版本号)移动到plugins目录下。
1
mv optional-reporter-plugins/kafka-reporter-plugin-x.x.x.jar plugins/
编辑agent.conf
在SkyWalking agent的config目录下,找到agent.conf配置文件。需要添加或修改以下配置项以启用Kafka上报:
1
2
3
4
5
6
7
8
9# agent.conf 文件中的部分配置
plugin.kafka.bootstrap_servers=localhost:9092
plugin.kafka.namespace=skywalking-logs
# 另外配置了地址的,用引用方式
# 配置Kafka服务地址
plugin.kafka.bootstrap_servers=${SW_KAFKA_BOOTSTRAP_SERVERS:localhost:9092}
# 配置Kafka的Topic
plugin.kafka.namespace=${SW_KAFKA_NAMESPACE:skywalking-logs}注意:确保Kafka服务正在运行,并且你使用的端口与bootstrap_servers配置中的端口相匹配。
启动应用:
使用带有SkyWalking agent的JVM参数启动你的应用。SkyWalking agent将开始收集数据,并通过Kafka发送到OAP服务器。验证Kafka透传是否成功
要验证Kafka透传是否成功,你可以使用Kafka命令行工具来检查数据是否已被成功发送到指定的Topic中。你可以使用如下命令:
1  | ./kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic skywalking-logs --from-beginning  | 
如果一切配置正确,你将能看到SkyWalking agent发送的跟踪数据在控制台上滚动显示。
skywalking监控中间件redis
配置SkyWalking Agent:步骤同上 Java Agent 部署
配置Redis
在监控Redis之前,需要为Redis启用Trace功能,并配置Trace的采样率。 对于使用Spring Boot的应用程序,你可以在
application.properties文件中添加以下配置:1
2
3
4
5
6# 服务名称
spring.application.name=your-application-name
# SkyWalking配置
skywalking.trace.redis.host=your-redis-host
skywalking.trace.redis.port=your-redis-port
skywalking.trace.redis.sample-rate=0.5启动SkyWalking Agent
在Agent安装目录下,找到skywalking-agent.jar的文件。通过以下命令启动Agent:
1
java -jar skywalking-agent.jar
查看监控数据
一旦SkyWalking Agent启动成功,它将会开始收集和发送监控数据到SkyWalking服务器。 你可以通过访问SkyWalking的Web界面来查看监控数据。在浏览器中输入http://localhost:8080,即可访问SkyWalking的控制台。 在控制台中选择查看Redis相关的监控数据,如请求数、响应时间等。
SkyWalking探针采集数据如何收集
既然是分布式链路平台,那么数据收集肯定的核心功能,在 Skywalking 中,数据是通过探针侵入业务,然后通过通信通道传输到 OAP Server 端。针对每一个探针,其实收集的逻辑都不太一样,这里我就重点分析下常用技术中间件的探针数据是如何收集的。
gateway-2.1.x-plugin
Spring Cloud Gateway 是一个非常火的服务治理网关,所以 Skywalking 肯定是要支持对它的性能数据的采集。
- 定义探针 
FilteringWebHandlerInstrumentation,用于增强 org.springframework.cloud.gateway.handler.FilteringWebHandler,拦截 FilteringWebHandler 中以 handle 开头的方法。 - 定义拦截器 
FilteringWebHandlerInterceptor,在 beforeMethod 方法中植入需要采集的数据,从 allArguments 参数中,获取到当前网关路由的 ServerWebExchange,然后拼装 operationName,例如: operationName + route.getId()。 - **
HttpClientOperationsSendInterceptor**,创建 AbstractSpan 并设置组件类型为 ComponentsDefine.SPRING_CLOUD_GATEWAY,最后调用 ContextManager.stopSpan(span) 存储链路数据。 
dubbo-2.7.x-plugin
Dubbo 框架肯定是得支持的,如何支持?
- 定义探针 
DubboInstrumentation,并增强类 org.apache.dubbo.monitor.support.MonitorFilter,这个类是 Dubbo 服务治理的核心类,拦截的方法必须是要含有 invoke 字段。 - 拦截器 
DubboInterceptor,通过 beforeMethod,获取到 Invoker、Invocation 和 RpcContext,然后再区分是消费者还是提供者,如果是消费者,那么就是 ExitSpan,如果是提供者就是 EntrySpan,从链路数据流向来看,消费者是出去,而提供者流量是流入。createExitSpan 和 createEntrySpan,就会植入一些性能采集指标,比如 RT 等。 
jedis-2.x-plugin
- 定义探针:
JedisInstrumentation,这个探针用于植入类 redis.clients.jedis.Jedis。 - 定义一批特殊处理的拦截器——最常规的拦截器就是 
JedisMethodInterceptor,并通过 beforeMethod、afterMethod 和 handleMethodException 采集链路信息。 
其他组件基本都是一样的,都是通过基于字节码的 AOP 技术来植入链路采集数据。
关于 Skywalking 探针的链路数据采集我们需要知道底层核心,我在这里就列举下:
StaticMethodsInter
用于拦截类实例方法的实际字节 buddy 拦截器。这个类用于连接 Byte-buddy 和 Skywalking plugin。
ConstructorInter
用于拦截构造函数方法的实际字节 buddy 拦截器,然后通过自定义 intercept 方法逻辑,调用拦截器的 onConstruct 逻辑,完成基于构造函数的请求拦截。
InstMethodsInter
用于拦截实例方法的实际字节 buddy 拦截器,自定义 intercept 方法,然后再方法中国封装拦截器对 beforeMethod、handleMethodException 和 afterMethod 这三个方法的调用。



