4. 报警系统QuickAlarm之报警规则解析

报警系统QuickAlarm之报警规则解析

前面两篇分别说了报警执行器和报警规则的定义及用户扩展加载,接下来就是比较核心的一块了,如何将报警规则和报警执行器关联起来,即当发生报警时,应该call哪一个报警执行器

I. 背景知识点

0. 声明

在正式进入之前,有必要额外声明一下,因为目前的v1版本,没有开放报警规则的自定义,也就是说,目前只支持默认的报警规则,所以接下来的主要内容将集中在

  • 系统默认的报警规则的解析
  • 即基于报警频率阀值,自动选择报警执行器的规则解析

1. 报警规则

如果对于报警规则,依然不是很清晰的,可以阅读一下《报警系统QuickAlarm之报警规则的设定与加载》

这里简单的进行说明,系统中默认的报警规则结构为:

  • key为报警类型(即用户执行报警时,传进来的报警类型参数)
  • value为具体报警规则
    • 每个报警执行器拥有一个报警频率区间,通过报警频率映射到报警执行器的区间来选择对应的AlarmExecutor,这就是系统定义的报警规则

II. 报警规则解析

通过前面的报警规则的简单说明,基本上也可以捞出报警规则的解析原则了

  • 每种报警类型,对应一个报警规则
  • 每个报警规则中,可以有多个报警执行器
  • 每个报警执行器都有一个对应的报警频率的阀值
  • 根据阀值对所有的报警执行器排序
  • 计算报警频率,映射到哪个区间,则选择哪个报警执行器

上面是一个简单的解析规则,当然实际上和这个差不多,但有一些问题需要额外注意

  1. 只想选择一种报警方式,是否可以支持?
  2. 多重报警方式同时调用怎么处理?(如我希望用短信提示说有问题,同时用邮件包含详细的异常堆栈)
  3. 频率限制
  4. 报警类型没有设置报警规则如何处理?
  5. 报警规则中使用了一个未注册的报警执行器会怎样?

1. 实现方案说明

再次将报警规则类拿出来看一下

/**
 * 报警用户
 */
private List<String> users;


/**
 * 报警的阀值
 */
private List<AlarmThreshold> alarmThreshold;


/**
 * 最小的报警数
 */
private int minLimit;


/**
 * 最大的报警数
 */
private int maxLimit;


/**
 * 报警类型 {@link IExecute#getName()}
 */
private String alarmLevel;


/**
 * true 表示当报警超过当前的阀值之后, 将提升报警的程度
 */
private boolean autoIncEmergency;

针对上面的问题,逐一说明

  • 首先是 autoIncEmergency 这个参数,如果为true,则表示可以走上面的哪个区间映射的规则;否则就全部走AlarmConfig中默认的报警类型了
  • minLimit : 表示发生报警的频率下限值,小于这个值就不会执行具体的报警逻辑
  • maxLimit : 最大的报警频率,超过了也不报警(简单的频率控制)
  • alarmLevel: 对应的就是具体的报警类型
  • alarmThreshold: 这个只有在autoIncEmergency=true时,才有小,也就是我们前面说的不同的报警执行器,根据阀值区间进行排序,开启之后,遍历,判断频率是否在这个区间内,若在,则表示可以选择它了
  • 如果不存在报警规则,则采用默认的兜底规则
  • 若报警执行器也不存在,就直接采用系统定义的日志报警执行器

2. 实现

基本上前面已经将整个逻辑都说了,所以实际的编码反而比较清晰了

/**
 * 获取具体的报警执行器
 * <p>
 * 1. 未开启严重等级上升时, 直接返回
 * 2. 开启之后, 判断当前的计数 范围
 *
 * @param alarmConfig 报警配置项, 内部所有的参数都不可能为null
 */
public static ExecuteHelper getExecute(final AlarmConfig alarmConfig, 
  int count) {
    // 未达到报警的下限 or 超过报警的上限时
    if (count < alarmConfig.getMinLimit() || count > alarmConfig.getMaxLimit()) {
        return new ExecuteHelper(SimpleExecuteFactory.getExecute(NoneExecute.NAME), 
        alarmConfig.getUsers());
    }

    // 未开启报警升级, 直接返回
    if (!alarmConfig.isAutoIncEmergency()) {
        return new ExecuteHelper(SimpleExecuteFactory.
          getExecute(alarmConfig.getAlarmLevel()),
          alarmConfig.getUsers());
    }


    // 报警等级开启上升之趋势
    // 1. 获取设置的默认等级
    // 2. 判断当前的报警次数, 选择对应的报警类型
    // 3. 选择具体的报警类型
    String defaultLevel = alarmConfig.getAlarmLevel();
    String selectLevel = null;
    List<String> selectUser = alarmConfig.getUsers();

    List<AlarmThreshold> list = alarmConfig.getAlarmThreshold();
    boolean useNew = false;
    boolean containDefaultLevel = false;
    for (AlarmThreshold alarmThreshold : list) {
        if (Objects.equals(alarmThreshold.getAlarmLevel(), defaultLevel)) {
            containDefaultLevel = true;
        }
    }


    for (AlarmThreshold alarmThreshold : list) {
        // 表示当前的报警等级已经赶上默认的报警等级了, 所以要选择新的报警类型
        if (Objects.equals(alarmThreshold.getAlarmLevel(), defaultLevel)) {
            useNew = true;
        }

        if (count < alarmThreshold.getThreshold()) {
            break;
        }

        selectLevel = alarmThreshold.getAlarmLevel();
        // 选择新的报警类型时, 需要更新报警用户
        selectUser = alarmThreshold.getUsers(); 
    }


    // 阀值列表中不包含默认报警类型,则根据新的来
    if (!containDefaultLevel && selectLevel != null) {
        return new ExecuteHelper(SimpleExecuteFactory.getExecute(selectLevel), selectUser);
    }


    // 如果阀值列表中包含了默认报警类型, 且已经超过默认阀值
    if (useNew && selectLevel != null) {
        return new ExecuteHelper(SimpleExecuteFactory.getExecute(selectLevel), selectUser);
    } else {
        return new ExecuteHelper(SimpleExecuteFactory.getExecute(defaultLevel), alarmConfig.getUsers());
    }
}

具体的实现基本和我们前面分析的一样,但有一个地方需要额外注意

  • 默认报警阀值,可以直接决定是否需要报警
  • 因此定义的其他报警方式的阀值,应该在默认的阀值区间内
  • 当然AlarmThreshold中不包含默认报警方式时,优先选择阀值区间的报警方式
  • 当然AlarmThreshold中包含默认报警方式时,根据新的规则做处理

(吐槽:上面这个实现有点绕,后面想办法规避下,搞得不太好理解了)

另外一个问题就是,上面的实现没有支持可以同时选择多个报警执行器的情况

因为考虑到后面肯定会对报警规则的定义和解析放开,所以先实现了一个简单的场景,具体的放在后面处理

III. 小结

到这里报警规则和报警执行器之间的解析关系已确定,剩下的东西就简单了,一个维持报警频率计数,一个报警线程池,再加上一个对外接口的封装而言

基本上,到这里主要的核心逻辑已经完成,小结一下本系统中的核心设计理念 -- 一切可自定义(当然目前差得有点远)

1. 报警执行器

  • 通过SPI机制支持用户自定义扩展
  • 要求 Executor 拥有唯一标识
  • 因为报警执行器支持扩展,所以Executor的内部实现,完全可以由用户决定

2. 报警规则

  • 目前报警规则只提供默认的基于频率区间的选择方案
  • 报警规则通过报警执行器的name与之唯一对应,若对应不上,则选择默认执行器
  • 报警规则的加载同样基于SPI,支持自定义,因此报警规则可以存在任何地方
  • 报警规则加载器,提供一个报警规则变动的钩子(load()),若采用自定义的加载类,则确保规则变动时,主动回调这个方法
  • 默认的报警规则加载类,是基于系统的配置文件实现,内部托管了文件的变动更新事件(使用commons-io实现)

IV. 其他

相关博文

  1. 报警系统QuickAlarm总纲
  2. 报警系统QuickAlarm之报警执行器的设计与实现
  3. 报警系统QuickAlarm之报警规则的设定与加载
  4. 报警系统QuickAlarm之报警规则解析
  5. 报警系统QuickAlarm之频率统计及接口封装
  6. 报警系统QuickAlarm使用手册

项目: QuickAlarm

个人博客: Z+|blog

基于hexo + github pages搭建的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛

声明

尽信书则不如,已上内容,纯属一家之言,因本人能力一般,见识有限,如发现bug或者有更好的建议,随时欢迎批评指正,我的微博地址: 小灰灰Blog

扫描关注

QrCode
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容