当 DDoS 攻击把带宽和连接表同时打到极限时,服务器能做的其实只有一件事:把有限的资源留给你最输不起的业务。本文用 9 个问答讲清 DDoS 业务优先级取舍的判定方法、网关层分流配置、分级降级策略与切换清洗的时机。
Q:为什么「所有业务一起保」等于全部保不住?
资源是守恒的。一次 20Gbps 的四层攻击会同时打满三样东西:出口带宽、连接跟踪表条目、内核的 SYN_RECV 队列。这三项都不是「多给点 CPU」能缓解的,所以平均分配的结果是每个业务都卡到不可用。
- 带宽被塞满后,所有业务的 RTT 一起抬升,支付接口超时率飙升。
- 连接表被打满后,新连接直接
SYN dropped,连 SSH 都进不去。 - 源站进程被大量半开连接拖住,健康检查失败,负载均衡把节点全部摘掉。
结论很直接:被攻击时的目标不是「都活着」,而是「核心业务活着」。取舍不是妥协,而是应急设计的一部分,必须提前写进预案,而不是等打上门才临时决定。
Q:怎么给业务定优先级?分几档比较合理?
建议分三档,判断标准是「停一小时损失多少」和「能不能事后补回来」:
- P0 不可停:登录鉴权、订单与支付、核心 API。停摆即直接损失收入,且无法补回。
- P1 可降级:商品详情、内容页、用户中心。可以变慢、可以少功能,但不能白屏。
- P2 可暂弃:图片与视频原图、导出下载、历史报表、站内搜索、统计与推荐位接口。
把这份清单写成一文件,而不是留在脑子里。示例结构:
# /etc/nginx/conf.d/priority.conf
# P0: /api/pay /api/auth /api/order
# P1: / /product /user
# P2: /static/img /download /export /search /stats
关键点:P2 的判定要往前放。攻击刚开始时就该把 P2 先摘掉,而不是等 P0 出问题了才动手,这时已经来不及了。
Q:「保谁弃谁」的判定依据是什么?
四个维度打分,不要只看访问量:
- 收入相关度:直接产生交易的最优先,展示类最低。
- 资源占用比:同样保 1 个 QPS,接口只吃 CPU 几毫秒,图片要吃几 MB 带宽。优先弃「单位请求消耗大」的。
- 可替代性:能走 CDN 的(静态资源)、能延迟处理的(报表导出)、能事后补的,全部排后面。
- 用户感知强度:白屏最刺眼,转圈次之,提示「功能维护中」感知最低。
# 现场看谁在吃资源:按请求的响应字节排序,找出消耗最大的路径
awk '{print $7, $10}' /var/log/nginx/access.log \
| awk '{s[$1]+=$2; c[$1]++} END {for(i in s) printf "%12.0f %8d %s\n", s[i], c[i], i}' \
| sort -rn | head -20
读法:字节数大但请求数少的路径,是最值得先弃的;请求数大但字节小的路径(比如 API),弃掉的收益低,应该保。
Q:怎么在 Nginx 或负载均衡层做业务级分流?
核心思路是给不同优先级打不同的限速与并发额度,让 P2 先被削掉,P0 始终有配额。用 map 按路径给不同 zone 是最干净的写法:
map $uri $biz_level {
default p1;
~^/api/(pay|auth|order) p0;
~^/(product|user) p1;
~^/(static|download|export|search|stats) p2;
}
map $biz_level $limit_key {
p0 ""; # P0 不限速,空 key 不计入 limit_req
p1 $binary_remote_addr;
p2 $binary_remote_addr;
}
limit_req_zone $limit_key zone=p1zone:10m rate=30r/s;
limit_req_zone $limit_key zone=p2zone:10m rate=2r/s;
server {
location / {
limit_req zone=p1zone burst=60 nodelay;
}
location ~ ^/(static|download|export|search|stats) {
limit_req zone=p2zone burst=5 nodelay;
limit_conn p2conn 2;
}
}
limit_conn_zone $binary_remote_addr zone=p2conn:10m;
两个注意点:一是 P0 用空 key 免限速的前提是它前面已经有鉴权,否则攻击者直接打 P0 路径就能绕过所有限制;二是所有限速都要配 limit_req_status 429,返回语义正确的错误码,方便前端做区分处理。
Q:图片和视频这类大流量业务被打了怎么办?
P2 里最典型的就是静态大文件。处置顺序是「先切走、再限速、最后才封」:
# 1. 把静态资源整段交给 CDN,源站只服务回源
location ~* \.(jpg|jpeg|png|gif|webp|mp4|zip)$ {
# 不在 CDN 回源白名单里的直连请求,直接拒绝
if ($http_x_from_cdn = "") { return 403; }
limit_conn dl 4;
limit_rate_after 1m;
limit_rate 2m;
expires 30d;
add_header Cache-Control "public, max-age=2592000";
}
要点说明:只要不是 CDN 回源就直接拒绝,这一步比限速有效得多,因为它把攻击流量挡在了 CDN 边缘,根本到不了源站带宽。同时防盗链要升级为签名 URL,只做 Referer 白名单很容易被伪造。
Q:数据库和接口层怎么保住?
应用层被打时,真正先崩的往往是数据库。三件事按顺序做:
- 读写分离 + 只读降级:攻击期间把非核心查询全部路由到只读库,主库只保留写入。
- 接口分级超时:P0 接口超时给 3 秒,P1 给 1 秒,P2 直接快速失败,不要让它占着连接池排队。
- 热点数据前置缓存:把商品、配置这类高频只读数据放 Redis,攻击期间缓存 TTL 临时延长到 10 分钟,容忍短暂数据陈旧换来可用性。
# 接口快速失败示例(Nginx proxy 层面)
location /api/ {
proxy_connect_timeout 1s;
proxy_read_timeout 3s;
proxy_next_upstream error timeout http_502;
proxy_cache api_cache;
proxy_cache_valid 200 10s;
proxy_cache_use_stale error timeout updating;
}
proxy_cache_use_stale 这一项在攻击期间价值极高:上游超时时直接返回陈旧缓存而不是报错,用户看到的是「数据有点旧」,而不是「服务不可用」。
Q:用户侧怎么降级?错误页和排队怎么做?
降级的核心是「让用户知道自己被限了,而不是以为网站坏了」:
- 静态化兜底:核心内容页预生成 HTML,数据库挂了也能返回。
- 排队页:用 302 跳到一个静态等待页,前端每 5 秒轮询一次放行接口,避免用户反复刷新加剧压力。
- 语义化错误页:503 页要写「当前访问量过大,请稍后重试」,不要返回默认的 Nginx 页面。
# 用 token 桶思路做排队:放行号小于阈值的才进真实服务
location = /queue {
default_type text/plain;
add_header Cache-Control "no-store";
return 200 "wait\n";
}
error_page 503 /static/overload.html;
location = /static/overload.html {
internal;
root /var/www/static;
add_header Retry-After 5;
}
Retry-After 头一定要加,很多正常的采集合规爬虫与浏览器会尊重它,能自发降低重试频率,这是几乎零成本的压力削减。
Q:什么时候该切高防或者进黑洞?
判定不看攻击的绝对带宽,而看源站还剩多少可用余量:
# 三个数一起看:出口带宽占用、CPU 使用、连接数
sar -n DEV 1 3 | grep -E "IFACE|eth0" # 带宽是否接近出口上限
ss -s # 连接总数与 TIME_WAIT 占比
uptime # 负载均值
- 带宽占用超过出口 70%、且持续 5 分钟以上:该切高防牵引了,源站自身已经没有处置空间。
- CPU 正常但带宽满:四层攻击,清洗层能解决,切高防或 CDN 分流都有效。
- 带宽正常但 CPU 和连接数飙升:七层攻击,切高防收益有限,应该走 WAF 加业务降级。
特别提醒:黑洞是最后手段,它会让你的 IP 完全不可达,包括 SSH。触发黑洞后必须用同机房的跳板机或服务商控制台处理,不要指望在失联的情况下远程操作。
Q:还有什么补充建议?
- 预案要提前演练一次。把「关掉 P2、切 CDN、开排队页」写成一键脚本,实测一遍耗时,攻击当天才不会手忙脚乱。
- P2 清单要按季度更新。业务上线后路径会变,旧清单可能把新核心业务误判成可弃对象。
- 降级要有开关和留痕。每次降级记录触发时间、原因、影响范围,否则事后复盘说不清是哪一步救了业务。
- 别把「加带宽」当下策而是最后手段。如果限速与分流都没做,加了带宽同样会被吃满,还会把成本曲线一起抬高。
一句话总结:DDoS 应急的本质是资源分配问题,而不是攻防技术问题。提前把业务分级、把降级开关做好,比临场指挥有效得多。