CC防护反向代理层的连接数限制与队列管理,核心就是在Nginx、HAProxy或Cloudflare等反向代理中间件上,通过设定单个IP的并发连接上限、总连接数阈值以及请求排队机制,把恶意高频请求挡在应用服务器前面。具体做法是:在Nginx里用limit_conn_zone和limit_conn指令限制每IP并发数,用limit_req_zone配合burst和nodelay做请求速率控制,再配合队列超时策略把超出阈值的请求放入等待队列或直接拒绝。这套组合拳打下来,绝大多数CC攻击流量会被消化在代理层,后端服务基本不受影响。

为什么反向代理层必须做连接数限制

CC攻击的本质是用大量看似合法的HTTP请求压垮服务器。攻击工具通常会控制成千上万个IP或者少量IP高频发起请求,每个请求本身不复杂,但量大到足以让服务器线程池耗尽、数据库连接打满。反向代理作为流量入口,是第一道防线。如果代理层不做任何限制,所有请求直接透传到后端,那CC防护就形同虚设。连接数限制的意义在于:把"无限开放"变成"有限准入",让正常用户的请求能进来,把异常高频的请求拦在门外或者拖慢处理速度。

Nginx层面的连接数限制配置详解

Nginx是目前用得最多的反向代理,它原生支持两类限制:基于连接数的limit_conn和基于请求速率的limit_req。先说limit_conn,它限制的是同时建立的TCP连接数。配置方式如下:

http {
    # 定义限制区域,以客户端IP为key,10m内存大约能存16万个IP的状态
    limit_conn_zone $binary_remote_addr zone=conn_limit:10m;

    server {
        location / {
            # 每个IP最多允许10个并发连接
            limit_conn conn_limit 10;
            # 超过限制的请求返回503
            limit_conn_status 503;
        }
    }
}

再说limit_req,它限制的是单位时间内的请求数,更适合防CC。burst参数是关键,它定义了突发请求的缓冲区大小,nodelay表示超出部分立即处理还是排队。典型配置:

http {
    # 以IP为key,每秒1个请求,10m内存
    limit_req_zone $binary_remote_addr zone=req_limit:10m rate=1r/s;

    server {
        location / {
            limit_req zone=req_limit burst=20 nodelay;
            limit_req_status 503;
        }
    }
}

这里rate=1r/s意味着每个IP每秒只能发1个请求,burst=20允许瞬间突发20个请求排队处理,nodelay表示这20个请求不延迟直接处理但超出就拒绝。如果去掉nodelay,超出的请求会被延迟到速率允许时再处理,相当于一个简单的队列。

HAProxy的连接限制与队列机制

HAProxy在四层和七层都能做限制,适合高并发场景。它用stick-table来追踪每个IP的连接状态,配合tcp-request content和http-request track-sc0等指令实现精细控制。核心配置思路:

frontend http_front
    bind *:80
    # 追踪每个源IP的并发连接数
    stick-table type ip size 100k expire 30s store conn_cur,conn_rate(3s)

    # 超过50个并发连接的IP直接拒绝
    tcp-request content reject if { src_conn_cur ge 50 }

    # 每秒超过30个请求的IP进入慢速队列
    tcp-request content track-sc0 src if { src_conn_rate gt 30 }

default_backend web_servers

HAProxy的优势在于它能同时追踪连接数和请求速率,而且stick-table支持动态过期,内存占用可控。对于CC防护来说,HAProxy的队列管理更灵活,可以把超限请求路由到专门的"慢速后端",让攻击流量在一个隔离池里慢慢消耗,不影响正常业务。

队列管理的三种策略对比

队列管理是CC防护里最容易被忽视但极其重要的环节。当请求超过限制时,你有三种选择:直接拒绝、延迟处理、放入专用队列。直接拒绝最简单,返回503或429状态码,优点是资源消耗最小,缺点是可能误杀正常用户的突发请求。延迟处理是把超限请求缓存起来,按速率慢慢释放,优点是不丢请求,缺点是占用代理内存,队列满了还是得拒绝。专用队列是把超限请求转发到一个独立的后端池,这个池可以是一个专门的"黑洞"服务器或者一个返回静态页面的轻量服务,优点是隔离性好,不影响主业务,缺点是架构复杂一些。

实际生产环境中,推荐的做法是分级处理:第一级用limit_req做速率限制,正常请求直接通过;第二级对超出burst的请求做短时间排队(比如500ms内重试);第三级对持续超限的IP直接拉黑。这样既不会误杀正常用户的短暂高峰,又能有效消耗攻击流量。

连接数限制的参数调优要点

参数设置不是越严越好。如果limit_conn设成每个IP只能1个连接,那用户打开一个网页需要加载十几个资源,每个资源都要重新建连接,体验会非常差。一般建议:普通Web站点每个IP并发连接设5-15个,API接口设3-8个;limit_req的rate根据业务来,比如一个新闻站每秒5-10个请求算正常,电商站可能需要15-20个。burst值通常设为rate的3-5倍,给正常用户的突发行为留余量。另外,limit_conn_zone的内存大小要根据预期IP数来算,10m大约支持16万个IP状态,如果你的站点日活IP超过这个数,就要调大或者换用$remote_addr(更省内存但精度略低)。

配合WAF和行为分析做智能限流

单纯靠固定阈值的连接数限制,面对分布式CC攻击(大量不同IP同时发起请求)效果有限。这时候需要结合WAF的行为分析能力。比如检测到某个IP的请求模式异常(频繁访问同一URL、User-Agent异常、请求间隔过于均匀),就动态降低它的限额甚至直接封禁。Nginx可以通过lua模块或者ngx_http_limit_req_module的动态变量来实现这种智能限流。思路是:先用固定阈值挡住大部分攻击,再用行为分析识别漏网的精细攻击,两层叠加才够稳。

反向代理层的超时与队列溢出处理

队列不是无限的。当排队请求超过代理的缓冲区大小时,必须有溢出策略。Nginx里可以通过proxy_connect_timeout、proxy_read_timeout等指令控制后端等待时间,但更关键的是在limit_req层面设置队列大小。HAProxy的stick-table有maxconn参数可以限制追踪条目数。溢出时的处理建议:记录日志、返回503、同时触发告警通知运维。千万不要让队列无限增长,否则代理本身会被撑爆,CC防护变成了自我攻击。

监控与告警:连接数限制不是设完就不管了

部署了连接数限制之后,必须持续监控几个关键指标:每个IP的并发连接数分布、被拒绝请求的比例、队列长度变化、503状态码的增长趋势。如果某个时间段503突然飙升,可能是误杀了正常用户,需要调参数;如果被拒绝比例一直很低但后端负载很高,说明攻击流量绕过了代理层的限制,需要检查是否有直接访问后端IP的情况。推荐用Prometheus加Grafana做实时监控,把limit_conn和limit_req的状态暴露成指标,设置阈值告警。

总结:连接数限制是CC防护的基础但不是全部

反向代理层的连接数限制与队列管理,是CC防护体系里最基础也最有效的一环。它的核心逻辑就是"限流+排队+分级处理",通过Nginx的limit_conn/limit_req或者HAProxy的stick-table来实现。但要注意,这只是第一道防线,面对高级CC攻击还需要配合IP信誉库、验证码挑战、JS指纹识别、分布式限流等手段。把代理层的连接数限制做扎实,至少能挡住80%以上的CC攻击流量,让后端服务有喘息的空间去应对剩下的威胁。