7、SkyWalking 告警功能
SkyWalking 告警功能是在6.x版本新增的,其核心由一组规则驱动,这些规则定义在config/alarm-settings.yml文件中。 告警规则的定义分为两部分:
- 告警规则:它们定义了应该如何触发度量警报,应该考虑什么条件。
- Webhook(网络钩子):定义当警告触发时,哪些服务终端需要被告知
告警规则
SkyWalking 的发行版都会默认提供config/alarm-settings.yml文件,里面预先定义了一些常用的告警规则。如下:
- 过去 3 分钟内服务平均响应时间超过 1 秒。
- 过去 2 分钟服务成功率低于80%。
- 过去 3 分钟内服务响应时间超过 1s 的百分比
- 服务实例在过去 2 分钟内平均响应时间超过 1s,并且实例名称与正则表达式匹配。
- 过去 2 分钟内端点平均响应时间超过 1 秒。
- 过去 2 分钟内数据库访问平均响应时间超过 1 秒。
- 过去 2 分钟内端点关系平均响应时间超过 1 秒。
这些预定义的告警规则,打开config/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进行序列化的。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:告警时间,格式为时间戳
邮件告警功能实践
根据以上两个小节的介绍,可以得知:SkyWalking是不支持直接向邮箱、短信等服务发送告警信息的,SkyWalking只会在发生告警时将告警信息发送至配置好的Webhook接口。
但我们总不能人工盯着该接口的日志信息来得知服务是否发生了告警,因此我们需要在该接口里实现发送邮件或短信等功能,从而达到个性化的告警通知。
接下来开始动手实践,这里基于Spring Boot进行实现。首先是添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
配置邮箱服务:
server:
port: 9134
#邮箱配置
spring:
mail:
host: smtp.163.com
#发送者邮箱账号
username: 你的邮箱@163.com
#发送者密钥
password: 你的邮箱服务密钥
default-encoding: utf-8
port: 465 #端口号465或587
protocol: smtp
properties:
mail:
debug:
false
smtp:
socketFactory:
class: javax.net.ssl.SSLSocketFactory
根据SkyWalking发送的JSON数据定义一个DTO,用于接口接收数据
@Data
public class SwAlarmDTO {
private Integer scopeId;
private String scope;
private String name;
private Integer id0;
private Integer id1;
private String ruleName;
private String alarmMessage;
private Long startTime;
}
接着定义一个接口,实现接收SkyWalking的告警通知,并将数据发送至邮箱
@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/alarm")
public class SwAlarmController {
private final JavaMailSender sender;
@Value("${spring.mail.username}")
private String from;
/**
* 接收skywalking服务的告警通知并发送至邮箱
*/
@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("告警邮件已发送...");
}
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\n---------------\n\n");
}
return sb.toString();
}
}
最后将该接口配置到SkyWalking中,Webhook的配置位于config/alarm-settings.yml文件的末尾,格式为http://{ip}:{port}/{uri}。如下示例
[root@ip-236-048 skywalking]# vim config/alarm-settings.yml
webhooks:
- http://127.0.0.1:9134/alarm/receive
测试告警功能
完成告警接口的开发及配置后,我们来进行一个简单的测试。这里有一条调用链路如下
我在/producer接口中增加了一行睡2秒的代码
@Override
@Trace
@Tag(key="getAll",value="returnedObj")
public List<Order> all() throws InterruptedException {
TimeUnit.SECONDS.sleep(2);
return orderMapper.selectAll();
}
http://localhost:8072/order/all
执行完测试代码,等待约两分钟后,告警接口的控制台输出了一段日志信息