Prometheus+Alertmanager 實戰:告警消息推送至自定義接口
前言
在監控系統中,及時將告警信息推送至業務系統、運維平臺或通知渠道是保障系統穩定性的關鍵環節。
本文將詳細介紹如何通過Prometheus+Alertmanager構建監控告警體系,并將告警消息推送至自定義接口,包含完整配置、告警格式解析及實戰代碼。
整體架構與工作流程
Prometheus與Alertmanager的協同工作流程如下:
- 數據采集:Prometheus通過Exporter采集目標服務的監控指標(如CPU使用率、內存占用等)。
- 告警規則觸發:Prometheus根據預定義的告警規則,判斷指標是否超過閾值,若觸發則生成告警。
- 告警聚合與路由:Alertmanager接收Prometheus的告警,進行去重、分組、抑制處理后,通過 Webhook 推送到自定義接口。
- 自定義處理:自定義接口接收告警消息,進行存儲、展示、轉發等業務處理。
圖片
實現
配置 Prometheus(定義告警規則)
Prometheus負責監控指標采集和告警規則判斷,需配置指標采集目標和告警規則。
基礎配置(prometheus.yml)
global:
scrape_interval: 15s # 采集間隔
evaluation_interval: 15s # 告警規則評估間隔
scrape_configs:
- job_name: 'node_exporter'# 采集節點監控數據(服務器CPU、內存等)
static_configs:
- targets: ['192.168.1.100:9100', '192.168.1.101:9100'] # 目標節點IP:端口
rule_files:
- "alert_rules.yml"# 告警規則文件路徑
alerting:
alertmanagers:
- static_configs:
- targets: ['192.168.1.200:9093'] # Alertmanager地址告警規則配置(alert_rules.yml)
定義具體的告警觸發條件,包含標簽(labels)和注釋(annotations):
groups:
- name: 服務器基礎監控
rules:
# 1. CPU使用率過高告警
- alert: HighCpuUsage
expr: 100 - (avg(rate(node_cpu_seconds_total{mode="idle"}[5m])) by (instance) * 100) > 80
for: 2m # 持續2分鐘觸發告警
labels:
severity: critical # 告警級別:critical(嚴重)/warning(警告)
service: node # 業務標簽:用于路由分類
annotations:
summary: "服務器CPU使用率過高"
description: "實例 {{ $labels.instance }} 的CPU使用率超過80%,當前值:{{ $value | humanizePercentage }},持續時間:2分鐘"
threshold: "80%"# 自定義字段:閾值
value: "{{ $value | humanizePercentage }}"# 自定義字段:當前值
# 2. 內存使用率過高告警
- 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: "服務器內存使用率過高"
description: "實例 {{ $labels.instance }} 的內存使用率超過90%,當前值:{{ $value | humanizePercentage }}"核心字段說明:
- expr:PromQL查詢表達式,用于判斷是否觸發告警。
- for:持續時間,指標超過閾值持續該時間后才觸發告警。
- labels:告警標簽,用于Alertmanager路由和分組(如按severity區分級別)。
- annotations:告警描述信息,可包含自定義字段(如threshold)。
配置 Alertmanager(推送至自定義接口)
Alertmanager負責告警的聚合、路由和推送,通過webhook_configs配置自定義接口地址。
基礎配置(alertmanager.yml)
global:
resolve_timeout: 5m # 告警恢復判斷的超時時間
route:
group_by: ['alertname', 'service'] # 按告警名稱和服務分組
group_wait: 10s # 組內第一個告警觸發后,等待10s再發送(合并同組告警)
group_interval: 1m # 同一組告警再次發送的間隔
repeat_interval: 4h # 重復發送相同告警的間隔(避免頻繁通知)
receiver: 'custom-api'# 默認接收者
receivers:
- name: 'custom-api'
webhook_configs:
- url: 'http://192.168.1.300:8080/api/alert/receive'# 自定義接口地址
send_resolved: true# 發送告警恢復通知(status: resolved)
http_config:
# 接口認證配置(可選)
bearer_token: 'your-api-token'# 令牌認證
# basic_auth: # 基礎認證
# username: 'admin'
# password: 'secret'
# 進階:按標簽路由到不同接口(可選)
# routes:
# - match:
# severity: critical
# receiver: 'critical-api' # 嚴重告警發送到專用接口
# - match:
# severity: warning
# receiver: 'warning-api' # 警告告警發送到普通接口自定義接口開發(接收告警消息)
自定義接口需接收Alertmanager發送的POST請求,請求體為JSON格式,包含完整的告警信息。
告警消息 JSON 格式詳解
Alertmanager推送的JSON結構如下(包含firing和resolved兩種狀態):
{
"receiver": "custom-api",
"status": "firing", // 告警狀態:firing(觸發)/resolved(恢復)
"alerts": [
{
"status": "firing",
"labels": {
"alertname": "HighCpuUsage",
"instance": "192.168.1.100:9100",
"severity": "critical",
"service": "node"
},
"annotations": {
"summary": "服務器CPU使用率過高",
"description": "實例 192.168.1.100:9100 的CPU使用率超過80%,當前值:85%,持續時間:2分鐘",
"threshold": "80%",
"value": "85%"
},
"startsAt": "2023-10-01T08:30:00.000Z", // 告警開始時間
"endsAt": "0001-01-01T00:00:00Z", // 告警結束時間(恢復時更新)
"generatorURL": "http://prometheus:9090/graph?g0.expr=..." // 告警來源鏈接
}
],
"groupLabels": {
"alertname": "HighCpuUsage",
"service": "node"
},
"commonLabels": {
"alertname": "HighCpuUsage",
"service": "node"
},
"commonAnnotations": {},
"externalURL": "http://alertmanager:9093", // Alertmanager地址
"version": "4",
"groupKey": "{}/{alertname='HighCpuUsage',service='node'}"
}關鍵字段解析:
- status:全局告警狀態(與alerts[0].status一致)。
- alerts:告警數組(可能包含多個同組告警)。
- labels:告警標簽(用于分類和路由)。
- annotations:告警描述(包含自定義字段如threshold)。
- startsAt/endsAt:告警開始/結束時間(恢復時endsAt更新為實際時間)。
接口實現
使用Spring Boot開發自定義接口,解析告警消息并處理:
@RestController
@RequestMapping("/api/alert")
public class AlertReceiverController {
private static final Logger log = LoggerFactory.getLogger(AlertReceiverController.class);
// 存儲告警的數據庫操作(示例)
@Autowired
private AlertRecordService alertRecordService;
@PostMapping("/receive")
public ResponseEntity<String> receiveAlert(@RequestBody AlertMessage alertMessage) {
log.info("收到告警消息:{}", alertMessage);
// 1. 解析告警狀態
String globalStatus = alertMessage.getStatus();
log.info("全局告警狀態:{}", globalStatus);
// 2. 處理每個告警
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. 業務處理:存儲到數據庫
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);
// 若為恢復狀態,補充結束時間
if ("resolved".equals(globalStatus)) {
record.setEndTime(parseDateTime(alert.getEndsAt()));
}
alertRecordService.save(record);
}
return ResponseEntity.ok("告警接收成功");
}
// 時間格式轉換(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();
}
// 實體類定義(省略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;
}
}進階技巧
告警消息模板自定義
通過Alertmanager的模板功能,自定義推送至接口的 JSON 格式(如過濾字段、添加業務標識)。
在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 }}告警抑制(避免風暴)
通過inhibit_rules配置抑制規則,避免因一個故障引發大量關聯告警(如服務器宕機時,抑制該服務器的所有應用告警):
inhibit_rules:
- source_match:
severity: 'critical' # 源告警級別
target_match:
severity: 'warning' # 被抑制的告警級別
equal: ['instance'] # 當instance標簽相同時觸發抑制



























