目录
Spring Boot Admin 监控告警服务
邮件警报
钉钉警报
Spring Boot Admin 监控告警服务
在微服务架构下,服务的数量少则几十,多则上百,所以对服务的监控必不可少。如果是以前的单体项目,启动了多少个项目是固定的,可以通过第三方监控工具对其进行监控,然后实时告警。
在微服务下,由于服务数量太多,并且可以随时扩展,这个时候第三方的监控功能就不适用了,不过我们可以通过 Spring Boot Admin 连接注册中心来查看服务状态,这个只能在页面查看。
很多时候我们更希望能够自动监控,通过邮件告警,比如发出“某某服务下线了”这样的功能。在 Spring Boot Admin 中其实已经有这样的功能了,我们只需要配置一些邮件的信息就可以使用。
邮件警报
引入邮件所需要的依赖,代码如下所示:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
然后在配置文件中增加邮件服务器的信息:
spring:
mail:
host: smtp.qq.com
username: xxx.qq.com
password: qq 邮箱的授权码
properties:
smtp:
auth: true
starttls:
enable: true
required: true
boot:
admin:
notify:
mail:
# 发送给谁
to: xxx@126.com
# 是谁发送出去的
from: xxx.qq.com
配置好之后就可以收到监控邮件了。
钉钉警报
目前很多公司都是用钉钉来办公,通过钉钉可以发送监控消息,非常方便。Spring Boot Admin 中默认是没有钉钉警报这个功能的,我们可以自己去扩展使用钉钉来发送监控信息。
创建钉钉机器人,拿到 token
钉钉官方提供了统一的 SDK ,使用 SDK 可以便捷的调用服务端 API,但没有放到公共 maven 仓库中,需要自行下载后导入到项目,或者上传到自己的搭建的nexus私服中:
<dependency>
<groupId>com.dingtalk</groupId>
<artifactId>taobao-sdk-java-auto</artifactId>
<version>20210219</version>
</dependency>
通过扩展 AbstractEventNotifier
或 AbstractStatusChangeNotifier
。在 blog-admin-server 工程中编写一个自定义的通知器:
@Component
public class DingTalkNotifier extends AbstractEventNotifier {
private static final Logger logger = LoggerFactory.getLogger(DingTalkNotifier.class);
/**
* 消息模板
*/
private static final String template = "服务名:%s(%s) \n状态:%s(%s) \n服务ip:%s";
@Value("${spring.admin.ding-talk-token}")
private String dingTalkToken;
public DingTalkNotifier(InstanceRepository repository) {
super(repository);
}
@Override
protected Mono<Void> doNotify(InstanceEvent event, Instance instance) {
return Mono.fromRunnable(() -> {
if (event instanceof InstanceStatusChangedEvent) {
logger.info("Instance {} ({}) is {}", instance.getRegistration().getName(), event.getInstance(),
((InstanceStatusChangedEvent) event).getStatusInfo().getStatus());
String status = ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus();
String messageText = null;
switch (status) {
// 健康检查没通过
case "DOWN":
logger.info("发送 健康检查没通过 的通知!");
messageText = String.format(template, instance.getRegistration().getName(),event.getInstance(), ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus(),"健康检查没通过",instance.getRegistration().getServiceUrl());
this.sendMessage(messageText);
break;
// 服务离线
case "OFFLINE":
logger.info("发送 服务离线 的通知!");
messageText = String.format(template, instance.getRegistration().getName(),event.getInstance(), ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus(),"服务离线",instance.getRegistration().getServiceUrl());
this.sendMessage(messageText);
break;
//服务上线
case "UP":
logger.info("发送 服务上线 的通知!");
messageText = String.format(template, instance.getRegistration().getName(),event.getInstance(), ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus(),"服务上线",instance.getRegistration().getServiceUrl());
this.sendMessage(messageText);
break;
// 服务未知异常
case "UNKNOWN":
logger.info("发送 服务未知异常 的通知!");
messageText = String.format(template, instance.getRegistration().getName(),event.getInstance(), ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus(),"服务未知异常",instance.getRegistration().getServiceUrl());
this.sendMessage(messageText);
break;
default:
break;
}
} else {
logger.info("Instance {} ({}) {}", instance.getRegistration().getName(), event.getInstance(),
event.getType());
}
});
}
/**
* 发送消息
* @param messageText
*/
private void sendMessage(String messageText){
DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/robot/send?access_token=" + dingTalkToken);
OapiRobotSendRequest request = new OapiRobotSendRequest();
request.setMsgtype("text");
OapiRobotSendRequest.Text text = new OapiRobotSendRequest.Text();
text.setContent(messageText);
request.setText(text);
try {
client.execute(request);
} catch (ApiException e) {
logger.info("[ERROR] sendMessage", e);
}
}
}
目前我们已经配置好了警报功能,当服务上下线的时候就会发送警报,当网络发生波动的时候也有可能会触发警报。当前的警报只会发送一次,也就是说你的服务挂掉之后你会收到一条警报。如果是网络引起的警报也会收到一条警报,这个时候你就无法判断服务是不是真正出问题了。
我们的需求也很简单,当服务真正挂掉的时候,警报可以发送多条,比如每 10 秒发送一条,这样连续性的警报就很容易让维护人员关注和辨别。
可以通过配置 RemindingNotifier
来实现上面的需求:
@Autowired
private DingTalkNotifier dingTalkNotifier;
@Primary
@Bean(initMethod = "start", destroyMethod = "stop")
public RemindingNotifier remindingNotifier(InstanceRepository repository) {
RemindingNotifier notifier = new RemindingNotifier(dingTalkNotifier, repository);
notifier.setReminderPeriod(Duration.ofSeconds(20));
notifier.setCheckReminderInverval(Duration.ofSeconds(20));
return notifier;
}
这里设置的时间间隔是 20 秒一次,当服务出问题的时候就会每隔 20 秒发送一次警报,直到服务正常才会停止。