监控指标采集(WarningLog) -> 规则验证 (WarningRuleRecord)-> 通知记录(WarningEvent)
报警规则
报警的触发条件和通知方式。
报警事件 WarningRuleRecord
系统每隔1分钟,就会根据报警规则中设置的报警触发条件,判断指标是否触发报警。如果触发,则会生成一个报警事件记录。
通知记录 WarningEvent
报警事件生成之后,系统会根据报警规则中设置的报警生效时段和报警间隔,判断是否发送报警通知(电话、短信、钉钉群机器人)给您。如果发送,则会生成一个通知记录。
阈值报警
当前指标的值和阈值实时比较,如果符合设定的阈值条件,则触发报警。
1.0 监控平台之前出过的问题
虽然 之前让公元优化定时轮询的执行线程池,理论上所有定时任务都会在同一个线程池的不同线程上-一定程度上解决了之前的告警事件延时问题。默认是所有定时轮询都是一个线程执行。 导致告警事件延时。出现大量延时重复数据。
1.1 监控指标采集
WarningLog metric 收集表
type =1 业务上队列积压监控 (轮询调用队列服务,拉取)
type =2 来自队列监控 ,(推送,这个目前只有一个指标,没有插件开发收集指标问题。java这边会开发收集tps ,rt 等指标插件,详情请看https://www.jianshu.com/p/28d25a6637ff)
type =3 来自采集器(拉取)
监控设计上拉取就有问题 ,70个线上指标就出现了线上指标延迟问题。如果有上万个线上指标呢。
通过分布式lock ,定时轮询监控指标通过3种不同方式,进行收集批量写入WarningLog 表 。
性能上 ,不管有多少pod , 同时执行的只有一个pod的一个线程池 。性能上,无扩展的能力 。
而且目前收集都采用的拉的方式,一旦某个服务不可用,会阻塞当前执行线程。收集的数据量很大的情况 ,必然会导致数据收集端的延时 。所以线上对接的业务指标还不是很多,大概60,70个。没有服务metric 指标等,和以前公司几十万个服务监控指标差距还是很大的,目前作用其实也不大。
1.2 监控规则
监控规则采用 自定义 @Async 方式,执行规则将符合规则的告警数据插入告警规则表WarningRuleRecord中, @Async大量存在与j37代码中。所有异步接口代码都公用一个线程池 ,随着未来规则越来越多,必然会存在着上一个监控规则轮询没有执行完 ,下个规则轮询就开始的问题.随着累积的加剧 ,后期必然会影响其他的异步方法调用。
目前线上已经出现了积压情况。值得警惕
j37-51-6988d5667c-dtc22 | online | 10.66.1.207 | cn-zhangjiakou.10.63.97.203 | 线程池 async-service- 中队列积压任务数量为 71
1.3 告警
通过告警规则找到对应告警规则记录WarningRuleRecord,通过告警通知合并策略以及通知策略。下推通知WarningEvent给用户
代码规范真的蛮弱的 , 0,6 表示类别,状态, 还是蛮难看懂的
query.setIsDelete(0);
query.setStatus(0);
query.setCreateDate(beforeTime);
query.setRuleId(warningRule.getId());
query.setWarningServiceId(warningRule.getWarningServiceId());
List<WarningEvent> eventList = eventMapper.queryByWarningServiceId(query);
if (CollectionUtils.isNotEmpty(eventList)) {
for (WarningEvent item : eventList) {
WarningEventOperation eventOperation = new WarningEventOperation();
eventOperation.setIsDelete(0);
eventOperation.setEventId(item.getId());
eventOperation.setType(6);
1.4 过期数据清除
虽然通过分布式lock ,但依然会有多个pod 同时执行dataclean任务,这里让我不得不怀疑分布式lock 有没有作用。
从清除数据上可知 ,每天凌晨2点线上清除的数据在 16w 级别 ,数据量不大。
1.5 通知流程
下面是实现代码
/**
* 每天凌晨2:00清理数据
*/
@Scheduled(cron = "0 0 2 * * ?")
private void dataClean() {
redisLockUtil.executeWithLock("data:clean:cron:Lock", () -> {
// 定时清理主无效的(告警规则运行记录)
warningCronService.dataClean();
});
}
/**
* 整分钟00秒运行
*/
@Scheduled(cron = "0 */1 * * * ?")
private void executeLogCollectCron() {
redisLockUtil.executeWithLock("warning:Collect:Execute:Lock111", () -> {
// 告警规则运行周期(整分钟00秒运行)
warningCronService.excute();
//告警日志数据采集器(周期性采集数据)
warningCronService.executeLogCollect();
//防止异步方法过快释放分布式锁 (任务运行多次)
waitReleaseLock(1);
});
}
/**
* 整分钟00秒运行
*/
@Scheduled(cron = "0 */1 * * * ?")
private void executeLogCollectCron() {
redisLockUtil.executeWithLock("warning:Collect:Execute:Lock111", () -> {
// 告警规则运行周期(整分钟00秒运行)
warningCronService.excute();
//告警日志数据采集器(周期性采集数据)
warningCronService.executeLogCollect();
//防止异步方法过快释放分布式锁 (任务运行多次)
waitReleaseLock(1);
});
}
/**
* 整分钟30秒运行
*/
@Scheduled(cron = "30 */1 * * * ?")
private void executeExcuteCron() {
redisLockUtil.executeWithLock("warning:Excute:Execute:Lock", () -> {
//每1分钟通过接口调用,获取队列积压数据&(记录最大历史积压值)
warningCronService.executeQueueWarning();
});
}
/**
* 每三十秒检测是否有待接收事件需要发送消息(包括轮询消息和合并后消息)
*/
@Scheduled(cron = "0/30 * * * * ?")
private void sendQueueMessage() {
redisLockUtil.executeWithLock("send:Queue:Message", () -> {
// 三十秒一次检测队列事件是否超过合并周期(超过周期就发送预警消息)
warningCronService.sendQueueMessage();
// 三十秒一次检测普通事件是否超过合并周期(超过周期就发送预警消息)
warningCronService.sendMessage();
// 轮询发送消息
warningCronService.sendMoreMessage();
});
}
/**
* 每天凌晨2:00清理数据
*/
@Scheduled(cron = "0 0 2 * * ?")
private void dataClean() {
redisLockUtil.executeWithLock("data:clean:cron:Lock", () -> {
// 定时清理主无效的(告警规则运行记录)
warningCronService.dataClean();
});
}
private void waitReleaseLock(int i) {
try {
Thread.sleep(i * 1000);
} catch (Exception e) {
}
}
/**
* 从队列里面获取
*/
@Scheduled(cron = "0/30 * * * * ?")
public void queueCollect() {
if (!queueCollectFlag) {
return;
}
redisLockUtil.executeWithLock(QUEUE_COLLECT_REDIS_KEY, () -> {
warningCronService.exportLogFromQueue();
});
}