前提需求:告警规则和告警发送通知策略都动态配置在数据库,方便管理和随时修改、删除。Prometheus需要动态读取数据库配置的告警规则,并根据数据的通知策略(邮件、短信、钉钉、微信等)把告警发送出去

需求分析:下面主要从表设计、组件配置、代码逻辑设计几个方面介绍。

1. 表设计

1.1 告警规则表

| 字段名 | 字段类型 | 说明 |
| id | int | ID主键 |
| notice_id | int | 通知策略ID |
| name | varchar | 告警名称 |
| rule | varchar | 告警规则 |
| duration | varchar | 持续时间 |
| content | varchar | 告警内容 |
| annotation | varchar | 注释 |
| tag | varchar | 标签 |

1.2 通知策略表

| 字段名 | 字段类型 | 说明 |
| id | int | 主键ID |
| name | varchar | 策略名称 |
| start_time | varchar | 通知时间段-开始时间 |
| end_time | varchar | 通知时间段-结束时间 |
| cycle | varchar | 通知周期 |
| type | varchar | 通知方式(短信、微信、钉钉、邮件等) |
| contact | varchar | 电话或者邮箱地址 |

1.3 告警消息表

| 字段名 | 字段类型 | 说明 |
| id | int | 主键ID |
| 告警标题 | varchar | 告警标题 |
| 告警内容 | varchar | 告警内容 |
| 告警规则唯一ID | varchar | 告警规则唯一ID |
| 通知策略ID | varchar |通知策略ID |
| 创建时间 | varchar | 创建时间 |
| 更新时间 | varchar | 更新时间 |
| 发送状态 | varchar | 0未发送;1已发送 |

2. Prometheus、Alertmanager组件配置

2.1 告警规则YML文件

2.2 Alertmanager.YML文件配置

route:
group_by: ['alertname', 'cluster', 'service']
group_wait: 1s
group_interval: 30s
repeat_interval: 40s
receiver: 'web.hook'
receivers:

2.3 Prometheus.YML文件配置

global:
scrape_interval: 15s
evaluation_interval: 15s
alerting:
alertmanagers:
- static_configs:
- targets: ['localhost:9093']
rule_files:

  • "/Users/wjf/Desktop/yml/*.yml"

scrape_configs:

  • job_name: "prometheus"
    static_configs:
    • targets: ["localhost:9090"]
  • job_name: "node"
    static_configs:
    • targets: ["localhost:9100"]

3. 代码逻辑设计

3.0 根据数据生成告警规则YML文件

SnakeYAML生成Prometheus告警规则.yml文件
// 创建告警规则对象
List<Map<String, Object>> rules = new ArrayList<>();

    Map<String, Object> alertRule = new HashMap<>();  
    alertRule.put("alert", "HighRequestLatency");  
    alertRule.put("expr", "job:request_latency_seconds:mean5m{job=\"myjob\"} > 1");  
    alertRule.put("for", "10m");  
    Map<String, String> labels = new HashMap<>();  
    labels.put("severity", "page");  
    alertRule.put("labels", labels);  
    Map<String, String> annotations = new HashMap<>();  
    annotations.put("summary", "High request latency");  
    annotations.put("description", "The job {{ $labels.job }} has a high request latency.");  
    alertRule.put("annotations", annotations);  
    rules.add(alertRule);  

    // 创建告警规则组对象  
    Map<String, Object> ruleGroup = new HashMap<>();  
    ruleGroup.put("name", "example-group");  
    ruleGroup.put("rules", rules);  

    // 创建顶级对象结构  
    Map<String, Object> root = new HashMap<>();  
    root.put("groups", List.of(ruleGroup));  

    // 配置YAML的序列化选项  
    DumperOptions options = new DumperOptions();  
    options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);  
    options.setPrettyFlow(true);  
    Yaml yaml = new Yaml(options);  

    // 将告警规则对象序列化为YAML字符串  
    String yamlString = yaml.dump(root);  

    // 将YAML字符串写入文件  
    try (FileWriter writer = new FileWriter("alert_rules.yml")) {  
        writer.write(yamlString);  
    } catch (IOException e) {  
        e.printStackTrace();  
    } 

3.1 将Alertmanager的告警消息保存到MySQL数据库

(1)Alertmanager的配置文件中设置一个Webhook,以便在触发告警时发送HTTP POST请求到你的Java服务。
image
(2)Alertmanager发送的告警消息通常是JSON格式的。你需要编写代码来解析这些JSON消息,提取告警标题、描述、标签等信息。

3.2 定时任务定时扫描告警消息表

(1)需要写一个定时任务方法,定时扫描告警消息表,查询待发送的告警消息,获取到待发送的告警消息集合

3.3 根据通知策略表的通知时间段、通知周期判断消息何时发送

(1)查询当前时间是否在通知时间段-开始、通知时间段-结束 时间区间之间;不在则跳过该条消息,在则继续下一步。
(2)根据告警策略唯一ID去 告警消息表查询最近一次发送告警的时间,然后根据当前时间 - 最近一次发送告警时间;如果小于通知周期时间则跳过该条消息;大于则进行下一步。