關(guān)于SkyWalking的基礎(chǔ)使用參考:
官方文檔:
SkyWalking 告警功能
SkyWalking 告警功能是在6.x版本新增的始衅,其核心由一組規(guī)則驅(qū)動(dòng)冷蚂,這些規(guī)則定義在config/alarm-settings.yml
文件中。 告警規(guī)則的定義分為兩部分:
- 告警規(guī)則:它們定義了應(yīng)該如何觸發(fā)度量警報(bào)汛闸,應(yīng)該考慮什么條件蝙茶。
- Webhook(網(wǎng)絡(luò)鉤子):定義當(dāng)警告觸發(fā)時(shí),哪些服務(wù)終端需要被告知
告警規(guī)則
SkyWalking 的發(fā)行版都會(huì)默認(rèn)提供config/alarm-settings.yml
文件诸老,里面預(yù)先定義了一些常用的告警規(guī)則隆夯。如下:
- 過去3分鐘內(nèi)服務(wù)平均響應(yīng)時(shí)間超過1秒
- 服務(wù)成功率在過去2分鐘內(nèi)低于80%
- 服務(wù)90%響應(yīng)時(shí)間在過去3分鐘內(nèi)低于1000毫秒
- 服務(wù)實(shí)例在過去2分鐘內(nèi)的平均響應(yīng)時(shí)間超過1秒
- 端點(diǎn)平均響應(yīng)時(shí)間過去2分鐘超過1秒
這些預(yù)定義的告警規(guī)則,打開config/alarm-settings.yml
文件即可看到别伏。其具體內(nèi)容如下:
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_p90_sla_rule:
# Metrics value need to be long, double or int
metrics-name: service_p90
op: ">"
threshold: 1000
period: 10
count: 3
silence-period: 5
message: 90% response time of service {name} is more than 1000ms in 3 minutes of last 10 minutes
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
除此之外蹄衷,官方還提供了一個(gè)config/alarm-settings-sample.yml
文件,該文件是一個(gè)告警規(guī)則的示例文件厘肮,里面展示了目前支持的所有告警規(guī)則配置項(xiàng):
# Sample alarm rules.
rules:
# Rule unique name, must be ended with `_rule`.
endpoint_percent_rule:
# Metrics value need to be long, double or int
metrics-name: endpoint_percent
threshold: 75
op: <
# The length of time to evaluate the metrics
period: 10
# How many times after the metrics match the condition, will trigger alarm
count: 3
# How many times of checks, the alarm keeps silence after alarm triggered, default as same as period.
silence-period: 10
message: Successful rate of endpoint {name} is lower than 75%
service_percent_rule:
metrics-name: service_percent
# [Optional] Default, match all services in this metrics
include-names:
- service_a
- service_b
exclude-names:
- service_c
threshold: 85
op: <
period: 10
count: 4
告警規(guī)則配置項(xiàng)的說(shuō)明:
-
Rule name:規(guī)則名稱愧口,也是在告警信息中顯示的唯一名稱。必須以
_rule
結(jié)尾类茂,前綴可自定義 -
Metrics name:度量名稱调卑,取值為oal腳本中的度量名,目前只支持
long
大咱、double
和int
類型。詳見Official OAL script - Include names:該規(guī)則作用于哪些實(shí)體名稱注益,比如服務(wù)名碴巾,終端名(可選,默認(rèn)為全部)
- Exclude names:該規(guī)則作不用于哪些實(shí)體名稱丑搔,比如服務(wù)名厦瓢,終端名(可選,默認(rèn)為空)
- Threshold:閾值
-
OP: 操作符啤月,目前支持
>
煮仇、<
、=
- Period:多久告警規(guī)則需要被核實(shí)一下谎仲。這是一個(gè)時(shí)間窗口浙垫,與后端部署環(huán)境時(shí)間相匹配
- Count:在一個(gè)Period窗口中,如果values超過Threshold值(按op)郑诺,達(dá)到Count值夹姥,需要發(fā)送警報(bào)
- Silence period:在時(shí)間N中觸發(fā)報(bào)警后,在TN -> TN + period這個(gè)階段不告警辙诞。 默認(rèn)情況下辙售,它和Period一樣,這意味著相同的告警(在同一個(gè)Metrics name擁有相同的Id)在同一個(gè)Period內(nèi)只會(huì)觸發(fā)一次
- message:告警消息
Webhook(網(wǎng)絡(luò)鉤子)
Webhook可以簡(jiǎn)單理解為是一種Web層面的回調(diào)機(jī)制飞涂,通常由一些事件觸發(fā)旦部,與代碼中的事件回調(diào)類似祈搜,只不過是Web層面的。由于是Web層面的士八,所以當(dāng)事件發(fā)生時(shí)容燕,回調(diào)的不再是代碼中的方法或函數(shù),而是服務(wù)接口曹铃。例如缰趋,在告警這個(gè)場(chǎng)景,告警就是一個(gè)事件陕见。當(dāng)該事件發(fā)生時(shí)秘血,SkyWalking就會(huì)主動(dòng)去調(diào)用一個(gè)配置好的接口,該接口就是所謂的Webhook评甜。
SkyWalking的告警消息會(huì)通過 HTTP 請(qǐng)求進(jìn)行發(fā)送灰粮,請(qǐng)求方法為 POST
,Content-Type
為 application/json
忍坷,其JSON 數(shù)據(jù)實(shí)基于List<org.apache.skywalking.oap.server.core.alarm.AlarmMessage
進(jìn)行序列化的粘舟。JSON數(shù)據(jù)示例:
[{
"scopeId": 1,
"scope": "SERVICE",
"name": "serviceA",
"id0": 12,
"id1": 0,
"ruleName": "service_resp_time_rule",
"alarmMessage": "alarmMessage xxxx",
"startTime": 1560524171000
}, {
"scopeId": 1,
"scope": "SERVICE",
"name": "serviceB",
"id0": 23,
"id1": 0,
"ruleName": "service_resp_time_rule",
"alarmMessage": "alarmMessage yyy",
"startTime": 1560524171000
}]
字段說(shuō)明:
-
scopeId、scope:所有可用的 Scope 詳見
org.apache.skywalking.oap.server.core.source.DefaultScopeDefine
- name:目標(biāo) Scope 的實(shí)體名稱
- id0:Scope 實(shí)體的 ID
- id1:保留字段佩研,目前暫未使用
- ruleName:告警規(guī)則名稱
- alarmMessage:告警消息內(nèi)容
- startTime:告警時(shí)間柑肴,格式為時(shí)間戳
郵件告警功能實(shí)踐
根據(jù)以上兩個(gè)小節(jié)的介紹,可以得知:SkyWalking是不支持直接向郵箱旬薯、短信等服務(wù)發(fā)送告警信息的晰骑,SkyWalking只會(huì)在發(fā)生告警時(shí)將告警信息發(fā)送至配置好的Webhook接口。
但我們總不能人工盯著該接口的日志信息來(lái)得知服務(wù)是否發(fā)生了告警绊序,因此我們需要在該接口里實(shí)現(xiàn)發(fā)送郵件或短信等功能硕舆,從而達(dá)到個(gè)性化的告警通知。
接下來(lái)開始動(dòng)手實(shí)踐骤公,這里基于Spring Boot進(jìn)行實(shí)現(xiàn)抚官。首先是添加依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
配置郵箱服務(wù):
server:
port: 9134
#郵箱配置
spring:
mail:
host: smtp.163.com
#發(fā)送者郵箱賬號(hào)
username: 你的郵箱@163.com
#發(fā)送者密鑰
password: 你的郵箱服務(wù)密鑰
default-encoding: utf-8
port: 465 #端口號(hào)465或587
protocol: smtp
properties:
mail:
debug:
false
smtp:
socketFactory:
class: javax.net.ssl.SSLSocketFactory
根據(jù)SkyWalking發(fā)送的JSON數(shù)據(jù)定義一個(gè)DTO,用于接口接收數(shù)據(jù):
@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;
}
接著定義一個(gè)接口阶捆,實(shí)現(xiàn)接收SkyWalking的告警通知凌节,并將數(shù)據(jù)發(fā)送至郵箱:
package com.example.alarmdemo.controller;
import com.example.alarmdemo.dto.SwAlarmDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/alarm")
public class SwAlarmController {
private final JavaMailSender sender;
@Value("${spring.mail.username}")
private String from;
/**
* 接收skywalking服務(wù)的告警通知并發(fā)送至郵箱
*/
@PostMapping("/receive")
public void receive(@RequestBody List<SwAlarmDTO> alarmList) {
SimpleMailMessage message = new SimpleMailMessage();
// 發(fā)送者郵箱
message.setFrom(from);
// 接收者郵箱
message.setTo(from);
// 主題
message.setSubject("告警郵件");
String content = getContent(alarmList);
// 郵件內(nèi)容
message.setText(content);
sender.send(message);
log.info("告警郵件已發(fā)送...");
}
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目標(biāo) Scope 的實(shí)體名稱: ").append(dto.getName())
.append("\nScope 實(shí)體的 ID: ").append(dto.getId0())
.append("\nid1: ").append(dto.getId1())
.append("\n告警規(guī)則名稱: ").append(dto.getRuleName())
.append("\n告警消息內(nèi)容: ").append(dto.getAlarmMessage())
.append("\n告警時(shí)間: ").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
測(cè)試告警功能
完成告警接口的開發(fā)及配置后,我們來(lái)進(jìn)行一個(gè)簡(jiǎn)單的測(cè)試儡司。這里有一條調(diào)用鏈路如下:
我在/producer
接口中增加了一行會(huì)導(dǎo)致異常的代碼娱挨,故意使該接口不可用:
@GetMapping
public String producer() {
log.info("received a request");
int i = 1 / 0;
return "this message from producer";
}
接下來(lái)編寫一段測(cè)試代碼,讓其服務(wù)成功率滿足在過去2分鐘內(nèi)低于80%這條默認(rèn)的告警規(guī)則:
public static void main(String[] args) {
RestTemplate restTemplate = new RestTemplate();
for (int i = 0; i < 100; i++) {
String result = restTemplate.getForObject("http://127.0.0.1:8936/consumer", String.class);
log.info(result);
}
}
執(zhí)行完測(cè)試代碼捕犬,等待約兩分鐘后跷坝,告警接口的控制臺(tái)輸出了一段日志信息:
此時(shí)酵镜,郵箱正常收到了告警郵件: