Prometheus+Alertmanager 實(shí)戰(zhàn):告警消息推送至自定義接口
前言
在監(jiān)控系統(tǒng)中,及時(shí)將告警信息推送至業(yè)務(wù)系統(tǒng)、運(yùn)維平臺(tái)或通知渠道是保障系統(tǒng)穩(wěn)定性的關(guān)鍵環(huán)節(jié)。
本文將詳細(xì)介紹如何通過(guò)Prometheus+Alertmanager構(gòu)建監(jiān)控告警體系,并將告警消息推送至自定義接口,包含完整配置、告警格式解析及實(shí)戰(zhàn)代碼。
整體架構(gòu)與工作流程
Prometheus與Alertmanager的協(xié)同工作流程如下:
- 數(shù)據(jù)采集:Prometheus通過(guò)Exporter采集目標(biāo)服務(wù)的監(jiān)控指標(biāo)(如CPU使用率、內(nèi)存占用等)。
- 告警規(guī)則觸發(fā):Prometheus根據(jù)預(yù)定義的告警規(guī)則,判斷指標(biāo)是否超過(guò)閾值,若觸發(fā)則生成告警。
- 告警聚合與路由:Alertmanager接收Prometheus的告警,進(jìn)行去重、分組、抑制處理后,通過(guò) Webhook 推送到自定義接口。
- 自定義處理:自定義接口接收告警消息,進(jìn)行存儲(chǔ)、展示、轉(zhuǎn)發(fā)等業(yè)務(wù)處理。
圖片
實(shí)現(xiàn)
配置 Prometheus(定義告警規(guī)則)
Prometheus負(fù)責(zé)監(jiān)控指標(biāo)采集和告警規(guī)則判斷,需配置指標(biāo)采集目標(biāo)和告警規(guī)則。
基礎(chǔ)配置(prometheus.yml)
global:
scrape_interval: 15s # 采集間隔
evaluation_interval: 15s # 告警規(guī)則評(píng)估間隔
scrape_configs:
- job_name: 'node_exporter'# 采集節(jié)點(diǎn)監(jiān)控?cái)?shù)據(jù)(服務(wù)器CPU、內(nèi)存等)
static_configs:
- targets: ['192.168.1.100:9100', '192.168.1.101:9100'] # 目標(biāo)節(jié)點(diǎn)IP:端口
rule_files:
- "alert_rules.yml"# 告警規(guī)則文件路徑
alerting:
alertmanagers:
- static_configs:
- targets: ['192.168.1.200:9093'] # Alertmanager地址告警規(guī)則配置(alert_rules.yml)
定義具體的告警觸發(fā)條件,包含標(biāo)簽(labels)和注釋(annotations):
groups:
- name: 服務(wù)器基礎(chǔ)監(jiān)控
rules:
# 1. CPU使用率過(guò)高告警
- alert: HighCpuUsage
expr: 100 - (avg(rate(node_cpu_seconds_total{mode="idle"}[5m])) by (instance) * 100) > 80
for: 2m # 持續(xù)2分鐘觸發(fā)告警
labels:
severity: critical # 告警級(jí)別:critical(嚴(yán)重)/warning(警告)
service: node # 業(yè)務(wù)標(biāo)簽:用于路由分類
annotations:
summary: "服務(wù)器CPU使用率過(guò)高"
description: "實(shí)例 {{ $labels.instance }} 的CPU使用率超過(guò)80%,當(dāng)前值:{{ $value | humanizePercentage }},持續(xù)時(shí)間:2分鐘"
threshold: "80%"# 自定義字段:閾值
value: "{{ $value | humanizePercentage }}"# 自定義字段:當(dāng)前值
# 2. 內(nèi)存使用率過(guò)高告警
- alert: HighMemoryUsage
expr: (node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes * 100 > 90
for: 5m
labels:
severity: warning
service: node
annotations:
summary: "服務(wù)器內(nèi)存使用率過(guò)高"
description: "實(shí)例 {{ $labels.instance }} 的內(nèi)存使用率超過(guò)90%,當(dāng)前值:{{ $value | humanizePercentage }}"核心字段說(shuō)明:
- expr:PromQL查詢表達(dá)式,用于判斷是否觸發(fā)告警。
- for:持續(xù)時(shí)間,指標(biāo)超過(guò)閾值持續(xù)該時(shí)間后才觸發(fā)告警。
- labels:告警標(biāo)簽,用于Alertmanager路由和分組(如按severity區(qū)分級(jí)別)。
- annotations:告警描述信息,可包含自定義字段(如threshold)。
配置 Alertmanager(推送至自定義接口)
Alertmanager負(fù)責(zé)告警的聚合、路由和推送,通過(guò)webhook_configs配置自定義接口地址。
基礎(chǔ)配置(alertmanager.yml)
global:
resolve_timeout: 5m # 告警恢復(fù)判斷的超時(shí)時(shí)間
route:
group_by: ['alertname', 'service'] # 按告警名稱和服務(wù)分組
group_wait: 10s # 組內(nèi)第一個(gè)告警觸發(fā)后,等待10s再發(fā)送(合并同組告警)
group_interval: 1m # 同一組告警再次發(fā)送的間隔
repeat_interval: 4h # 重復(fù)發(fā)送相同告警的間隔(避免頻繁通知)
receiver: 'custom-api'# 默認(rèn)接收者
receivers:
- name: 'custom-api'
webhook_configs:
- url: 'http://192.168.1.300:8080/api/alert/receive'# 自定義接口地址
send_resolved: true# 發(fā)送告警恢復(fù)通知(status: resolved)
http_config:
# 接口認(rèn)證配置(可選)
bearer_token: 'your-api-token'# 令牌認(rèn)證
# basic_auth: # 基礎(chǔ)認(rèn)證
# username: 'admin'
# password: 'secret'
# 進(jìn)階:按標(biāo)簽路由到不同接口(可選)
# routes:
# - match:
# severity: critical
# receiver: 'critical-api' # 嚴(yán)重告警發(fā)送到專用接口
# - match:
# severity: warning
# receiver: 'warning-api' # 警告告警發(fā)送到普通接口自定義接口開(kāi)發(fā)(接收告警消息)
自定義接口需接收Alertmanager發(fā)送的POST請(qǐng)求,請(qǐng)求體為JSON格式,包含完整的告警信息。
告警消息 JSON 格式詳解
Alertmanager推送的JSON結(jié)構(gòu)如下(包含firing和resolved兩種狀態(tài)):
{
"receiver": "custom-api",
"status": "firing", // 告警狀態(tài):firing(觸發(fā))/resolved(恢復(fù))
"alerts": [
{
"status": "firing",
"labels": {
"alertname": "HighCpuUsage",
"instance": "192.168.1.100:9100",
"severity": "critical",
"service": "node"
},
"annotations": {
"summary": "服務(wù)器CPU使用率過(guò)高",
"description": "實(shí)例 192.168.1.100:9100 的CPU使用率超過(guò)80%,當(dāng)前值:85%,持續(xù)時(shí)間:2分鐘",
"threshold": "80%",
"value": "85%"
},
"startsAt": "2023-10-01T08:30:00.000Z", // 告警開(kāi)始時(shí)間
"endsAt": "0001-01-01T00:00:00Z", // 告警結(jié)束時(shí)間(恢復(fù)時(shí)更新)
"generatorURL": "http://prometheus:9090/graph?g0.expr=..." // 告警來(lái)源鏈接
}
],
"groupLabels": {
"alertname": "HighCpuUsage",
"service": "node"
},
"commonLabels": {
"alertname": "HighCpuUsage",
"service": "node"
},
"commonAnnotations": {},
"externalURL": "http://alertmanager:9093", // Alertmanager地址
"version": "4",
"groupKey": "{}/{alertname='HighCpuUsage',service='node'}"
}關(guān)鍵字段解析:
- status:全局告警狀態(tài)(與alerts[0].status一致)。
- alerts:告警數(shù)組(可能包含多個(gè)同組告警)。
- labels:告警標(biāo)簽(用于分類和路由)。
- annotations:告警描述(包含自定義字段如threshold)。
- startsAt/endsAt:告警開(kāi)始/結(jié)束時(shí)間(恢復(fù)時(shí)endsAt更新為實(shí)際時(shí)間)。
接口實(shí)現(xiàn)
使用Spring Boot開(kāi)發(fā)自定義接口,解析告警消息并處理:
@RestController
@RequestMapping("/api/alert")
public class AlertReceiverController {
private static final Logger log = LoggerFactory.getLogger(AlertReceiverController.class);
// 存儲(chǔ)告警的數(shù)據(jù)庫(kù)操作(示例)
@Autowired
private AlertRecordService alertRecordService;
@PostMapping("/receive")
public ResponseEntity<String> receiveAlert(@RequestBody AlertMessage alertMessage) {
log.info("收到告警消息:{}", alertMessage);
// 1. 解析告警狀態(tài)
String globalStatus = alertMessage.getStatus();
log.info("全局告警狀態(tài):{}", globalStatus);
// 2. 處理每個(gè)告警
for (AlertDetail alert : alertMessage.getAlerts()) {
// 提取核心信息
String alertName = alert.getLabels().get("alertname");
String instance = alert.getLabels().get("instance");
String severity = alert.getLabels().get("severity");
String summary = alert.getAnnotations().get("summary");
String description = alert.getAnnotations().get("description");
LocalDateTime startTime = parseDateTime(alert.getStartsAt());
// 3. 業(yè)務(wù)處理:存儲(chǔ)到數(shù)據(jù)庫(kù)
AlertRecord record = new AlertRecord();
record.setAlertName(alertName);
record.setInstance(instance);
record.setSeverity(severity);
record.setSummary(summary);
record.setDescription(description);
record.setStatus(globalStatus);
record.setStartTime(startTime);
// 若為恢復(fù)狀態(tài),補(bǔ)充結(jié)束時(shí)間
if ("resolved".equals(globalStatus)) {
record.setEndTime(parseDateTime(alert.getEndsAt()));
}
alertRecordService.save(record);
}
return ResponseEntity.ok("告警接收成功");
}
// 時(shí)間格式轉(zhuǎn)換(ISO 8601格式)
private LocalDateTime parseDateTime(String dateTimeStr) {
if (dateTimeStr == null || "0001-01-01T00:00:00Z".equals(dateTimeStr)) {
return null;
}
return LocalDateTime.parse(dateTimeStr, DateTimeFormatter.ISO_DATE_TIME)
.atZone(ZoneOffset.UTC)
.withZoneSameInstant(ZoneId.systemDefault())
.toLocalDateTime();
}
// 實(shí)體類定義(省略getter/setter)
public static class AlertMessage {
private String receiver;
private String status;
private List<AlertDetail> alerts;
private Map<String, String> groupLabels;
private Map<String, String> commonLabels;
private Map<String, String> commonAnnotations;
private String externalURL;
private String version;
private String groupKey;
}
public static class AlertDetail {
private String status;
private Map<String, String> labels;
private Map<String, String> annotations;
private String startsAt;
private String endsAt;
private String generatorURL;
}
}進(jìn)階技巧
告警消息模板自定義
通過(guò)Alertmanager的模板功能,自定義推送至接口的 JSON 格式(如過(guò)濾字段、添加業(yè)務(wù)標(biāo)識(shí))。
在alertmanager.yml中配置模板:
templates:
- '/etc/alertmanager/templates/custom_template.tmpl' # 模板文件路徑
receivers:
- name: 'custom-api'
webhook_configs:
- url: 'http://192.168.1.300:8080/api/alert/receive'
send_resolved: true
body: '{{ template "custom.alert" . }}' # 引用模板{{ define "custom.alert" }}
{
"alertId": "{{ .GroupKey }}",
"status": "{{ .Status }}",
"service": "{{ index .CommonLabels "service" }}",
"alerts": [
{{ range .Alerts }}
{
"instance": "{{ index .Labels "instance" }}",
"summary": "{{ .Annotations.summary }}",
"value": "{{ .Annotations.value }}"
}{{ if not loop.Last }},{{ end }}
{{ end }}
],
"timestamp": "{{ now }}"
}
{{ end }}告警抑制(避免風(fēng)暴)
通過(guò)inhibit_rules配置抑制規(guī)則,避免因一個(gè)故障引發(fā)大量關(guān)聯(lián)告警(如服務(wù)器宕機(jī)時(shí),抑制該服務(wù)器的所有應(yīng)用告警):
inhibit_rules:
- source_match:
severity: 'critical' # 源告警級(jí)別
target_match:
severity: 'warning' # 被抑制的告警級(jí)別
equal: ['instance'] # 當(dāng)instance標(biāo)簽相同時(shí)觸發(fā)抑制




























