springCloud二-SkyWalking3-性能剖析-⽇志上传-告警管理-接入飞书
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 前言
 - 1. 性能剖析
 - 2. ⽇志上传
 - 2.1 ⽇志配置
 
- 3. 告警管理
 - 3.1 告警规则
 - 3.2 Webhook
 - 3.2.1 SkyWalking 的 WebHook 实现
 - 3.2.1.1 告警触发与推送
 - 3.2.1.2 WebHook配置
 - 3.2.1.3 典型应⽤场景
 
- 3.2.2 WebHook实践
 - 3.2.2.1 配置WebHook
 - 3.2.2.2 接⼝开发
 
- 3.2.3 配置126网易邮件告警
 
- 3.3 接入飞书
 - 总结
 
前言
1. 性能剖析
性能剖析功能是⼀种针对分布式系统代码级性能的动态分析技术, SkyWalking 提供了追踪分析的功能,可以查看请求调⽤链中具体⽅法或者代码块的执⾏耗时, ⽤于快速识别⾼耗时⽅法(如慢SQL查询等), 定位服务调⽤链(Trace)中具体 Span(单个操作节点)的性能问题
就是分析每一行代码的消耗时间

 点击trace profing
 点击新建任务
 
 选择query9
 
 点击新建任务

 发现第一行耗时最长
 点击这一行,然后点击分析

 
我们找到这里,说明是这个执行了2000ms
 
 还知道是35行代码耗时
 com.bite.order.controller.OrderController.queryOrder:35

果然是35行
这样我们就知道是哪里代码慢了
2. ⽇志上传
SkyWalking不仅⽀持链路追踪, 还可以集成⽇志数据, 帮助⽤⼾在⼀个平台上统⼀查看⽇志和追踪信息, 基于 Trace ID 实现⽇志与请求链路的⾃动关联,快速定位故障上下⽂.
    public OrderInfo queryOrder(Integer orderId) {log.info("queryOrder,orderId:{}",orderId);return orderMapper.selectById(orderId);}
 
问题是什么呢,问题就是如果是多线程的话,打印日志的顺序就可能不是按照一个线程打印一堆了,而是按照一种日志打印一堆—》比较混乱

 我们只需要在trace这里点击查看日志
就是把控制台的日志上传到SkyWalking中
配置参考
        <dependency><groupId>org.apache.skywalking</groupId><artifactId>apm-toolkit-logback-1.x</artifactId><version>9.4.0</version></dependency>
 
2.1 ⽇志配置

 我们现在的id与traceId无关,没有关联起来

 但是SkyWalking是有traceId的
所以要配置TraceId,还有上报到SkyWalking中
添加 logback-spring.xml ⽂件
 • Logback 框架默认加载的配置⽂件名为 logback.xml , 该名称适⽤于⾮ Spring Boot 应⽤.
 • Spring Boot默认会识别logback-spring.xml, 这是Spring Boot推荐的⽅式, 优先级⾼于默认logback.xml, ⽀持 Spring 扩展特性(如 ${spring.profiles.active})
 • 若同时存在 logback.xml 和 logback-spring.xml , Spring Boot 优先加载 logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false"></configuration>
 
大框架
在日志中打印traceId
 set %tid in Pattern section of logback.xml
    <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.TraceIdPatternLogbackLayout"><Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%tid] [%thread] %-5level %logger{36} -%msg%n</Pattern></layout></encoder></appender>
 
appender 是负责日志的输出的核心组件,把日志内容输出到指定的目标
ConsoleAppender表示输出到控制台
 Pattern表示输出的格式
 其中%tid就是traceId
        <root level="INFO"><appender-ref ref="STDOUT"/></root>
 
这个是定义STDOUT日志输出的级别


 这个TID就是traceID
然后是日志上报到SkyWalking中
grpc上报日志到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>
 
GRPCLogClientAppender就是上报日志到SkyWalking
    <root level="INFO"><appender-ref ref="STDOUT"/><appender-ref ref="grpc-log"/></root>
 
这样就可以了
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false"><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.TraceIdPatternLogbackLayout"><Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%tid] [%thread] %-5level %logger{36} -%msg%n</Pattern></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%n</Pattern></layout></encoder></appender><root level="INFO"><appender-ref ref="STDOUT"/><appender-ref ref="grpc-log"/></root></configuration>
 
这是总体代码
 
 这样日志就来了
而且它把每一个trace的日志都是放在一起的

 这些上传的日志都是由于trace引起的日志,有traceId才行
 启动的时候的日志就不会上传了
3. 告警管理
除了指标的监测之外, SkyWalking 还提供了告警功能. 当系统出现异常时(如接⼝响应慢, 成功率低), ⾃动触发通知, 帮助研发⼈员或者运维⼈员快速定位问题

 点击告警
 
 点击进入有告警详情
希望配置告警,比如成功率低于80%的时候告警
 还有就是告警希望可以通过邮件等形式告诉我,不然我不可能一直盯着页面看吧
3.1 告警规则
SkyWalking 的告警系统预先定义了⼀部分告警规则, 在 config/alarm-settings.yml ⽂件中, ⽤⼾也可以⾃定义告警规则.

告警规则
默认告警规则
为⽅便起⻅,SkyWalking提供了⼀个默认的alarm-setting.yml, 包括以下规则:
- 过去 3 分钟内服务平均响应时间超过 1 秒。
 - 最近 2 分钟服务成功率低于 80%。
 - 过去 3 分钟内超过 1 秒的服务响应时间百分位数
 - 服务实例在过去 2 分钟内的平均响应时间超过 1 秒,并且实例名称与正则表达式匹配。
 - 终端节点在过去 2 分钟内的平均响应时间超过 1 秒。
 - 过去 2 分钟内数据库访问平均响应时间超过 1 秒。
 - 终端节点关系 过去 2 分钟内超过 1 秒的平均响应时间。
 

 service_resp_time_rule是告警的规则名称
 规则名称必须是唯一的,而且必须以_rule结尾
expression是告警规则的配置
sum(service_resp_time > 1000) >= 3的意思就是一分钟内(一分钟统计)有三次响应时间大于一秒钟------》告警
period:10表示统计最近十分钟内的
    silence-period: 5
 
这个表示静默时长,报警之后5分钟之内,就不报警了
message表示告警的信息
XXXX_rule: 规则名称, 必须以"_rule" 结尾
• expression:告警表达式, 结果为1时, 触发报警
• period: 告警周期, 评估指标的时间⻓度(以分钟为单位)
• silence-period: 静默期, 在告警触发后, 多⻓时间内不再触发.在Time-N (TN)触发告警后,在"TN -> TN +period"时间段内保持静默.默认情况下, 它的⼯作⽅式与period相同. 同⼀告警在⼀个周期内只能触发⼀次
• message: 告警消息
 
所以service_resp_time_rule就是过去 3 分钟内服务平均响应时间超过 1 秒。
database_access_resp_time_rule:过去 2 分钟内数据库访问平均响应时间超过 1 秒。
endpoint_relation_resp_time_rule:终端节点关系 过去 2 分钟内超过 1 秒的平均响应时间。等等
 rules:下面的_rule都是SkyWalking默认支持的告警—》都是会生效的
 当然你也可以在alarm-settings.yml这个文件中自己配置规则
#hooks:
#  webhook:
#    default:
#      is-default: true
#      urls:
#        - http://127.0.0.1/notify/
#        - http://127.0.0.1/go-wechat/
 
这个配置呢
 默认告警会显示在SkyWalking的UI界面上
webhook就是主动通知我们告警信息的,而不是让我们自己去ui界面查看
3.2 Webhook
webhook是⼀种允许应⽤程序向外部系统(飞书,微信)实时推送事件或数据的机制, 通常通过HTTP回调实现, 从⽽实现跨系统⾃动化的信息传递
核⼼特征:
 • 事件驱动: 当预设条件触发时(如告警触发、数据更新), 主动向⽬标 URL 发送 HTTP 请求(通常为POST)
 • 轻量级集成: 接收⽅只需提供⼀个可访问的 HTTP 端点即可接收数据, ⽆需轮询查询
 • 灵活扩展: 适⽤于告警通知, 流程触发, 数据同步等场景
3.2.1 SkyWalking 的 WebHook 实现
SkyWalking 提供了WebHook的⽅式, 主要⽤于告警通知
3.2.1.1 告警触发与推送
当监控指标(如响应时间、错误率等)达到告警规则阈值时, SkyWalking会⽣成告警事件, ⾃动把告警信息封装为JSON格式, 通过HTTP的⽅式发送⾄预设的WebHook接收地址.
#hooks:
#  webhook:
#    default:
#      is-default: true
#      urls:
#        - http://127.0.0.1/notify/
#        - http://127.0.0.1/go-wechat/
 
http的url就是在这里配置的
告警json格式

 我们去查看一下这个文件List<org.apache.skywalking.oap.server.core.alarm.AlarmMessage>

 点这个

点击star
 跳转到github
 然后搜索AlarmMessage

就是这个类,就是告警信息
scopeId、scope: 告警⽬标的监控范围, 参考org.apache.skywalking.oap.server.core.source.DefaultScopeDefine 中定义
DefaultScopeDefine 也可以搜索到

 ◦ scopeId、scope:就是说你是端点告警还是service告警还是实例告警
Name: 告警⽬标的名称,如服务名、端点名等

 就这几个告警
id0: ⽬标实体的主要ID,通常是数据库中的主键
 ◦ id1: ⽬标实体的次要ID(可选),⽤于更精确的标识
ruleName: 触发告警的规则名称—》alarm-settings.yml中的
 ◦ alarmMessage: 具体的告警消息内容
 ◦ startTime: 告警触发的时间戳(毫秒)
 ◦ 标签: 标签列表,包含与告警相关的附加信息
3.2.1.2 WebHook配置
在 alarm-settings.yml 中定义 WebHook 地址及关联规则
hooks:webhook:default:is-default: trueurls:- http://127.0.0.1/notify/- http://127.0.0.1/go-wechat/
 
urls 为接收告警的HTTP端点
3.2.1.3 典型应⽤场景
◦ 集成第三⽅系统: 推送告警⾄钉钉, 企业微信、⻜书, 邮箱等协作⼯具.
 ◦ ⾃动化运维: 触发运维脚本(如⾃动扩容)或联动故障管理系统.
 ◦ 数据聚合分析: 将告警事件转发⾄⼤数据平台进⾏统计分析
3.2.2 WebHook实践
3.2.2.1 配置WebHook
配置 alarm-settings.yml , 然后重启
我们再来创建一个专门用于告警的应用程序
hooks:webhook:default:is-default: trueurls:- http://127.0.0.1:8084/alarm/handler
 
3.2.2.2 接⼝开发

    <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-test</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><includeSystemScope>true</includeSystemScope></configuration></plugin></plugins></build>
 
server:port: 8084
logging:pattern:dateformat: HH:mm:ss:SSS
 
@RestController
@RequestMapping("/alarm")
public class AlarmController {@RequestMapping("/handler")public String handler(){}
} 
@Setter
@Getter
public class AlarmMessage {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 Set<String> hooks = new HashSet<>();private String expression;private JsonObject mqeMetricsSnapshot;
}
 
给我们的告警信息是一个AlarmMessage 的json格式
 所以这个类也要创建
@Setter
@Getter
public class AlarmMessage {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 String expression;
}
 
我们创建的删除了一些属性
 
 说错了,这个才是给我们的json里面的内容
 所以要含有tags,全部属性都要含有
 
这个Tag怎么处理呢
搜索Tag.java

 还是仿照官方的
@Data
public class AlarmMessage {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 String expression;@Datapublic class Tag {private String key;private String value;}
}
 
这样就OK了
@Slf4j
@RestController
@RequestMapping("/alarm")
public class AlarmController {@RequestMapping("/handler")public String handler(@RequestBody AlarmMessage alarmMessage){log.info("接收到告警,alarmMessage:{}",alarmMessage);return "接收到告警"; }
}
 
然后SkyWalking也要重启
 然后jmeter跑起来

 我们等待UI界面,直到UI界面出现最新的告警信息—》只要第一个出来了,后面就很快了
这个17:21的是十几分钟以前的

 OK,新的告警信息来了
 
 我们看到error了,说json解析异常

 他说接收到的json是一个数组
    @RequestMapping("/handler")public String handler(@RequestBody List<AlarmMessage> alarmMessageList){log.info("接收到告警,alarmMessageList:{}",alarmMessageList);return "接收到告警";}
 

 新告警又来了

 也是打印出来了
3.2.3 配置126网易邮件告警
SkyWalking的WebHook功能, 会通过HTTP的⽅式, 把告警信息发送⾄预设的WebHook接收地址, 我们可以借此功能在这个接⼝⾥实现发送邮件或者短信等功能, 从⽽达到告警主动通知.
springboot发送邮件
        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId></dependency>
 
spring:mail:# 指定邮件服务器地址host: smtp.qq.com
 
这个是qq邮箱
spring:mail:# 指定邮件服务器地址host: smtp.126.com
 
这个是126邮箱
手机下载网易邮箱,注册网易免费邮箱一个就可以了
spring:mail:# 指定邮件服务器地址host: smtp.126.com
 
网易邮箱
然后是申请授权码了

设置–》点击pop3

然后我们开启pop3/SMTP
这样就会出现了
spring:mail:# 指定邮件服务器地址host: smtp.126.com# 登录账户username: xxxxx@126.com# 授权码password: "xxxxxxxx"# 端口port: 465# 默认编码default-encoding: UTF-8# 使用的协议protocol: smtps# 其他的属性properties:"mail.smtp.connectiontimeout": 5000"mail.smtp.timeout": 3000"mail.smtp.writetimeout": 5000"mail.smtp.auth": true"mail.smtp.starttls.enable": true"mail.smtp.starttls.required": true
 
只需要改账户名授权码和host就可以了

 这里有测试代码,我们直接复制就可以了
@SpringBootTest
class AlarmServiceApplicationTest {@AutowiredJavaMailSender javaMailSender;@Testvoid sendEmail() throws Exception{// 创建一个邮件消息MimeMessage message = javaMailSender.createMimeMessage();// 创建 MimeMessageHelperMimeMessageHelper helper = new MimeMessageHelper(message, false);// 发件人邮箱和名称helper.setFrom("ck_yyds@126.com", "springdoc");// 收件人邮箱helper.setTo("ck_yyds@126.com");// 邮件标题helper.setSubject("Hello");// 邮件正文,第二个参数表示是否是HTML正文helper.setText("Hello <strong> World</strong>!", true);// 发送javaMailSender.send(message);}}
 

这样就成功了
我们分装一下发送邮件的方法
    @Autowiredprivate MailProperties mailProperties;
 
我们注入这个

 这个类MailProperties 会读取邮件的配置信息

这些都是默认的配置可以不写
spring:mail:# 其他的属性properties:"personal": "ck告警系统" #发送人姓名"subject": "告警通知"#邮件标题
 
我们设置这个
@Slf4j
@Configuration
public class Mail {@Autowiredprivate JavaMailSender javaMailSender;@Autowiredprivate MailProperties mailProperties;public void sendEmail(String to,String content)  {try {// 创建一个邮件消息MimeMessage message = javaMailSender.createMimeMessage();// 创建 MimeMessageHelperMimeMessageHelper helper = new MimeMessageHelper(message, false);String from = mailProperties.getUsername();// 发件人邮箱和名称helper.setFrom(from, mailProperties.getProperties().getOrDefault("personal",from));//如果没有获取到personal的值,就是用默认值from// 收件人邮箱helper.setTo(to);// 邮件标题helper.setSubject(mailProperties.getProperties().getOrDefault("subject","告警通知"));// 邮件正文,第二个参数表示是否是HTML正文helper.setText(content, true);// 发送javaMailSender.send(message);}catch (Exception e){log.error("邮件发送失败,e:{}",e);}}
}
 
这样就分装好了
    @Autowiredprivate Mail mail;
 
    @RequestMapping("/handler")public String handler(@RequestBody List<AlarmMessage> alarmMessageList){log.info("接收到告警,alarmMessageList:{}",alarmMessageList);mail.sendEmail("ck_yyds@126.com",buildContent(alarmMessageList));return "接收到告警";}private String buildContent(List<AlarmMessage> alarmMessageList) {StringBuilder builder = new StringBuilder();builder.append("告警详情:");for (AlarmMessage message:alarmMessageList){builder.append("<br/>scopeId:").append(message.getScopeId()).append("<br/>scope:").append(message.getScope()).append("<br/>Name:").append(message.getName()).append("<br/>Id0:").append(message.getId0()).append("<br/>RuleName:").append(message.getRuleName()).append("<br/>AlarmMessage:").append(message.getAlarmMessage()).append("<br/>StartTime:").append(message.getStartTime()).append("<br/>-------------------------");}return builder.toString();}
 
然后启动等待告警
 
 
3.3 接入飞书
SkyWalking的WebHook功能, 也集成了第三⽅系统, 可以通过简单的配置, 推送告警⾄Slack, 企业微信, 钉钉, ⻜书等.
接入飞书
 钉钉和飞书是一样的
 微信只支持企业微信
钉钉
- 先注册飞书账号
 - 创建机器⼈
打开⻜书群组 → 点击右上⻆「设置」→「群机器⼈」→「添加机器⼈」→ 选择「⾃定义机器⼈」
配置机器⼈名称, 获取⽣成的 Webhook URL(格式为 https://open.feishu.cn/openapis/bot/v2/hook/xxxxxx ) 

 随便找一个群,点击设置
 里面有一个群机器人
 点击添加机器人
 
选择自定义机器人
 
 成功之后会有一个webhook的地址–》记录下来

 设置这个的话,发送请求就必须要有签名校验了

直接复制这个配置就可以了
 但是还要加上第一级:hooks
hooks:feishu:default:is-default: truetext-template: |-{"msg_type": "text","content": {"text": "Apache SkyWalking Alarm: \n %s."},"ats":"feishu_user_id_1,feishu_user_id_2"}      webhooks:- url: https://open.feishu.cn/open-apis/bot/v2/hook/dummy_tokensecret: dummysecret
 
ats这个是配置具体的userId,就是通知指定的一个人
这里的url改为刚刚添加机器人的webhook地址
 secret就改为刚刚的签名
 没有设置签名校验的话,secret就不用配置
然后就是重启SkyWalking
初始化慢慢等待吧

 
 新告警来了,飞书也来消息了
如果想使用更加个性化的模版的话,SkyWalking就不行了

 可以点击这个链接
在群组中使用机器人
