skywalking
是一个优秀的国产开源框架,2015年由个人吴晟(华为开发者)开源 , 2017年加入Apache
孵化器。短短两年就被Apache
收入麾下,实力可见一斑。
skywalking
支持dubbo
,SpringCloud
,SpringBoot
集成,代码无侵入,通信方式采用GRPC
,性能较好,实现方式是java
探针,支持告警,支持JVM
监控,支持全局调用统计等等,功能较完善。
Skywalking
相比于zipkin
还是有很大的优势的,如下:
skywalking
采用字节码增强的技术实现代码无侵入,zipKin
代码侵入性比较高skywalking
功能比较丰富,报表统计,UI界面更加人性化skywalking
和zipkin
一样,也分为服务端和客户端,服务端负责收集日志数据并且展示,架构如下:
上述架构图中主要分为四个部分,如下:
Agent
:负责收集日志数据,并且传递给中间的OAP服务器
OAP
:负责接收 Agent
发送的 Tracing
和 Metric
的数据信息,然后进行分析(Analysis Core
) ,存储到外部存储器( Storage
),最终提供查询( Query
)功能。UI
:负责提供web
控制台,查看链路,查看各种指标,性能等等。Storage
:负责数据的存储,支持多种存储类型。看了架构图之后,思路很清晰了,Agent
负责收集日志传输数据,通过GRPC
的方式传递给OAP
进行分析并且存储到数据库中,最终通过UI界面将分析的统计报表、服务依赖、拓扑关系图展示出来。
skywalking
同样是通过jar
包方式启动,需要下载jar包,地址:https://skywalking.apache.org/downloads/
选择V9.5.0这个版本,如下图:
解压之后完整目录如下图:
重要的目录结构分析如下:
agent
:客户端需要指定的目录,其中有一个jar,就是负责和客户端整合收集日志skywalking8.7.0
之后的版本,agent
的相关代码被抽离出skywalking当中,需要自行下载agent
,从官网下载与之相对应的:https://skywalking.apache.org/downloads/bin
:服务端启动的脚本config
:一些配置文件的目录logs
:oap服务的日志目录oap-libs
:oap所需的依赖目录webapp
:UI服务的目录启动之前需要对配置文件做一些修改,修改如下:
这个是oap
服务的配置文件,需要修改注册中心为nacos
,如下图:
nacos
,这样就不用在启动参数中指定了。nacos
的相关配置这个是UI服务的配置文件,其中有一个server.port
配置,是UI服务的端口,默认8080
,将其改成8888,避免端口冲突,如下:
serverPort: ${SW_SERVER_PORT:-8888}
启动命令在/bin
目录下,这里需要启动两个服务,如下:
oap服务
:对应的启动脚本oapService.bat
,Linux下对应的后缀是sh
UI服务
:对应的启动脚本webappService.bat
,Linux下对应的后缀是sh
当然还有一个startup.bat
启动文件,可以直接启动上述两个服务,我们可以直接使用这个脚本,直接双击,将会弹出两个窗口则表示启动成功,如下图:
此时直接访问:http://localhost:8888/,直接进入UI端,如下图:
客户端也就是单个微服务,由于Skywalking
采用字节码增强技术,因此对于微服务无代码侵入,只要是普通的微服务即可,不需要引入什么依赖。
想要传输数据必须借助skywalking
提供的agent
,只需要在启动参数指定即可,命令如下:
-javaagent:D:\SoftWare\Tools\SkyWalking\skywalking-agent\skywalking-agent.jar
-Dskywalking.agent.service_name=skywalking-product-service
-Dskywalking.collector.backend_service=127.0.0.1:11800
上述命令解析如下:
-javaagent
:指定skywalking
中的agent
中的skywalking-agent.jar
的路径-Dskywalking.agent.service_name
:指定在skywalking
中的服务名称,一般是微服务的spring.application.name
-Dskywalking.collector.backend_service
:指定oap
服务绑定的地址,如果是本地,由于oap
服务默认的端口是11800
,因此只需要配置为127.0.0.1:11800
注意
:agent
的jar
包路径不能包含中文,不能有空格,否则运行不成功。
只要服务端重启之后,这些链路追踪数据将会丢失了,因为skywalking
默认持久化的方式是存储在内存中。
当然这里也是可以通过插拔方式的替换掉存储中间件,企业中往往是使用ES
存储,这里介绍一下MySQL的方式存储
修改 config/application.yml
文件中的存储方式,总共需要修改两处地方。
修改默认的存储方式为mysql,如下:
storage:
selector: ${SW_STORAGE:mysql}
默认的 oap
中是没有jdbc
驱动依赖,因此需要我们手动添加一下,只需要将驱动的jar放在oap-libs
文件夹中,如下图:
好了,已经配置完成,启动服务端,在skywalking
这个数据库中将会自动创建表,如下图:
在skywalking
的UI
端有一个日志的模块,用于收集客户端的日志,默认是没有数据的,那么需要如何将日志数据传输到skywalking
中呢?
日志框架的种类很多,比较出名的有log4j,logback,log4j2,那么就以logback
为例子介绍一下如何配置,官方文档如下:
log4j:https://skywalking.apache.org/docs/skywalking-java/v8.8.0/en/setup/service-agent/java-agent/application-toolkit-log4j-1.x/
log4j2:https://skywalking.apache.org/docs/skywalking-java/v8.8.0/en/setup/service-agent/java-agent/application-toolkit-log4j-2.x/
logback:https://skywalking.apache.org/docs/skywalking-java/v8.8.0/en/setup/service-agent/java-agent/application-toolkit-logback-1.x/
根据官方文档,需要先添加依赖,如下:
<dependency>
<groupId>org.apache.skywalkinggroupId>
<artifactId>apm-toolkit-traceartifactId>
<version>8.8.0version>
dependency>
<dependency>
<groupId>org.apache.skywalkinggroupId>
<artifactId>apm-toolkit-opentracingartifactId>
<version>8.8.0version>
dependency>
<dependency>
<groupId>org.apache.skywalkinggroupId>
<artifactId>apm-toolkit-logback-1.xartifactId>
<version>8.8.0version>
dependency>
新建一个logback-spring.xml
放在resource
目录下,配置如下:
点击此处了解logback.xml文件解析
<configuration scan="true" scanPeriod=" 5 seconds">
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.mdc.TraceIdMDCPatternLogbackLayout">
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{tid}] [%thread] %-5level %logger{36} -%msg%nPattern>
layout>
encoder>
appender>
<appender name="grpc-log" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.mdc.TraceIdMDCPatternLogbackLayout">
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{tid}] [%thread] %-5level %logger{36} -%msg%nPattern>
layout>
encoder>
appender>
<appender name="fileAppender" class="ch.qos.logback.core.FileAppender">
<file>./logs/gateway-all.logfile>
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
<Pattern>[%sw_ctx] [%level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %logger:%line - %msg%nPattern>
layout>
encoder>
appender>
<root level="INFO">
<appender-ref ref="stdout"/>
<appender-ref ref="grpc-log"/>
root>
<logger name="fileLogger" level="INFO">
<appender-ref ref="fileAppender"/>
logger>
configuration>
注意
:如果agent
和oap
服务不在同一台服务器上,需要在/agent/config/agent.config
配置文件末尾添加如下配置:
plugin.toolkit.log.grpc.reporter.server_host=${SW_GRPC_LOG_SERVER_HOST:10.10.10.1}
plugin.toolkit.log.grpc.reporter.server_port=${SW_GRPC_LOG_SERVER_PORT:11800}
plugin.toolkit.log.grpc.reporter.max_message_size=${SW_GRPC_LOG_MAX_MESSAGE_SIZE:10485760}
plugin.toolkit.log.grpc.reporter.upstream_timeout=${SW_GRPC_LOG_GRPC_UPSTREAM_TIMEOUT:30}
配置分析如下:
配置名 | 解释 | 默认值 |
---|---|---|
plugin.toolkit.log.transmit_formatted | 是否以格式化的格式传输记录的数据 | TRUE |
plugin.toolkit.log.grpc.reporter.server_host | 指定要向其报告日志数据的grpc服务器的主机 | 127.0.0.1 |
plugin.toolkit.log.grpc.reporter.server_port | 指定要向其报告日志数据的grpc服务器的端口 | 11800 |
plugin.toolkit.log.grpc.reporter.max_message_size | 指定grpc客户端要报告的日志数据的最大大小 | 10485760 |
plugin.toolkit.log.grpc.reporter.upstream_timeout | 客户端向上游发送数据时将超市多长时间,单位:秒 | 30 |
skywalking
在性能剖析方面真的是非常强大,提供到基于堆栈的分析结果,能够让运维人员一眼定位到问题。
假如一个/order/list接口有超时,如下:
@GetMapping("/list")
public List<Order> list() throws InterruptedException{
Thread.sleep(2000);
return LongStream.of(1,2,3).mapToObj(id->new Order(id,20231000L,"test","test")).collect(Collectors.toList());
}
上述代码中休眠了2秒,看看如何在skywalking
中定位这个问题。
在性能剖析模块->新建任务->选择服务、填写端点、监控时间,操作如下图:
上图中选择了最大采样数为5,则直接访问5次:http://localhost:1003/order/list,然后选择这个任务将会出现监控到的数据,如下图:
上图中可以看到{GET}/order/list这个接口上耗费了2秒以上,因此选择这个接口点击分析,可以看到详细的堆栈信息,如下图:
是不是很清楚了,在OrderController这个接口线程睡眠了两秒…
对于服务的异常信息,比如接口有较长延迟,skywalking
也做出了告警功能,如下图:
skywalking
中有一些默认的告警规则,如下:
当然除了以上四种,随着Skywalking
不断迭代也会新增其他规则,这些规则的配置在config/alarm-settings.yml
配置文件中,如下:
# Sample alarm rules.
rules:
# Rule unique name, must be ended with `_rule`.
service_resp_time_rule:
metrics-name: service_resp_time
op: ">"
threshold: 1000
period: 10
count: 3
silence-period: 5
message: Response time of service {name} is more than 1000ms in 3 minutes of last 10 minutes.
service_sla_rule:
# Metrics value need to be long, double or int
metrics-name: service_sla
op: "<"
threshold: 8000
# The length of time to evaluate the metrics
period: 10
# How many times after the metrics match the condition, will trigger alarm
count: 2
# How many times of checks, the alarm keeps silence after alarm triggered, default as same as period.
silence-period: 3
message: Successful rate of service {name} is lower than 80% in 2 minutes of last 10 minutes
service_resp_time_percentile_rule:
# Metrics value need to be long, double or int
metrics-name: service_percentile
op: ">"
threshold: 1000,1000,1000,1000,1000
period: 10
count: 3
silence-period: 5
message: Percentile response time of service {name} alarm in 3 minutes of last 10 minutes, due to more than one condition of p50 > 1000, p75 > 1000, p90 > 1000, p95 > 1000, p99 > 1000
service_instance_resp_time_rule:
metrics-name: service_instance_resp_time
op: ">"
threshold: 1000
period: 10
count: 2
silence-period: 5
message: Response time of service instance {name} is more than 1000ms in 2 minutes of last 10 minutes
database_access_resp_time_rule:
metrics-name: database_access_resp_time
threshold: 1000
op: ">"
period: 10
count: 2
message: Response time of database access {name} is more than 1000ms in 2 minutes of last 10 minutes
endpoint_relation_resp_time_rule:
metrics-name: endpoint_relation_resp_time
threshold: 1000
op: ">"
period: 10
count: 2
message: Response time of endpoint relation {name} is more than 1000ms in 2 minutes of last 10 minutes
webhooks:
# - http://127.0.0.1/notify/
# - http://127.0.0.1/go-wechat/
每个规则都由相同的属性组成,这些属性的含义如下图:
属性 | 含义 |
---|---|
metrics-name | oal脚本中度量名称 |
threshold | 阈值,与metrics-name和下面的比较符号相匹配 |
op | 比较操作符号,可以设定>,<,= |
period | 多久检查一次当前的指标数据是否符合告警规则,单位:分钟 |
count | 达到多少次后,发送告警消息 |
silence-period | 在多久之内,忽略相同告警信息 |
message | 告警消息内容 |
include-names | 本规则告警生效服务列表 |
如果想要调整默认的规则,比如监控返回的信息,监控的参数等等,只需要改动上述配置文件中的参数即可。
当然除了以上默认的几种规则,skywalking
还适配了一些钩子(webhooks
)。其实就是相当于一个回调,一旦触发了上述规则告警,skywalking
则会调用配置的webhook
,这样开发者就可以定制一些处理方法,比如发送邮件、微信、钉钉通知运维人员处理。
当然这个钩子也是有些规则的,如下:
注意
:AlarmMessage
这个类随着skywalking
版本的迭代可能出现不同,一定要到对应版本源码中去找到这个类,拷贝其中的属性。这个类在源码的路径:org.apache.skywalking.oap.server.core.alarm,如下图:
新建一个告警模块:skywalking-alarm1004,其中利用webhook
定义一个接口,如下:
@RestController
@RequestMapping("/alarm")
@Slf4j
public class AlarmController{
// skywalking回调触发方法
@PostMapping("/receive")
public void receive(@RequestBody List<AlarmMessage> list){
//todo 此处可以填写发送邮件,微信,钉钉
log.info("------------------");
log.info(JSON.toJSONString(list));
}
}
接口定制完成后,只需要在config/alarm-settings.yml
配置文件中添加这个钩子,如下图:
webhooks:
- http://127.0.0.1:1004/alarm/receive
# - http://127.0.0.1/go-wechat/
好了,这就已经配置完成了,测试也很简单,还是调用上面案例中的睡眠两秒的接口:http://localhost:1003/order/list,多调用几次,则会触发告警,控制台打印日志如下: