nginx中proxy_cache与limit_rate共用时,限速必须置于启用缓存的location块内,确保缓存命中与回源均生效;需禁用sendfile、注意gzip压缩后限速、合理处理range请求,并通过cache-control绕过缓存验证限速效果。

在 Nginx 中结合代理缓存(proxy_cache)配置下行带宽限速,核心原则是:限速必须作用于最终发往客户端的响应流,且不能干扰缓存逻辑。关键在于明确 limit_rate 的生效位置、与缓存模块的协作关系,以及避开常见冲突点。
限速指令必须放在缓存生效后的响应路径上
proxy_cache 本身不改变响应内容或传输节奏,它只决定是否从本地磁盘/内存读取响应体并直接返回。因此,limit_rate 必须放在 location 块中(而非 upstream 或 http 全局),确保无论响应来自缓存还是回源,都经过同一限速出口:
- 正确写法:在启用缓存的 location 内直接写
limit_rate,例如:location /downloads/ {<br> proxy_cache my_cache;<br> proxy_pass http://backend;<br> limit_rate 200k;<br> limit_rate_after 1m;<br>} - 错误做法:把
limit_rate放在 upstream 块、server 顶层或 proxy_pass 所在的另一 location,会导致缓存命中时绕过限速 - 注意:
limit_rate对缓存未命中(首次回源)和缓存命中(serve from cache)均生效,因为 Nginx 是在构建响应时统一控制发送节奏
缓存与限速共存时的三个关键细节
proxy_cache 和 limit_rate 协同工作时,以下三点直接影响效果稳定性:
-
sendfile 需禁用或谨慎搭配:若开启
sendfile on,Linux 内核可能绕过用户态限速逻辑,造成首包突增。建议显式关闭:sendfile off;;如必须开启,需加tcp_nodelay on;并配合limit_rate_after缓解抖动 -
gzip 压缩后限速:若启用
gzip on,limit_rate限制的是压缩后的字节数(即真实网络流量),不是原始文件大小。例如一个 10MB 的日志文件 gzip 后剩 1.2MB,则限速按这 1.2MB 计算 -
range 请求需单独处理:客户端断点续传(Range: bytes=xxx-)会触发多个子请求,每个子请求独立计算
limit_rate_after。设limit_rate_after 2m,则每个 range 都有前 2MB 不限速——这对大文件分片下载是合理的,但要注意总并发数仍受limit_conn约束
避免缓存导致的“限速失效”错觉
实际观察中常误判限速未生效,其实多为缓存行为干扰:
-
首次访问慢、后续快?:首次回源 + 限速 → 感知到压速;缓存命中后响应极快 → 误以为限速“失效”。验证方法:用
curl -H "Cache-Control: no-cache" -s -w '%{speed_download}\n' -o /dev/null http://x/x.zip强制跳过缓存实测 -
部分文件没被限速?:检查 location 是否匹配文件类型。例如只对 ZIP 限速:
location ~ \.(zip|iso)$ { limit_rate 100k; },而 PNG、JS 文件不受影响 -
缓存过期策略影响体验:若
proxy_cache_valid 200 1h;,则一小时内所有相同请求都走缓存,无法体现限速波动。如需调试,可临时设为proxy_cache_valid 200 5s;
推荐的完整配置模板
适用于代理缓存 + 大文件下载限速场景,兼顾首屏体验与带宽控制:
proxy_cache_path /var/cache/nginx/download_cache levels=1:2 keys_zone=download_cache:100m max_size=10g inactive=30m;
server {
listen 80;
server_name files.example.com;
<pre class="brush:php;toolbar:false;">location /dl/ {
proxy_cache download_cache;
proxy_cache_valid 200 206 1h;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_lock on;
proxy_cache_lock_timeout 5s;
proxy_pass https://origin-server;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# 关键:限速放在这里,作用于缓存/回源统一出口
limit_rate_after 2m;
limit_rate 300k;
# 避免 sendfile 干扰
sendfile off;
tcp_nodelay on;
# 可选:防单 IP 过度并发
limit_conn perip 3;
limit_conn_zone $binary_remote_addr zone=perip:10m;
}}











