<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>限流 on Zero Day Notes</title>
        <link>https://blog.5772447.xyz/tags/%E9%99%90%E6%B5%81/</link>
        <description>Recent content in 限流 on Zero Day Notes</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh</language>
        <lastBuildDate>Sun, 23 Nov 2025 22:51:12 +0000</lastBuildDate><atom:link href="https://blog.5772447.xyz/tags/%E9%99%90%E6%B5%81/index.xml" rel="self" type="application/rss+xml" /><item>
            <title>Nginx 限流误杀正常请求：阈值调优与复盘</title>
            <link>https://blog.5772447.xyz/posts/2025-11-23-%E4%B8%80%E6%AC%A1nginx%E9%99%90%E6%B5%81%E9%98%88%E5%80%BC%E8%BF%87%E4%BD%8E%E8%AF%AF%E6%9D%80%E6%AD%A3%E5%B8%B8%E7%94%A8%E6%88%B7%E8%AF%B7%E6%B1%82%E7%9A%84%E6%8E%92%E6%9F%A5%E8%AE%B0%E5%BD%95/</link>
            <pubDate>Sun, 23 Nov 2025 22:51:12 +0000</pubDate>
            <guid>https://blog.5772447.xyz/posts/2025-11-23-%E4%B8%80%E6%AC%A1nginx%E9%99%90%E6%B5%81%E9%98%88%E5%80%BC%E8%BF%87%E4%BD%8E%E8%AF%AF%E6%9D%80%E6%AD%A3%E5%B8%B8%E7%94%A8%E6%88%B7%E8%AF%B7%E6%B1%82%E7%9A%84%E6%8E%92%E6%9F%A5%E8%AE%B0%E5%BD%95/</guid>
            <description>&lt;h2 id=&#34;一问题背景&#34;&gt;&lt;a href=&#34;#%e4%b8%80%e9%97%ae%e9%a2%98%e8%83%8c%e6%99%af&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;一、问题背景&#xD;&#xA;&lt;/h2&gt;&lt;p&gt;我们的主站 &lt;code&gt;www.example.com&lt;/code&gt; 使用 Nginx 1.24 作为七层接入网关，前面是 CDN，后面挂 8 个应用节点。由于此前遭遇过一次恶性 CC 攻击，安全团队要求对核心接口加限流。目标是：拦住异常高频的刷接口行为，但&lt;strong&gt;不能影响正常用户的浏览和下单&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;限流方案采用 Nginx 原生的 &lt;code&gt;limit_req&lt;/code&gt; 模块（基于漏桶算法），按客户端 IP 做粒度。上线时间是周一下午，由运维在网关配置中新增了一段 &lt;code&gt;limit_req_zone&lt;/code&gt; + &lt;code&gt;limit_req&lt;/code&gt; 规则，并 &lt;code&gt;nginx -s reload&lt;/code&gt; 平滑生效。本以为只是&amp;quot;加一道保险&amp;quot;，没想到立刻引发客诉。&lt;/p&gt;&#xA;&lt;h2 id=&#34;二故障现象&#34;&gt;&lt;a href=&#34;#%e4%ba%8c%e6%95%85%e9%9a%9c%e7%8e%b0%e8%b1%a1&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;二、故障现象&#xD;&#xA;&lt;/h2&gt;&lt;p&gt;reload 后大约 10 分钟，客服群开始炸：大量用户反馈&amp;quot;页面打开就提示 503 Service Temporarily Unavailable&amp;quot;，且&lt;strong&gt;不是刷子，是普通用户&lt;/strong&gt;，包括公司内网同事自己访问也中招。&lt;/p&gt;&#xA;&lt;p&gt;监控侧：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Nginx &lt;code&gt;503&lt;/code&gt; 返回码占比从 0.1% 飙到 18%；&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;limit_req&lt;/code&gt; 拒绝计数（&lt;code&gt;$limit_req_status&lt;/code&gt;）持续高位：&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&#xA;&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;limit_req_status  rejected: 12453  (last 1 min)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;被拒的 IP 高度分散，并非集中在少数异常 IP，说明是&lt;strong&gt;正常流量被误杀&lt;/strong&gt;；&lt;/li&gt;&#xA;&lt;li&gt;应用节点 CPU、连接数都很低，证明后端完全健康，问题 100% 出在网关限流层。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;这与&amp;quot;防 CC&amp;quot;的目标完全背离：攻击没拦住多少，正常用户先被砍了一半。&lt;/p&gt;&#xA;&lt;h2 id=&#34;三排查过程&#34;&gt;&lt;a href=&#34;#%e4%b8%89%e6%8e%92%e6%9f%a5%e8%bf%87%e7%a8%8b&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;三、排查过程&#xD;&#xA;&lt;/h2&gt;&lt;p&gt;第一步，定位是哪条 limit_req 规则在拒绝。打开 Nginx 的 &lt;code&gt;limit_req_status&lt;/code&gt; 日志字段，确认返回 503 的请求都带 &lt;code&gt;limit_req_status=503&lt;/code&gt;，且命中的 zone 是 &lt;code&gt;perip&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;第二步，看配置。问题一目了然：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&#xA;&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1&#xA;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2&#xA;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3&#xA;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4&#xA;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5&#xA;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6&#xA;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7&#xA;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8&#xA;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9&#xA;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;http&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;limit_req_zone&lt;/span&gt; $binary_remote_addr &lt;span style=&#34;color:#e6db74&#34;&gt;zone=perip:10m&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;rate=2r/s&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;server&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;location&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;/&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;limit_req&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;zone=perip&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;burst=3&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;nodelay&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;proxy_pass&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;http://backend&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;三个致命点：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;strong&gt;&lt;code&gt;rate=2r/s&lt;/code&gt; 太小&lt;/strong&gt;：每个 IP 平均每秒只允许 2 个请求。现代网页一次打开就并发数十个请求（html + css + js + 图片 + api），瞬时远超 2/s。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;&lt;code&gt;burst=3&lt;/code&gt; 太小&lt;/strong&gt;：只缓冲 3 个超出请求就拒绝，正常用户的突发并发根本装不下。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;&lt;code&gt;nodelay&lt;/code&gt; 误用&lt;/strong&gt;：&lt;code&gt;nodelay&lt;/code&gt; 让 burst 内的请求不排队立即处理，等于把限流瞬时阈值直接抬到 &lt;code&gt;rate+burst=5&lt;/code&gt;，超出立刻 503，没有平滑过渡，正常用户的并发瞬间被打挂。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;第三步，验证判断。用正常浏览器行为模拟单 IP 的首屏请求数：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&#xA;&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1&#xA;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;2&#xA;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;3&#xA;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;4&#xA;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;5&#xA;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;6&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ curl -s -o /dev/null -w &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%{http_code}\n&amp;#34;&lt;/span&gt; https://www.example.com/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;200&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ &lt;span style=&#34;color:#75715e&#34;&gt;# 并发模拟首屏 20 个资源请求&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ seq &lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt; | xargs -P &lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt; -I&lt;span style=&#34;color:#f92672&#34;&gt;{}&lt;/span&gt; curl -s -o /dev/null -w &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%{http_code}\n&amp;#34;&lt;/span&gt; https://www.example.com/assets/&lt;span style=&#34;color:#f92672&#34;&gt;{}&lt;/span&gt; 2&amp;gt;/dev/null | sort | uniq -c&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;17&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;503&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;200&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;单 IP 并发 20 个请求，17 个被 503——完美复现用户&amp;quot;打开就报错&amp;quot;。这正是 &lt;code&gt;rate+burst=5&lt;/code&gt; 在 &lt;code&gt;nodelay&lt;/code&gt; 下的直接后果。&lt;/p&gt;&#xA;&lt;p&gt;第四步，确认 CDN 是否放大问题。由于前面是 CDN，回源到 Nginx 时客户端 IP 已被 &lt;code&gt;X-Forwarded-For&lt;/code&gt; 携带，但 &lt;code&gt;limit_req_zone&lt;/code&gt; 用的是 &lt;code&gt;$binary_remote_addr&lt;/code&gt;（即 CDN 边缘节点 IP）。这意味着&lt;strong&gt;所有经同一 CDN 节点回源的用户被当成同一个 IP 限流&lt;/strong&gt;，进一步把正常流量成片误杀。这是第二个隐藏坑。&lt;/p&gt;&#xA;&lt;h2 id=&#34;四解决方案&#34;&gt;&lt;a href=&#34;#%e5%9b%9b%e8%a7%a3%e5%86%b3%e6%96%b9%e6%a1%88&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;四、解决方案&#xD;&#xA;&lt;/h2&gt;&lt;p&gt;应急先回退，再给出正确配置：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;立即 &lt;code&gt;nginx -s reload&lt;/code&gt; 回退到无 limit_req 的版本，503 比例 1 分钟内归零，客诉停止。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;修正限流参数，按&amp;quot;正常用户首屏并发约 20~30 个请求、且允许一定突发&amp;quot;来设计：&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&#xA;&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1&#xA;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2&#xA;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3&#xA;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4&#xA;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5&#xA;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6&#xA;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7&#xA;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8&#xA;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9&#xA;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10&#xA;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11&#xA;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12&#xA;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13&#xA;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14&#xA;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;15&#xA;&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;16&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;http&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# 用真实客户端 IP（CDN 场景取 XFF 最左）&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;map&lt;/span&gt; $http_x_forwarded_for $client_real_ip {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;default&lt;/span&gt; $binary_remote_addr;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;~^(?P&amp;lt;first&amp;gt;\d+\.\d+\.\d+\.\d+)&amp;#34;&lt;/span&gt; $first;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;limit_req_zone&lt;/span&gt; $client_real_ip &lt;span style=&#34;color:#e6db74&#34;&gt;zone=perip:20m&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;rate=20r/s&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;server&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;location&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;/&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;limit_req&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;zone=perip&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;burst=40&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;delay=20&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;limit_req_status&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;429&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;proxy_pass&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;http://backend&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;要点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;rate=20r/s&lt;/code&gt; 容纳正常浏览；&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;burst=40&lt;/code&gt; 给足突发缓冲；&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;去掉 &lt;code&gt;nodelay&lt;/code&gt;&lt;/strong&gt;，改用 &lt;code&gt;delay=20&lt;/code&gt;：前 20 个超出的请求不延迟，其余进队列平滑处理，既保体验又防刷；&lt;/li&gt;&#xA;&lt;li&gt;限流拒绝码改为 &lt;code&gt;429&lt;/code&gt;（语义更准确），并基于 &lt;code&gt;X-Forwarded-For&lt;/code&gt; 取真实客户端 IP，避免 CDN 合并误杀。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;ol start=&#34;3&#34;&gt;&#xA;&lt;li&gt;对静态资源（/assets/、图片）&lt;strong&gt;不限流&lt;/strong&gt;，只对 API 和登录等敏感路径限流，进一步降低误杀面。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;灰度上线后观察 30 分钟：503/429 比例稳定在 0.3%，且被拒 IP 确为少数高频异常来源，正常用户零投诉。&lt;/p&gt;&#xA;&lt;h2 id=&#34;五根因分析&#34;&gt;&lt;a href=&#34;#%e4%ba%94%e6%a0%b9%e5%9b%a0%e5%88%86%e6%9e%90&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;五、根因分析&#xD;&#xA;&lt;/h2&gt;&lt;p&gt;根因是 &lt;strong&gt;&lt;code&gt;limit_req&lt;/code&gt; 阈值设计与实际流量模型严重错配&lt;/strong&gt;，叠加两个误用：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;rate&lt;/code&gt;/&lt;code&gt;burst&lt;/code&gt; 按&amp;quot;单请求流&amp;quot;想象设置（2r/s、burst 3），但浏览器首屏天然并发几十请求，正常行为就被判为&amp;quot;超限&amp;quot;；&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;nodelay&lt;/code&gt; 把漏桶本该的&amp;quot;平滑排队&amp;quot;变成&amp;quot;瞬间砍杀&amp;quot;，剥夺了缓冲；&lt;/li&gt;&#xA;&lt;li&gt;CDN 场景下用 &lt;code&gt;$binary_remote_addr&lt;/code&gt; 取到的是 CDN 节点 IP，等于把整片用户合并成一个被限流对象，放大误杀。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;本质上，限流是保护手段，但阈值必须建立在&lt;strong&gt;对正常用户行为基线的量化&lt;/strong&gt;之上，不能拍脑袋。&lt;/p&gt;&#xA;&lt;h2 id=&#34;六预防措施&#34;&gt;&lt;a href=&#34;#%e5%85%ad%e9%a2%84%e9%98%b2%e6%8e%aa%e6%96%bd&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;六、预防措施&#xD;&#xA;&lt;/h2&gt;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;先度量，再限流&lt;/strong&gt;：上线前用日志统计真实用户 P95/P99 的每 IP 请求速率与并发，阈值取正常峰值的 1.5~2 倍。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;慎用 &lt;code&gt;nodelay&lt;/code&gt;&lt;/strong&gt;：除非明确要&amp;quot;超 burst 立即拒绝&amp;quot;，否则用 &lt;code&gt;delay=&lt;/code&gt; 让超出请求排队，保住体验。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;CDN 后取真实 IP&lt;/strong&gt;：务必 &lt;code&gt;real_ip&lt;/code&gt; / &lt;code&gt;X-Forwarded-For&lt;/code&gt; 解析真实客户端地址，避免按边缘节点聚合限流。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;分级限流&lt;/strong&gt;：静态资源不限，敏感/写接口严限，做到&amp;quot;该拦的拦、该放的放&amp;quot;。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;灰度 + 监控&lt;/strong&gt;：新限流规则先 1 台网关灰度，盯 &lt;code&gt;limit_req_status&lt;/code&gt; 与 4xx 比例，确认无误再全量；拒绝码用 429 便于区分。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;返回友好提示&lt;/strong&gt;：对限流返回 429 + &lt;code&gt;Retry-After&lt;/code&gt; 头，前端做退避重试，避免用户看到生硬 503。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;七总结&#34;&gt;&lt;a href=&#34;#%e4%b8%83%e6%80%bb%e7%bb%93&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;七、总结&#xD;&#xA;&lt;/h2&gt;&lt;p&gt;这次故障是典型的&amp;quot;安全策略反噬业务&amp;quot;。&lt;code&gt;limit_req&lt;/code&gt; 本身没错，错在阈值是凭直觉设的、且 &lt;code&gt;nodelay&lt;/code&gt; 用错了地方。排查关键三步：&lt;code&gt;limit_req_status&lt;/code&gt; 日志确认拒绝来源 → 看 &lt;code&gt;rate/burst/nodelay&lt;/code&gt; 组合 → 用真实并发复现 503。记住三条铁律：限流阈值必须基于真实流量基线；&lt;code&gt;nodelay&lt;/code&gt; 不是默认选项；CDN 后面一定要还原真实客户端 IP。限流的目标是&amp;quot;拦坏人&amp;quot;，不是&amp;quot;误伤好人&amp;quot;，上线前做一次灰度观测，能省掉一次客诉危机。&lt;/p&gt;&#xA;</description>
        </item></channel>
</rss>
