日志之SkyWalking使用讲解
skywalking是一个优秀的国产开源框架,2015年由个人吴晟(华为开发者)开源 , 2017年加入Apache孵化器。短短两年就被Apache收入麾下,实力可见一斑。skywalking支持dubboSpringBoot集成,代码无侵入,通信方式采用GRPC,性能较好,实现方式是java探针,支持告警,支持JVM监控,支持全局调用统计等等,功能较完善。
文章目录
1 SkyWalking
1.1 简介
skywalking
是一个优秀的国产开源框架,2015年由个人吴晟(华为开发者)开源 , 2017年加入Apache
孵化器。短短两年就被Apache
收入麾下,实力可见一斑。
skywalking
支持dubbo
,SpringCloud
,SpringBoot
集成,代码无侵入,通信方式采用GRPC
,性能较好,实现方式是java
探针,支持告警,支持JVM
监控,支持全局调用统计等等,功能较完善。
1.2 如何选择
1.2.1 与zipkin相比
Skywalking
相比于zipkin
还是有很大的优势的,如下:
skywalking
采用字节码增强的技术实现代码无侵入,zipKin
代码侵入性比较高
点击此处了解 SpringCloud之Sleuth+ZipKin全链路日志跟踪skywalking
功能比较丰富,报表统计,UI界面更加人性化
1.2.2 与ELK相比
各个特点:
SkyWalking
: 专注于应用性能监控(APM)的系统,主要提供分布式追踪、服务性能分析和多维度监控功能。
它支持自动化代码埋点,能够追踪微服务之间的调用关系和性能指标。ELK
:日志数据的集中管理和分析,Elasticsearch + Logstash + Filebeat,作为日志采集和存储,Kibana 作为可视化日志检索平台。
1.2.3 只用 SkyWalking 可以吗
SkyWalking
优点是服务性能分析和链路追踪,但也有不足之处。
采集方式上不足
Skywalking
监控 Java、Golang、Node、.NET 语言的链路都是采用了 SDK 或者 Agent 的方式将数据上报到 Skyalking 后端,不过都是采用 gRPC 的方式和后端交互,比如 Java 项目,SkyWalking Agent
采集到后端的 Java 日志后进行上报。而对于 Nginx 则需要写 Lua 脚本来和 SkyWalking AOP 服务通信,对于 MySQL 日志也需要单独写脚本来上报日志。
数据可视化的不足
SkyWalking
对于链路的展示非常直观,但是对于日志的数据的展示探索能力很弱,而 Kibana 提供了丰富的可视化选型,如折线图、饼图等。
SkyWalking 对于日志的搜索和展示能力较弱,而 Kibana 对于搜索的方式非常丰富,而且支持高亮。
1.3 Skywalking架构
skywalking
和zipkin
一样,也分为服务端和客户端,服务端负责收集日志数据并且展示,架构如下:
上述架构图中主要分为四个部分,如下:
- 最上面的
Tracing
:负责从应用中,收集链路信息,发送给SkyWalking OAP
服务器,目前支持SkyWalking、Zikpin、Jaeger
等提供的 Tracing 数据信息。一般采用的是SkyWalking Agent
收集SkyWalking Tracing
数据,传递给SkyWalking OAP
服务器。 - 中间的
OAP
:负责接收Agent
发送的Tracing
和Metric
的数据信息,然后进行分析(Analysis Core
) ,存储到外部存储器(Storage
),最终提供查询(Query
)功能。 - 左面的
UI
:负责提供web
控制台,查看链路,查看各种指标,性能等等。 - 右面
Storage
:负责数据的存储,支持多种存储类型。目前支持 ES、MySQL、Sharding Sphere、TiDB、H2 多种存储器。
看了架构图之后,思路很清晰了,Agent
负责收集日志传输数据,通过GRPC
的方式传递给OAP
进行分析并且存储到数据库中,最终通过UI界面将分析的统计报表、服务依赖、拓扑关系图展示出来。
1.4 服务端搭建
skywalking
同样是通过jar
包方式启动,需要下载jar包,地址:https://skywalking.apache.org/downloads/
1.4.1 下载安装包
选择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服务的目录
1.4.2 配置修改
启动之前需要对配置文件做一些修改,修改如下:
1.4.2.1 config/application.yml
这个是oap
服务的配置文件,需要修改注册中心为nacos
,如下图:
- 配置①:修改默认注册中心选择
nacos
,这样就不用在启动参数中指定了。 - 配置②:修改
nacos
的相关配置
1.4.2.2 webapp/webapp.yml
这个是UI服务的配置文件,其中有一个server.port
配置,是UI服务的端口,默认8080
,将其改成8888,避免端口冲突,如下:
serverPort: ${SW_SERVER_PORT:-8888}
1.4.3 启动服务
启动命令在/bin
目录下,这里需要启动两个服务,如下:
oap服务
:对应的启动脚本oapService.bat
,Linux下对应的后缀是sh
UI服务
:对应的启动脚本webappService.bat
,Linux下对应的后缀是sh
当然还有一个startup.bat
启动文件,可以直接启动上述两个服务,我们可以直接使用这个脚本,直接双击,将会弹出两个窗口则表示启动成功,如下图:
此时直接访问:http://localhost:8888/,直接进入UI端,如下图:
1.5 客户端搭建
客户端也就是单个微服务,由于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
包路径不能包含中文,不能有空格,否则运行不成功。
1.6 数据持久化
只要服务端重启之后,这些链路追踪数据将会丢失了,因为skywalking
默认持久化的方式是存储在内存中。
当然这里也是可以通过插拔方式的替换掉存储中间件,企业中往往是使用ES
存储,这里介绍一下MySQL的方式存储
1.6.1 修改配置文件
修改 config/application.yml
文件中的存储方式,总共需要修改两处地方。
修改默认的存储方式为mysql,如下:
storage:
selector: ${SW_STORAGE:mysql}
修改Mysql相关的信息,比如用户名、密码等,如下图:
1.6.2 添加MySQL的jdbc依赖
默认的 oap
中是没有jdbc
驱动依赖,因此需要我们手动添加一下,只需要将驱动的jar放在oap-libs
文件夹中,如下图:
好了,已经配置完成,启动服务端,在skywalking
这个数据库中将会自动创建表,如下图:
1.7 日志监控
在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/
1.7.1 添加依赖
根据官方文档,需要先添加依赖,如下:
<!-- 如果想在项目代码中获取链路TraceId,则需要引入此依赖 -->
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-trace</artifactId>
<version>8.8.0</version>
</dependency>
<!-- 自定义功能相关, 比如自定义tag -->
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-opentracing</artifactId>
<version>8.8.0</version>
</dependency>
<!-- skywalking 日志记录 logback插件 -->
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-logback-1.x</artifactId>
<version>8.8.0</version>
</dependency>
1.7.2 添加配置文件
新建一个logback-spring.xml
放在resource
目录下,配置如下:
点击此处了解logback.xml文件解析
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod=" 5 seconds">
<!--控制台日志打印-->
<!-- with the MDC, set %X{tid} in Pattern -->
<!-- MDC是什么:MDC采用Map的方式存储上下文,线程独立的,子线程会从父线程拷贝上下文 -->
<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%n</Pattern>
</layout>
</encoder>
</appender>
<!--skywalking日志上报-->
<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%n</Pattern>
</layout>
</encoder>
</appender>
<!--日志文件-->
<appender name="fileAppender" class="ch.qos.logback.core.FileAppender">
<file>./logs/gateway-all.log</file>
<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%n</Pattern>
</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 |
1.8 性能剖析
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秒以上,因此选择这个接口点击分析,可以看到详细的堆栈信息,如下图:
如何定位到睡眠2秒钟的那一行代码呢?直接往下翻,如下图:
是不是很清楚了,在OrderController这个接口线程睡眠了两秒…
1.9 监控告警
对于服务的异常信息,比如接口有较长延迟,skywalking
也做出了告警功能,如下图:
skywalking
中有一些默认的告警规则,如下:
- 最近3分钟内服务的平均响应时间超过1秒
- 最近2分钟服务成功率低于80%
- 最近3分钟90%服务响应时间超过1秒
- 最近2分钟内服务实例的平均响应时间超过1秒
当然除了以上四种,随着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
,这样开发者就可以定制一些处理方法,比如发送邮件、微信、钉钉通知运维人员处理。
当然这个钩子也是有些规则的,如下:
- POST请求
- application/json 接收数据
- 接收的参数必须是AlarmMessage中指定的参数。
注意
: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,多调用几次,则会触发告警,控制台打印日志如下:
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)