DDoS告警最容易走两个极端:要么一条都不响,要么一晚上响八十条没人看。本文用 10 个问答讲清 DDoS告警 该盯哪些指标、阈值怎么算、分级与抑制怎么做,附可直接套用的采集脚本和规则示例。
Q:为什么告警越多,真出事时越没人管?
- 告警的价值由「看到之后会行动的比例」决定,不是条数。
- 一条误报要花 5 到 10 分钟确认。一晚十条误报,值班的人第二天就会把通知静音。
- 告警疲劳比告警缺失更危险:真攻击来了,消息被埋在几十条噪声里。
- 合理目标是:每周 P1 告警不超过 2 条,且每条都真的需要人动手。
Q:DDoS 防御该盯哪几个指标?
- 入向带宽:最直观,但对小包洪水不敏感。
- 包速率 pps:小包攻击先炸 pps,带宽曲线还很平,只看带宽会漏。
- 新建连接速率:SYN Flood 与连接耗尽类攻击的核心特征。
- 半开连接数(
SYN_RECV):判断是不是被打在握手阶段。 - 业务成功率:最终判据。前四个是过程指标,业务挂了才是 P1。
Q:阈值怎么定?为什么静态拍数不行?
- 静态阈值(带宽过 500Mbps 就报)的问题在于业务本身有峰谷:夜里 100Mbps 是异常,白天 100Mbps 是正常。
- 用基线偏离更准:取近 7 天同小时的中位数或 P95,超过 3 倍且持续 2 分钟才触发。
- 基线必须按小时分桶,不要用全天平均,否则大促当天全是误报。
- 同时保留一条静态兜底(比如物理带宽的 80%),防止基线本身被长时间攻击污染。
IF=eth0
# 10 秒窗口估算入向带宽(Mbps),两次读取网卡计数取差值
r1=$(awk -F'[: ]+' -v i="$IF" '$0 ~ i {print $3; exit}' /proc/net/dev); sleep 10
r2=$(awk -F'[: ]+' -v i="$IF" '$0 ~ i {print $3; exit}' /proc/net/dev)
echo "in_mbps=$(( (r2-r1)*8/10/1000000 ))"
# pps 用 sar 取;列位随版本略有差异,先看表头再写死
sar -n DEV 1 5 | head -3
sar -n DEV 1 5 | awk -v i="$IF" '$2==i || $6==i' | tail -5
Q:为什么单指标告警误报特别多?
- 备份同步、爬虫补量、活动推广都能把带宽推上去,只看带宽必然误报。
- 组合条件更稳:带宽或 pps 超基线 3 倍,持续 2 分钟,且站点 5xx 比例在涨,三条同时满足才算 P1。
- 只满足前两条的进 P2 观察,不叫醒人。
- 组合会牺牲召回率,所以每条组合规则都要配一条兜底硬线,防止漏报。
Q:告警阈值和清洗阈值是一回事吗?
- 不是一回事。告警阈值是你自己判断「要不要人来看」;清洗阈值是防护设备判断「要不要开始清洗」。
- 两者错位就会出怪事:清洗阈值设得高,攻击打了五分钟设备还没动手;或者告警阈值设得高,清洗早开始了你才知道。
- 正确关系是告警阈值应当低于清洗阈值,让你在设备动手之前就掌握情况。
- 清洗阈值该设多少属于防护配置范畴,这里只强调两者的先后顺序不能倒。
Q:告警分级怎么定,几级够用?
- 三级最实用:P1 业务已受影响需立即处理;P2 有风险,30 分钟内查看;P3 只记录进日报,不通知人。
- 通知方式跟级别绑定:P1 打电话,P2 发群消息,P3 进日报。不绑定通知方式的分级没有意义。
- 每级写清响应时限和责任人,没有责任人的分级只是装饰。
- 级别由影响决定,不由流量大小决定。10G 打在静态资源上、业务正常,也只是 P2。
Q:告警抑制和聚合怎么做才不误事?
- 同源合并:同一 IP 段或同一攻击类型,5 分钟内只发一条,正文带上累计次数。
- 依赖抑制:源站不可达时,不再单独发「5xx 升高」,否则一条根因带出十条衍生告警。
- 维护窗口静默:发版、迁移前先静默,静默必须设自动结束时间,防止忘记恢复。
- 抑制规则要定期审计,抑制范围开太大,等于把监控关掉了一半。
# Prometheus 风格:组合条件 + 持续时间,避免单指标抖动
- alert: DdosP1
expr: |
(ddos_in_mbps > 3 * ddos_in_mbps_baseline
or ddos_pps > 3 * ddos_pps_baseline)
and on() (ddos_http_5xx_ratio > 0.02)
for: 2m
labels:
severity: P1
# 抑制:源站已不可达时,压掉所有衍生 P2
inhibit_rules:
- source_matchers: [alertname="OriginDown"]
target_matchers: [severity="P2"]
Q:告警风暴怎么压?
- 连续 N 次满足才触发(防抖),抖动型指标直接压掉。
- 触发和恢复的条件要分开写:触发要求 3 次,恢复要求连续 10 次正常,否则会在阈值上下反复报。
- 同一告警未恢复前不重复通知,只在状态变化时发一次。
- 一夜超过 20 条同类告警,说明阈值设错了,第二天必须调,不要靠忍。
# 5xx 比例的 1 分钟窗口,用来给告警条件当输入
awk '{t=int(substr($4,14,2)); n[t]++; if($9>=500) e[t]++}
END{for(k in n) printf "%02d时 5xx=%.1f%%\n", k, e[k]*100/n[k]}' \
/var/log/nginx/access.log | sort
Q:怎么验证告警准不准?
- 每月统计三个数:触发条数、真阳性条数、平均确认耗时。误报率超过 30% 就重设阈值。
- 用历史数据回放:把上个月一次真实攻击的曲线喂给规则,看是否在正确的时间点触发。
- 每季度做一次注入演练:压测把流量打到 2 倍基线,检查是否按级别通知到位。
- 演练必须包含「夜里没人盯手机」的场景,只测规则不测人,等于没测。
# alerts.csv 字段:时间,告警名,结果(TP/FP)
awk -F, 'NR>1{t++; if($3=="TP") tp++} END{printf "触发 %d 条,真阳性 %d,误报率 %.1f%%\n", t, tp, (t-tp)*100/t}' alerts.csv
Q:还有什么补充建议?
- 告警正文必须带三样:当前值、阈值、最近 5 分钟趋势,没有上下文的告警等于没告警。
- 把「谁被叫醒」和「谁能决策」分开,别叫醒了也做不了主。
- 规则文件纳入版本管理,改阈值要像改代码一样有人复核。
- 最后一句:好的 DDoS告警不是响得最狠的那套,是每次响都有人立刻知道该干什么的那套。