Apache无法实现子域名级QPS限流,因其VirtualHost无内置策略引擎,LimitRequestRate等指令仅支持粗粒度控制;推荐用Apache作反向代理,将限流交由Nginx/Envoy等专业网关处理。

Apache 本身不支持子域名级的精细化 QPS 控制。VirtualHost 只负责请求路由和配置隔离,没有内置的每秒请求数(QPS)、令牌桶、用户级限流等策略引擎。所有看似“限速”的指令(如 LimitRequestRate、MaxRequestWorkers)都是全局或目录级的粗粒度控制,无法按 api.example.com 和 admin.example.com 分别设不同 QPS 上限。
为什么不能直接用 VirtualHost 配置做子域名 QPS 限流
关键限制在于:
-
LimitRequestRate控制的是单连接响应字节发送速率(KB/s),不是请求数,也不区分域名 -
mod_evasive的DOSSiteCount是全站总请求数阈值,无法绑定到某个Host头 -
mod_qos虽支持QS_SrvMaxReqPerSec并可用<If "%{HTTP_HOST} == 'xxx'">包裹,但它实际是进程级计数,多个子域名共享同一计数器——除非为每个子域启独立 Apache 实例(不现实) - 所有模块均在 SSL 终结后生效,HTTPS 流量需先解密才能识别 Host,无法在 TLS 层拦截
推荐方案:Apache 仅作反向代理,限流交给下游专用网关
生产环境最稳定、可扩展的做法是让 Apache 退为纯七层路由层,把 QPS 控制逻辑下沉到更专业的组件中。典型结构为:
客户端 → Apache(vhost + proxy_pass)→ Nginx / Envoy / 自研限流网关
- 每个子域名对应一个独立
ProxyPass,指向下游网关中预定义的 upstream - 例如:
api.example.com转发到http://qps-api-limiter,该 upstream 在 Nginx 中配置了limit_req zone=api burst=30 nodelay - Apache 配置保持极简,避免重写、头修改等操作,防止干扰下游基于
X-Real-IP或Host的限流标识
若必须只用 Apache:mod_qos 是唯一可行选项(但有硬伤)
需手动编译启用第三方模块:mod_qos,并显式加载:
Apache Superset 是一个广泛采用的开源 BI 平台,用于 SQL 探索、图表构建和仪表板交付。当代理需要查询仓库数据、组装仪表板或使用成熟的分析界面解释指标而不是临时笔记本代码时,此技能非常有用。
LoadModule qos_module modules/mod_qos.so
基本子域名限流配置示例:
<If "%{HTTP_HOST} == 'api.example.com'">
QS_SrvMaxReqPerSec 100
QS_SrvMaxConnPerIP 20
QS_SrvMinDataRate 1000 50000
</If>
注意要点:
- 该模块不支持分布式计数,QPS 是单机进程内统计,多实例部署时需额外协调
- 限流发生在请求处理阶段,无法防御 SYN Flood 等四层攻击
- 调试困难,日志粒度粗,错误码返回不标准(常为 503 或静默丢包)
- 不兼容 HTTP/2 流复用场景下的精确请求计量
替代思路:组合 mod_security + 自定义规则实现轻量级频控
利用 mod_security 的变量跟踪能力,可模拟简单 QPS 控制:
<IfModule security2_module>
SecAction "id:500001,phase:2,nolog,pass,initcol:ip=%{REMOTE_ADDR},setvar:ip.request_count=+1,expirevar:ip.request_count=60"
SecRule IP:REQUEST_COUNT "@gt 60" "id:500002,phase:2,deny,status:429,msg:'QPS limit exceeded for this IP'"
</IfModule>
这个规则对每个 IP 记录 60 秒内请求数,超 60 次即返回 429。它可配合 <If "%{HTTP_HOST} == 'xxx'"> 块使用,但本质仍是 IP 级频控,不是子域名维度的并发配额分配。

















