文章

AIOps 实践与智能运维

AIOps 实践与智能运维

一句话:AIOps 不是”AI 取代运维”,而是用算法处理人脑处理不了的海量监控数据——异常检测、告警降噪、根因推断、容量预测——让告警更准、定位更快、容量更合理。

概述

SRE Agent 侧重”Agent 架构 + 工具串联”,AIOps 侧重”算法 + 数据分析”。两者互补:

SRE Agent = 用 LLM 做推理和工具调用(侧重"怎么执行")
AIOps     = 用 ML/统计算法做异常检测和模式识别(侧重"怎么发现")

AIOps 能力全景

graph TD
    subgraph 数据层
        METRICS[指标流]
        LOGS[日志流]
        TRACES[追踪流]
        EVENTS[变更事件]
    end
    
    subgraph 算法层
        AD[异常检测<br/>时序分析 / 统计模型]
        CD[告警降噪<br/>聚类 / 关联 / 抑制]
        RCA[根因推断<br/>拓扑关联 / 因果推断]
        CP[容量预测<br/>趋势预测 / 容量推演]
    end
    
    subgraph 输出层
        SMART_ALERT[智能告警]
        RCA_REPORT[根因报告]
        CAPACITY_PLAN[容量建议]
    end
    
    METRICS --> AD
    LOGS --> AD
    TRACES --> RCA
    EVENTS --> RCA
    
    AD --> CD
    CD --> SMART_ALERT
    RCA --> RCA_REPORT
    METRICS --> CP
    CP --> CAPACITY_PLAN

能力一:智能异常检测

传统告警的问题

传统阈值告警的困境:
  - 静态阈值:白天 1000 QPS 正常,凌晨 100 QPS 也正常 → 固定阈值误报多
  - 窗口固定:周末 vs 工作日、节假日 vs 日常 → 季节性模式被忽略
  - 单维度:只看 CPU 或只看 QPS → 多维关联异常无法发现
  - 噪音大:阈值敏感 → 误报多 → 告警疲劳 → 真正故障被忽略

时序异常检测算法

算法类型适用场景优点缺点
3-Sigma / Z-Score统计正态分布数据简单快速不适合非正态分布
IQR统计非正态分布鲁棒性强灵敏度低
EWMA平滑渐变趋势响应快滞后
Holt-Winters分解季节性数据适合周期模式需调参
Prophet分解复杂季节性自动调参较重
Isolation ForestML多维异常无需分布假设需训练
LSTM-AE深度学习复杂时序捕捉长期依赖需大量数据

Python 实现示例

import numpy as np
from collections import deque

class MultiStrategyAnomalyDetector:
    """多策略异常检测器"""
    
    def __init__(self, strategy="auto"):
        self.strategy = strategy
    
    def detect(self, series: list[float], 
               timestamps: list[float]) -> list[dict]:
        """检测时序异常"""
        
        if self.strategy == "auto":
            # 根据数据特征自动选择策略
            strategy = self._select_strategy(series)
        else:
            strategy = self.strategy
        
        if strategy == "zscore":
            return self._zscore_detect(series, timestamps)
        elif strategy == "iqr":
            return self._iqr_detect(series, timestamps)
        elif strategy == "ewma":
            return self._ewma_detect(series, timestamps)
        elif strategy == "seasonal":
            return self._seasonal_detect(series, timestamps)
    
    def _select_strategy(self, series):
        """自动选择策略"""
        # 检查是否有季节性
        if self._has_seasonality(series):
            return "seasonal"
        # 检查是否正态分布
        if self._is_normal(series):
            return "zscore"
        return "iqr"
    
    def _zscore_detect(self, series, timestamps, threshold=3):
        """Z-Score 检测"""
        mean = np.mean(series)
        std = np.std(series)
        anomalies = []
        for i, (val, ts) in enumerate(zip(series, timestamps)):
            z = (val - mean) / std if std > 0 else 0
            if abs(z) > threshold:
                anomalies.append({
                    "timestamp": ts,
                    "value": val,
                    "zscore": z,
                    "expected": mean,
                    "deviation": f"{abs(z):.1f} sigma",
                })
        return anomalies
    
    def _ewma_detect(self, series, timestamps, alpha=0.3, threshold=3):
        """EWMA 检测:适合渐变趋势"""
        ewma = [series[0]]
        anomalies = []
        for i in range(1, len(series)):
            new_ewma = alpha * series[i] + (1 - alpha) * ewma[-1]
            ewma.append(new_ewma)
            
            # 用 EWMA 的方差作为动态阈值
            ewma_std = np.std(ewma[max(0, i-20):i+1])  # 滑动窗口
            if ewma_std > 0:
                z = (series[i] - new_ewma) / ewma_std
                if abs(z) > threshold:
                    anomalies.append({
                        "timestamp": timestamps[i],
                        "value": series[i],
                        "expected": new_ewma,
                        "zscore": z,
                    })
        return anomalies
    
    def _has_seasonality(self, series):
        """检查季节性(简化版:自相关)"""
        if len(series) < 48:  # 至少 2 天的小时数据
            return False
        lag = 24  # 假设日周期
        if len(series) <= lag:
            return False
        corr = np.corrcoef(series[:-lag], series[lag:])[0, 1]
        return corr > 0.5
    
    def _is_normal(self, series):
        """检查是否近似正态分布"""
        if len(series) < 30:
            return True  # 数据少时假设正态
        # 用 Shapiro-Wilk 检验(简化版)
        mean = np.mean(series)
        std = np.std(series)
        if std == 0:
            return True
        skewness = np.mean(((np.array(series) - mean) / std) ** 3)
        return abs(skewness) < 1  # 偏度 < 1

Prometheus 异常检测规则

# 基于 predict_linear 的异常检测
- alert: AnomalyDetected
  expr: |
    # 实际值偏离预测值超过 3 倍标准差
    abs(
      rate(http_requests_total[5m]) 
      - predict_linear(rate(http_requests_total[7d])[7d:1h], 0)
    ) > 3 * stddev_over_time(rate(http_requests_total[7d])[7d:1h])
  for: 10m
  labels:
    severity: warning
    type: anomaly
  annotations:
    summary: "{{ $labels.service }} 流量异常检测触发"

# 基于历史同比的异常检测
- alert: DailyComparisonAnomaly
  expr: |
    # 当前 1h QPS vs 昨天同时段 1h QPS,偏差 > 50%
    abs(
      sum(rate(http_requests_total[1h])) by (service)
      - sum(rate(http_requests_total[1h] offset 1d)) by (service)
    ) / sum(rate(http_requests_total[1h] offset 1d)) by (service) > 0.5
  for: 15m
  labels:
    severity: warning
    type: anomaly

能力二:告警智能降噪

问题

告警风暴场景:
  14:00: 节点 A NotReady
  14:00:01 节点 A 上 Pod-1 down(×10 个 Pod)
  14:00:02 节点 A 上 Pod-2 down
  14:00:03 服务 A 依赖 Pod-1,成功率下降告警
  14:00:04 服务 B 依赖 Pod-2,延迟升高告警
  14:00:05 服务 C 依赖服务 A,级联告警
  ...
  → On-Call 收到 50+ 条告警,根本看不过来

降噪策略

策略做法效果
告警分组同一服务/节点的告警合并为一条50 条 → 5 条
因果关联识别因果链,只通知根因告警5 条 → 1 条
抑制(Inhibit)高严重度告警抑制低严重度告警减少噪音
频率限制同一告警 N 分钟内只通知一次防告警风暴
智能路由按根因分类路由到不同 On-Call减少误叫

Alertmanager 降噪配置

route:
  group_by: ['service', 'node']    # 按服务和节点分组
  group_wait: 30s                   # 等 30 秒收集同组告警
  group_interval: 5m               # 同组告警间隔
  repeat_interval: 4h              # 重复通知间隔
  receiver: 'default'
  routes:
    - match:
        severity: critical
      receiver: 'pagerduty'
      group_wait: 10s              # 紧急告警快速通知
    - match:
        severity: warning
      receiver: 'ticket'
      group_wait: 60s              # 非紧急等 1 分钟

inhibit_rules:
  # 节点 NotReady 时抑制该节点上的所有 Pod 告警
  - source_match:
      alertname: NodeNotReady
    target_match_re:
      alertname: PodDown|PodCrashLoop
    equal: ['node']
  
  # 服务 critical 告警时抑制 warning 告警
  - source_match:
      severity: critical
    target_match:
      severity: warning
    equal: ['service']

智能根因关联

class AlertCorrelator:
    """告警关联分析:识别因果链"""
    
    def __init__(self):
        self.dependency_graph = {}  # 服务依赖图
        self.alert_history = deque(maxlen=1000)
    
    def correlate(self, new_alert: dict) -> dict:
        """分析新告警与历史告警的关联"""
        
        # Step 1: 找时间窗口内的告警(前 5 分钟)
        recent = [
            a for a in self.alert_history
            if (new_alert["timestamp"] - a["timestamp"]).total_seconds() < 300
        ]
        
        # Step 2: 按依赖关系构建因果链
        causal_chain = self._find_causal_chain(new_alert, recent)
        
        # Step 3: 判断是否是根因
        if not causal_chain:
            # 没有上游告警 → 可能是根因
            self.alert_history.append(new_alert)
            return {
                "alert": new_alert,
                "is_root_cause": True,
                "suppressed_alerts": [],
            }
        else:
            # 有上游告警 → 是级联告警,抑制
            self.alert_history.append(new_alert)
            return {
                "alert": new_alert,
                "is_root_cause": False,
                "caused_by": causal_chain[0],
                "suppressed_alerts": [new_alert["alert_id"]],
                "root_cause_alert": causal_chain[-1],
            }
    
    def _find_causal_chain(self, alert, recent):
        """基于依赖图找因果链"""
        chain = []
        for r in recent:
            # 如果告警的服务依赖了上游告警的服务
            if r["service"] in self.dependency_graph.get(alert["service"], []):
                chain.append(r)
        return chain

能力三:根因自动推断

拓扑关联分析

class RootCauseInferencer:
    """根因推断:基于服务拓扑 + 时间窗口"""
    
    def __init__(self, topology):
        """
        topology: 服务调用拓扑
        {
            "api-gateway": ["order-svc", "user-svc"],
            "order-svc": ["mysql", "redis"],
            "user-svc": ["mysql", "kafka"],
        }
        """
        self.topology = topology
    
    def infer(self, anomalies: list[dict]) -> dict:
        """
        输入一批同时段异常,推断最可能的根因
        
        anomalies = [
            {"service": "api-gateway", "metric": "error_rate", "value": 0.15, "time": T},
            {"service": "order-svc", "metric": "error_rate", "value": 0.30, "time": T-10},
            {"service": "mysql", "metric": "connections", "value": 0.95, "time": T-30},
        ]
        """
        # Step 1: 按时间排序(最早的异常最可能是根因)
        sorted_anomalies = sorted(anomalies, key=lambda x: x["time"])
        
        # Step 2: 构建异常服务集合
        anomaly_services = {a["service"] for a in sorted_anomalies}
        
        # Step 3: 找最深的根(没有上游异常的服务)
        candidates = []
        for svc in anomaly_services:
            upstream = self.topology.get(svc, [])
            upstream_anomalies = set(upstream) & anomaly_services
            if not upstream_anomalies:
                # 没有上游异常 → 最可能的根因
                candidates.append(svc)
        
        # Step 4: 如果有多个候选,取最早的
        if candidates:
            earliest = min(
                candidates,
                key=lambda s: next(
                    a["time"] for a in sorted_anomalies if a["service"] == s
                )
            )
            return {
                "root_cause_service": earliest,
                "confidence": "high" if len(candidates) == 1 else "medium",
                "anomaly_chain": self._build_chain(earliest, anomaly_services),
                "all_anomalies": sorted_anomalies,
            }
        
        return {"root_cause_service": None, "confidence": "low"}
    
    def _build_chain(self, root, anomaly_services):
        """从根因开始构建影响链"""
        chain = [root]
        visited = {root}
        
        # BFS 找下游被影响的服务
        queue = [root]
        while queue:
            svc = queue.pop(0)
            for downstream, deps in self.topology.items():
                if svc in deps and downstream in anomaly_services and downstream not in visited:
                    chain.append(downstream)
                    visited.add(downstream)
                    queue.append(downstream)
        
        return chain

能力四:容量智能预测

class CapacityPredictor:
    """容量预测:基于历史趋势预测资源需求"""
    
    def predict(self, history: list[float], days_ahead: int = 7) -> dict:
        """
        基于历史数据预测未来容量需求
        """
        from numpy.polynomial import polynomial as P
        
        x = np.arange(len(history))
        y = np.array(history)
        
        # 线性回归
        coeffs = np.polyfit(x, y, 1)
        slope, intercept = coeffs
        
        # 预测
        future_x = np.arange(len(history), len(history) + days_ahead * 24)
        prediction = slope * future_x + intercept
        
        # 计算何时达到容量上限
        capacity_limit = self._get_capacity_limit()
        if slope > 0:
            days_until_full = int((capacity_limit - intercept) / slope / 24 - len(history) / 24)
        else:
            days_until_full = -1  # 不增长
        
        return {
            "current_value": history[-1],
            "predicted_7d": prediction[-1],
            "predicted_30d": slope * (len(history) + 30 * 24) + intercept,
            "capacity_limit": capacity_limit,
            "days_until_full": days_until_full,
            "growth_rate_daily": slope * 24,
            "recommendation": (
                f"URGENT: {days_until_full} 天后容量耗尽" if 0 < days_until_full < 14
                else f"PLAN: {days_until_full} 天后需扩容" if days_until_full < 30
                else "OK: 容量充足"
            ),
        }

AIOps 成熟度

级别特征技术栈
L1静态阈值告警Prometheus + Alertmanager
L2动态阈值 + 基于同比predict_linear + 历史对比
L3异常检测算法统计模型 + 时序分解
L4智能降噪 + 根因推断拓扑分析 + 因果推断
L5预测性运维 + 自愈ML 预测 + 自动修复

与 SRE Agent 的协同

告警触发 → AIOps 降噪(识别根因告警)

SRE Agent 接管 → 告警分析(LLM 归因 + RAG 检索)

SRE Agent → 故障诊断(工具链串联排查)

AIOps → 根因推断验证(拓扑关联确认)

SRE Agent → 执行修复(受限自动操作 or 人工审批)

AIOps → 验证恢复(异常消失确认)

常见问题 / 坑点

问题原因解决方案
异常检测误报多算法不适应季节性用季节性分解 + 动态基线
告警降噪过度关联规则太激进保守策略:宁可多报不漏报
根因推断不准拓扑图过时定期更新服务依赖图
ML 模型漂移业务变化后模型失效定期重训练 + 模型监控
算法太重生产环境扛不住轻量统计算法优先,ML 做离线分析

关联知识

参考资源

状态

  • AIOps 能力全景
  • 智能异常检测
  • 告警智能降噪
  • 根因自动推断
  • 容量智能预测
  • 与 SRE Agent 的协同
  • 成熟度模型