SkyWalking
SkyWalking是一个国产开源框架,2015年由吴晟开源 , 2017年加入Apache孵化器。 SkyWalking是分布式系统的应用程序性能监视工具,专为微服务、云原生架构和基于容器(Docker、K8s、Mesos)架构而设计。它是一款优秀的APM(Application Performance Management)工具,包括了分布式追踪、性能指标分析、应用和服务依赖分析等。
官网地址: https://skywalking.apache.org/
下载地址:http://skywalking.apache.org/downloads/
Github地址:https://github.com/apache/skywalking
文档地址: https://skyapm.github.io/document-cn-translation-of-skywalking/
SkyWalking优点:
- 接入段无代码入侵(字节码增强)
- 支持java/.net/Node.js/php/go等语言
- 调用链路可视化,聚合报表较丰富
- 探针(JavaAgent)对吞吐量影响较小
SkyWalking主要功能:
- 多种监控手段,可以通过语言探针(JavaAgent)和service mesh获得监控的数据
- 支持多种语言自动探针,包括 Java,.NET Core 和 Node.JS
- 轻量高效,无需大数据平台和大量的服务器资源
- 模块化,UI、存储、集群管理都有多种机制可选
- 支持告警
- 优秀的可视化解决方案
SkyWalking环境部署搭建
SkyWalking组成部分如下,其中skywalking oapservice集群和SkyWalking webapp UI服务在一个资源中,部署起来也是相对简单。
- skywalking agent和业务系统绑定在一起,负责收集各种监控数据
- Skywalking oapservice是负责处理监控数据的,比如接受skywalking agent的监控数据,并存储在数据库中。接受skywalking webapp的前端请求,从数据库查询数据,并返回数据给前端。Skywalking oapservice通常以集群的形式存在
- skywalking webapp,前端界面,用于展示数据
- 数据库用于存储监控数据的数据库,比如mysql、elasticsearch等
搭建SkyWalking OAP服务
下载资源
选择合适的版本下载解压即可。(我这边使用的是v9.2.0)
启动服务
启动前建议修改SkyWalking-web-UI的默认端口8080(8080经常被其他程序占用),此处修改为8868端口。
修改路径为apache-skywalking-apm-bin\webapp\webapp.yml
启动apache-skywalking-apm-bin\bin\startup.bat(linux下启动startup.sh)
没有日志实时输出,在apache-skywalking-apm-bin\logs下查看启动日志。
启动后会后两个服务,一个是SkyWalking-oap-server,一个是SkyWalking-web-ui。SkyWalking-oap-server服务启动后会暴露11800和12800两个端口(端口可以在apache-skywalking-apm-bin\config\application.yml中修改),11800负责收集监控数据,12800负责接受前端请求。
访问UI
访问http://127.0.0.1:8868/
SkyWalking接入微服务
下载Java Agent
我这边选择的是最新版v8.13.0。下载完成后解压出来即可。
win下整合SkyWalking
在需要整合SkyWalking的服务中添加参数,在IDEA中添加VM参数。linux下也是一样的使用java -jar带下面的参数运行。
-javaagent:D:\develop\skywalking\skywalking-agent\skywalking-agent.jar
-DSW_AGENT_NAME=skywalking-demo
-DSW_AGENT_COLLECTOR_BACKEND_SERVICES=127.0.0.1:11800
参数说明:
-javaagent:skywalking-agent.jar在本地磁盘的路径,必须是本地
-DSW_AGENT_NAM:在SkyWalking上显示的服务名
-DSW_AGENT_COLLECTOR_BACKEND_SERVICES:SkyWalking的collector服务的IP和端口,负责收集监控数据的端口
启动项目,请求一个接口,查看控制台。
整合了多个服务的效果(在需要整合的服务中添加对应的参数),调用链路就很清晰了。整合Gateway时需要注意添加plugin插件。
Linux下整合SkyWalking
准备一个springboot程序,打成可执行的jar包,写一个shell脚本。在shell脚本上通过设置相关参数启动项目。
startup.sh
#!/bin/sh
# SkyWalking Agent配置
export SW_AGENT_NAME=springboot‐skywalking‐demo #Agent名字,一般使用spring.application.name
export SW_AGENT_COLLECTOR_BACKEND_SERVICES=127.0.0.1:11800 #配置 Collector 地址。
export SW_AGENT_SPAN_LIMIT=2000 #配置链路的最大Span数量,默认为 300。
export JAVA_AGENT=‐javaagent:/usr/local/soft/apache‐skywalking‐apm‐bin/agent/skywalking‐agent.jar
java $JAVA_AGENT ‐jar springboot‐skywalking‐demo‐0.0.1‐SNAPSHOT.jar #jar启动
上面的脚本和在IDEA中启动写的vm参数是等价的。
SkyWalking持久化到MySQL
SkyWalking默认使用H2数据库存储,H2是一个基于内存的数据库,重启后数据就没有了。虽然SkyWalking监控数据是一个实时的,但运行时间长了内存容易满,就需要重启SkyWalking服务了。如果配置为持久化的数据库中(当然SkyWalking配合ES性能是最好),我们定期的进行数据清理即可,避免了频繁的重启服务。
- 修改配置
修改apache-skywalking-apm-bin\config\application.yml文件
-
添加mysql驱动
向apache-skywalking-apm-bin\oap-libs目录下添加MySQL数据库对应的连接驱动包
-
创建数据库
在数据库中创建apache-skywalking-apm-bin\config\application.yml中的数据库。
-
启动服务
双击apache-skywalking-apm-bin\bin\startup.bat。
启动服务后swtest中就会建好很多的表。
-
验证
重启SkyWalking服务之后,之前的报错依然存在。
自定义链路追踪
SkyWalking默认是会记录接口资源(也就是controller层)的链路,当我们希望对项目中的业务方法实现链路追踪,方便我们排查问题时,可以自定义链路追踪。
-
导入依赖
<dependency> <groupId>org.apache.skywalking</groupId> <artifactId>apm-toolkit-trace</artifactId> <version>8.5.0</version> </dependency>
-
添加追踪注解
在需要加入追踪的业务方法上添加@Trace注解@Trace public List<Order> all() throws InterruptedException { TimeUnit.SECONDS.sleep(2); return orderMapper.selectAll(); }
-
获取入参和返回值
添加追踪业务方法@Trace注解的基础上,使用@Tags和@Tag获取入参和返回值@Trace @Tag(key="all",value="returnedObj") public List<Order> all() throws InterruptedException { TimeUnit.SECONDS.sleep(2); return orderMapper.selectAll(); } @Trace @Tags({@Tag(key="get",value="returnedObj"),// "returnedObj"为返回值的固定写法,返回值类型需要重写toString方法 @Tag(key="get",value="arg[0]")}) // "arg[0]" 代表第一个入参参数 public Order get(Integer id) { return orderMapper.selectByPrimaryKey(id); }
集成日志
-
导入依赖
<dependency> <groupId>org.apache.skywalking</groupId> <artifactId>apm-toolkit-logback-1.x</artifactId> <version>{project.release.version}</version> </dependency>
-
添加配置文件
在项目resource下添加logback-spring.xml文件<?xml version="1.0" encoding="UTF-8"?> <configuration> <!-- 引入 Spring Boot 默认的 logback XML 配置文件 --> <include resource="org/springframework/boot/logging/logback/defaults.xml"/> <!--配置的是控制台日志输出,核心是获取TID追踪ID--> <appender name="console" 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.TraceIdPatternLogbackLayout"> <Pattern>-%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} [%tid] %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}</Pattern> </layout> </encoder> </appender> <!--配置的是SkyWalking中的日志,可以在SkyWalking UI中直接查看日志--> <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 --> <root level="INFO"> <appender-ref ref="console"/> <!--控制台输出日志--> <appender-ref ref="grpc-log"/> <!--同步日志到SkyWalking UI中--> </root> </configuration>
-
修改配置文件
在skywalking-agent\config\agent.config文件最后添加以下配置# 指定要向其报告日志数据的grpc服务器的主机,也就是SkyWalking OAP服务主机地址 plugin.toolkit.log.grpc.reporter.server_host=${SW_GRPC_LOG_SERVER_HOST:127.0.0.1} # SkyWalking OAP收集数据的端口,默认11800 plugin.toolkit.log.grpc.reporter.server_port=${SW_GRPC_LOG_SERVER_PORT:11800} # 日志信息最大size plugin.toolkit.log.grpc.reporter.max_message_size=${SW_GRPC_LOG_MAX_MESSAGE_SIZE:10485760} # 数据上报超时时间,单位 S plugin.toolkit.log.grpc.reporter.upstream_timeout=${SW_GRPC_LOG_GRPC_UPSTREAM_TIMEOUT:30}
-
启动项目和SkyWalking服务
控制台输出TID,可以使用TID去SkyWalking UI中查询相关信息。
SkyWalking UI界面中可以直接查看日志信息。
告警
SkyWalking告警功能是在6.x版本新增的,其核心由一组规则驱动,这些规则定义在apache-skywalking-apm-bin\config\alarm-settings.yml文件中。 告警规则的定义分为两部分:
告警规则
SkyWalking的发行版都会默认提供apache-skywalking-apm-bin\alarm-settings.yml文件,里面预先定义了一些常用的告警规则。如下:
- 过去 3 分钟内服务平均响应时间超过 1 秒
- 过去 2 分钟服务成功率低于80%
- 过去 3 分钟内服务响应时间超过 1s 的百分比
- 服务实例在过去 2 分钟内平均响应时间超过 1s,并且实例名称与正则表达式匹配
- 过去 2 分钟内端点平均响应时间超过 1 秒
- 过去 2 分钟内数据库访问平均响应时间超过 1 秒
- 过去 2 分钟内端点关系平均响应时间超过 1 秒
这些预定义的告警规则,打开alarm-settings.yml文件即可看到 。
告警规则配置项说明:
- Rule name:规则名称,也是在告警信息中显示的唯一名称。必须以_rule结尾,前缀可自定义
- Metrics name:度量名称,取值为oal脚本中的度量名,目前只支持long、double和int类型。详见Official OAL script
- Include names:该规则作用于哪些实体名称,比如服务名,终端名(可选,默认为全部)
- Exclude names:该规则作不用于哪些实体名称,比如服务名,终端名(可选,默认为空)
- Threshold:阈值
- OP: 操作符,目前支持 >、<、=
- Period:多久告警规则需要被核实一下。这是一个时间窗口,与后端部署环境时间相匹配
- Count:在一个Period窗口中,如果values超过Threshold值(按op),达到Count值,需要发送警报
- Silence period:在时间N中触发报警后,在TN -> TN + period这个阶段不告警。 默认情况下,它和Period一样,这意味着相同的告警(在同一个Metrics name拥有相同的Id)在同一个Period内只会触发一次
- message:告警消息
Webhook
Webhook可以简单理解为是一种Web层面的回调机制,通常由一些事件触发,与代码中的事件回调类似,只不过是Web层面的。由于是 Web层面的,所以当事件发生时,回调的不再是代码中的方法或函数,而是服务接口。
例如,在告警这个场景,告警就是一个事件。当该 事件发生时,SkyWalking就会主动去调用一个配置好的接口,该接口就是所谓的Webhook。
SkyWalking的告警消息会通过 HTTP 请求进行发送,请求方法为 POST,Content-Type 为 application/json,其JSON 数据实基于List< org.apache.skywalking.oap.server.core.alarm.AlarmMessage >进行序列化。JSON数据实例如下:
[{
"scopeId": 1,
"scope": "SERVICE",
"name": "serviceA",
"id0": "12",
"id1": "",
"ruleName": "service_resp_time_rule",
"alarmMessage": "alarmMessage xxxx",
"startTime": 1560524171000
}, {
"scopeId": 1,
"scope": "SERVICE",
"name": "serviceB",
"id0": "23",
"id1": "",
"ruleName": "service_resp_time_rule",
"alarmMessage": "alarmMessage yyy",
"startTime": 1560524171000
}]
字段说明:
- scopeId、scope:所有可用的 Scope 详见 org.apache.skywalking.oap.server.core.source.DefaultScopeDefine
- name:目标 Scope 的实体名称
- id0:Scope 实体的 ID
- id1:保留字段,目前暂未使用
- ruleName:告警规则名称
- alarmMessage:告警消息内容
- startTime:告警时间,格式为时间戳
告警实现发送邮件
-
导入依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency>
-
添加发送邮件配置
spring: # 邮箱配置 mail: host: smtp.163.com #发送者邮箱账号 username: 发送者邮箱账号 #发送者密钥 POP3 password: 发送者密钥 default‐encoding: UTF-8 port: 465 #端口号465或587 protocol: smtps properties: mail: debug: false smtp: socketFactory: class: javax.net.ssl.SSLSocketFactory
-
提供告警接口
@Slf4j @RestController @RequiredArgsConstructor @RequestMapping("/alarm") public class SwAlarmController { private final JavaMailSender sender; @Value("${spring.mail.username}") private String from; /** * 接收skywalking服务的告警通知并发送至邮箱 * * 必须是post */ @PostMapping("/receive") public void receive(@RequestBody List<SwAlarmDto> alarmList) { SimpleMailMessage message = new SimpleMailMessage(); // 发送者邮箱 message.setFrom(from); // 接收者邮箱 message.setTo(from); // 主题 message.setSubject("告警邮件"); String content = getContent(alarmList); // 邮件内容 message.setText(content); sender.send(message); log.info("告警邮件已发送..."+content); } private String getContent(List<SwAlarmDto> alarmList) { StringBuilder sb = new StringBuilder(); for (SwAlarmDto dto : alarmList) { sb.append("scopeId: ").append(dto.getScopeId()) .append("\nscope: ").append(dto.getScope()) .append("\n目标 Scope 的实体名称: ").append(dto.getName()) .append("\nScope 实体的 ID: ").append(dto.getId0()) .append("\nid1: ").append(dto.getId1()) .append("\n告警规则名称: ").append(dto.getRuleName()) .append("\n告警消息内容: ").append(dto.getAlarmMessage()) .append("\n告警时间: ").append(dto.getStartTime()) .append("\n标签: ").append(dto.getTags()) .append("\n\n---------------\n\n"); } return sb.toString(); } }
DTO
@Data public class SwAlarmDto { private int scopeId; private String scope; private String name; private String id0; private String id1; private String ruleName; private String alarmMessage; private List<Tag> tags; private long startTime; private transient int period; private transient boolean onlyAsCondition; @Data public static class Tag{ private String key; private String value; } }
-
添加Webhook调用的接口
修改apache-skywalking-apm-bin\config\alarm-settings.yml中的webhooks配置。接口为上一步编写的接口。webhooks: - http://127.0.0.1:8088/alarm/receive
启动项目和Skywalking服务,在任意一个接口中睡眠两秒,请求几次该接口。就可以收到告警的短信了。
我这边在all接口中睡眠了2秒,调用all接口几次,触发告警。收到邮件。
告警邮件
SkyWalking集群
SkyWalking OAP一般都是以集群的方式出现的。那么实现SkyWalking集群是将SkyWalking OAP作为一个服务注册到nacos上,只要SkyWalking OAP服务没有全部宕机,保证有一个SkyWalking OAP在运行,就能进行跟踪。
-
修改cluster方式
修改apache-skywalking-apm-bin\config\application.yml文件中的cluster方式为nacos。
-
配置SkyWalking UI服务访问的地址
修改apache-skywalking-apm-bin\webapp\webapp.yml文件,在oap-service下添加oap服务列表。
-
启动服务
启动时和单机的相同,需要将所有的OAP服务加入到参数中,多个使用英文逗号隔开。
startup.sh#!/bin/sh # SkyWalking Agent配置 export SW_AGENT_NAME=springboot‐skywalking‐demo export SW_AGENT_COLLECTOR_BACKEND_SERVICES=192.168.2.7:11800,192.168.2.8:11800,192.168.2.9:11800 # 多个使用英文逗号隔开 export SW_AGENT_SPAN_LIMIT=2000 export JAVA_AGENT=‐javaagent:/usr/local/soft/apache‐skywalking‐apm‐bin/agent/skywalking‐agent.jar java $JAVA_AGENT ‐jar springboot‐skywalking‐demo‐0.0.1‐SNAPSHOT.jar