<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>限流 on 寻 Mi 处</title>
        <link>https://blog.mibase.top/tags/%E9%99%90%E6%B5%81/</link>
        <description>Recent content in 限流 on 寻 Mi 处</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh</language>
        <lastBuildDate>Sun, 27 Apr 2025 03:28:00 +0800</lastBuildDate><atom:link href="https://blog.mibase.top/tags/%E9%99%90%E6%B5%81/index.xml" rel="self" type="application/rss+xml" /><item>
            <title>带宽一夜之间跑了 40G，原来是有人在爬我的站</title>
            <link>https://blog.mibase.top/p/%E5%B8%A6%E5%AE%BD%E4%B8%80%E5%A4%9C%E4%B9%8B%E9%97%B4%E8%B7%91%E4%BA%86-40g%E5%8E%9F%E6%9D%A5%E6%98%AF%E6%9C%89%E4%BA%BA%E5%9C%A8%E7%88%AC%E6%88%91%E7%9A%84%E7%AB%99/</link>
            <pubDate>Sun, 27 Apr 2025 03:28:00 +0800</pubDate>
            <guid>https://blog.mibase.top/p/%E5%B8%A6%E5%AE%BD%E4%B8%80%E5%A4%9C%E4%B9%8B%E9%97%B4%E8%B7%91%E4%BA%86-40g%E5%8E%9F%E6%9D%A5%E6%98%AF%E6%9C%89%E4%BA%BA%E5%9C%A8%E7%88%AC%E6%88%91%E7%9A%84%E7%AB%99/</guid>
            <description>&lt;img src=&#34;https://blog.mibase.top/p/%E5%B8%A6%E5%AE%BD%E4%B8%80%E5%A4%9C%E4%B9%8B%E9%97%B4%E8%B7%91%E4%BA%86-40g%E5%8E%9F%E6%9D%A5%E6%98%AF%E6%9C%89%E4%BA%BA%E5%9C%A8%E7%88%AC%E6%88%91%E7%9A%84%E7%AB%99/cover.jpg&#34; alt=&#34;Featured image of post 带宽一夜之间跑了 40G，原来是有人在爬我的站&#34; /&gt;&lt;p&gt;四月的某天，云厂商发来一条流量预警，说我这个月的出网流量已经用了 80%。&lt;/p&gt;&#xA;&lt;p&gt;我看了一眼统计，那天从凌晨到早上八点，跑了四十多个 G。平时一整天也就两三个 G。&lt;/p&gt;&#xA;&lt;p&gt;第一反应是被人盗链了。查了一下 nginx 的 access log，确实有几个 IP 在疯狂请求图片。&lt;/p&gt;&#xA;&lt;p&gt;但仔细一看，不对。它们请求的不只是图片，还有每一篇文章的 html，每个都带着不同的 UA，请求间隔很均匀，大概两百毫秒一次。这不是盗链，是有人在整站爬。&lt;/p&gt;&#xA;&lt;h2 id=&#34;先看清楚规模&#34;&gt;先看清楚规模&#xA;&lt;/h2&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;awk &lt;span class=&#34;s1&#34;&gt;&amp;#39;{print $1}&amp;#39;&lt;/span&gt; /var/log/nginx/access.log &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; sort &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; uniq -c &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; sort -rn &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; head -20&#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;前五名每个都有一万多次请求。再看它们的 UA：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;grep &lt;span class=&#34;s1&#34;&gt;&amp;#39;1.2.3.4&amp;#39;&lt;/span&gt; /var/log/nginx/access.log &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; awk -F&lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;#34;&amp;#39;&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;{print $6}&amp;#39;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; sort &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; uniq -c&#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;全是同一个 UA，一个很老的 Chrome 标识，而且请求头里没有 &lt;code&gt;Accept-Language&lt;/code&gt;，没有 &lt;code&gt;Referer&lt;/code&gt;。正常浏览器不会这样。&lt;/p&gt;&#xA;&lt;p&gt;这就是典型的爬虫，可能是某个做镜像站的在收集内容，也可能是训练数据。&lt;/p&gt;&#xA;&lt;h2 id=&#34;能做的事有几种&#34;&gt;能做的事有几种&#xA;&lt;/h2&gt;&lt;p&gt;最直接的是封 IP。但爬虫往往有一批 IP，封一个换一个。&lt;/p&gt;&#xA;&lt;p&gt;另一个办法是在 Cloudflare 那边开 Bot Fight Mode。免费版有这个功能，能挡掉一部分低级爬虫。但它有时候会误伤正常的搜索引擎，而且对模拟得很像的爬虫没效果。&lt;/p&gt;&#xA;&lt;p&gt;再一个就是在 nginx 层面做限流。这个是治本的，不管对方换多少 IP，只要单个 IP 的请求频率超过阈值，就限速或者拒绝。&lt;/p&gt;&#xA;&lt;p&gt;我选了限流，Bot Fight Mode 也顺手开着，两个一起用。&lt;/p&gt;&#xA;&lt;h2 id=&#34;limit_req_zone-是怎么回事&#34;&gt;limit_req_zone 是怎么回事&#xA;&lt;/h2&gt;&lt;p&gt;nginx 的限流模块叫 &lt;code&gt;ngx_http_limit_req_module&lt;/code&gt;，核心是漏桶算法。&lt;/p&gt;&#xA;&lt;p&gt;先说漏桶是什么意思。&lt;/p&gt;&#xA;&lt;p&gt;想象一个桶，桶底有个洞，水以固定的速度往外漏。你往桶里倒水，如果倒得比漏得快，水就会积起来。桶满了之后，再倒就溢出去了。&lt;/p&gt;&#xA;&lt;p&gt;对应到 nginx，请求就是水，桶的容量是 &lt;code&gt;burst&lt;/code&gt;，漏水速度是 &lt;code&gt;rate&lt;/code&gt;。请求速率超过 &lt;code&gt;rate&lt;/code&gt; 之后，会先在桶里排队，桶满了就拒绝，返回 503 或者你指定的状态码。&lt;/p&gt;&#xA;&lt;p&gt;这个算法有个特点，它允许短时间的突发。比如你设了 &lt;code&gt;rate=10r/s&lt;/code&gt;，&lt;code&gt;burst=20&lt;/code&gt;，那么一个瞬间来 25 个请求，前 10 个立刻处理，后面 15 个排队，第 26 个开始拒绝。&lt;/p&gt;&#xA;&lt;p&gt;这个特性对正常用户很友好，因为人浏览网页本来就是一阵一阵的。&lt;/p&gt;&#xA;&lt;h2 id=&#34;配置&#34;&gt;配置&#xA;&lt;/h2&gt;&lt;p&gt;先在 &lt;code&gt;http&lt;/code&gt; 块里定义 zone：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;limit_req_zone&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$binary_remote_addr&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;zone=perip:10m&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;rate=5r/s&lt;/span&gt;&lt;span class=&#34;p&#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;code&gt;$binary_remote_addr&lt;/code&gt; 是客户端 IP 的二进制形式，比 &lt;code&gt;$remote_addr&lt;/code&gt; 省空间。&lt;code&gt;zone=perip:10m&lt;/code&gt; 是给这个 zone 起个名字，分配 10M 内存。&lt;/p&gt;&#xA;&lt;p&gt;10M 大概能存十六万个 IP 的状态。对于个人站绰绰有余。&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;rate=5r/s&lt;/code&gt; 是每秒五个请求。这个值要看你的站。我的站页面不多，一个正常用户浏览的时候，一秒最多也就两三个请求（html 加 css 加 js 加几张图）。设成 5 是个合理的上限。&lt;/p&gt;&#xA;&lt;p&gt;注意 &lt;code&gt;rate&lt;/code&gt; 的单位。写 &lt;code&gt;5r/s&lt;/code&gt; 是每秒五个，写 &lt;code&gt;5r/m&lt;/code&gt; 是每分钟五个。这两个差别很大，别写错。&lt;/p&gt;&#xA;&lt;p&gt;然后在 &lt;code&gt;server&lt;/code&gt; 或者 &lt;code&gt;location&lt;/code&gt; 里用：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;server&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;listen&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;443&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;ssl&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;http2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;server_name&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;blog.mibase.top&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;location&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kn&#34;&gt;limit_req&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;zone=perip&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;burst=10&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;nodelay&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kn&#34;&gt;limit_req_status&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;429&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kn&#34;&gt;try_files&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$uri&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$uri/&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;404&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#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;code&gt;burst=10&lt;/code&gt; 是桶的容量，允许十个请求排队。&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;nodelay&lt;/code&gt; 这个参数很关键。不加它，排队的请求会按 rate 慢慢放行，用户会感觉页面加载被拖慢了。加了之后，桶里的请求立刻处理，只是超过桶容量的才拒绝。&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;limit_req_status 429&lt;/code&gt; 是自定义拒绝时的状态码。默认是 503，但 503 表示服务不可用，429 表示请求过多，语义上 429 更准确。有些爬虫看到 503 会重试，看到 429 会退避。&lt;/p&gt;&#xA;&lt;h2 id=&#34;limit_conn_zone-管并发&#34;&gt;limit_conn_zone 管并发&#xA;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;limit_req&lt;/code&gt; 管的是速率，&lt;code&gt;limit_conn&lt;/code&gt; 管的是同时打开的连接数。&lt;/p&gt;&#xA;&lt;p&gt;这两个要一起用。因为有的爬虫很聪明，它把请求间隔拉长到刚好不被限速，但同时开几十个连接。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;6&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;limit_conn_zone&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$binary_remote_addr&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;zone=conn_perip:10m&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;server&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;limit_conn&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;conn_perip&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;20&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;limit_conn_status&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;429&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#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;单个 IP 最多二十个并发连接。正常浏览器对一个站同时开六个连接就够了（HTTP/1.1 的限制），HTTP/2 会多一点，但也不会到二十。&lt;/p&gt;&#xA;&lt;h2 id=&#34;白名单&#34;&gt;白名单&#xA;&lt;/h2&gt;&lt;p&gt;搜索引擎的爬虫不能限。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;12&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;13&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;14&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;15&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;geo&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$limit&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;66.249.64.0/19&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;40.77.167.0/24&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;157.55.39.0/24&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;207.46.13.0/24&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;127.0.0.1/32&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;map&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$limit&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$limit_key&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$binary_remote_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;limit_req_zone&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$limit_key&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;zone=perip:10m&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;rate=5r/s&lt;/span&gt;&lt;span class=&#34;p&#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;code&gt;geo&lt;/code&gt; 模块按 IP 段匹配，匹配到的设成 0。&lt;code&gt;map&lt;/code&gt; 把 0 转成空字符串，空字符串在 &lt;code&gt;limit_req_zone&lt;/code&gt; 里表示不参与限流。&lt;/p&gt;&#xA;&lt;p&gt;这个写法比在 &lt;code&gt;location&lt;/code&gt; 里写一堆 &lt;code&gt;if&lt;/code&gt; 要干净得多，而且性能更好，因为 &lt;code&gt;geo&lt;/code&gt; 和 &lt;code&gt;map&lt;/code&gt; 都是编译成哈希表查找。&lt;/p&gt;&#xA;&lt;p&gt;白名单的 IP 段要定期核对。Google 和 Bing 都公布了官方列表，而且会变。我一般是每个月看一次。&lt;/p&gt;&#xA;&lt;h2 id=&#34;给不同路径设不同阈值&#34;&gt;给不同路径设不同阈值&#xA;&lt;/h2&gt;&lt;p&gt;静态资源可以放宽，因为一个页面会带很多张图。动态接口要收紧。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;12&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;limit_req_zone&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$limit_key&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;zone=static:10m&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;rate=30r/s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;limit_req_zone&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$limit_key&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;zone=dynamic:10m&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;rate=3r/s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;location&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;~&lt;/span&gt;&lt;span class=&#34;sr&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;\.(css|js|jpg|jpeg|png|webp|svg|woff2)&lt;/span&gt;$ &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;limit_req&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;zone=static&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;burst=50&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;nodelay&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;expires&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;1y&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;location&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/api/&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;limit_req&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;zone=dynamic&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;burst=5&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;nodelay&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;limit_req_status&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;429&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#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;h2 id=&#34;观察限流的效果&#34;&gt;观察限流的效果&#xA;&lt;/h2&gt;&lt;p&gt;nginx 的日志里默认不记录限流信息。想统计，得在 &lt;code&gt;log_format&lt;/code&gt; 里加变量。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;log_format&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;main&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$remote_addr&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$remote_user&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$time_local]&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$request&amp;#34;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;s&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$status&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$body_bytes_sent&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$http_referer&amp;#34;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;s&#34;&gt;&amp;#39;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$http_user_agent&amp;#34;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$http_x_forwarded_for&amp;#34;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;s&#34;&gt;&amp;#39;req_limit=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$limit_req_status&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;conn_limit=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$limit_conn_status&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#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;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;awk &lt;span class=&#34;s1&#34;&gt;&amp;#39;$NF ~ /req_limit=REJECTED/ {print $1}&amp;#39;&lt;/span&gt; /var/log/nginx/access.log &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; sort &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; uniq -c &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; sort -rn &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; head&#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 被拒得最多。&lt;/p&gt;&#xA;&lt;p&gt;配完当天，日志里被拒的请求有两万多次，来自三十多个 IP。流量从四十 G 降到了正常水平。&lt;/p&gt;&#xA;&lt;h2 id=&#34;几个容易踩的坑&#34;&gt;几个容易踩的坑&#xA;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;limit_req_zone&lt;/code&gt; 只能写在 &lt;code&gt;http&lt;/code&gt; 块里，写在 &lt;code&gt;server&lt;/code&gt; 里会报错。这个我一开始搞错了，&lt;code&gt;nginx -t&lt;/code&gt; 直接不通过。&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;burst&lt;/code&gt; 设太大等于没限流。因为桶的容量就是允许的突发量，设成一千，对方一次来一千个请求也能过。我的经验是，正常页面需要的资源数加一点余量，二三十就够了。&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;nodelay&lt;/code&gt; 不加的话，虽然请求不会被拒，但会被延迟处理，用户会觉得网站变慢。这个体验比直接返回 429 更糟。&lt;/p&gt;&#xA;&lt;p&gt;用了 Cloudflare 的话，一定要先配 &lt;code&gt;real_ip&lt;/code&gt;，否则 &lt;code&gt;$binary_remote_addr&lt;/code&gt; 拿到的是 Cloudflare 的节点 IP，限流会误伤所有用户。这个坑我在 fail2ban 那篇里也提过，是同一个问题。&lt;/p&gt;&#xA;&lt;p&gt;还有，&lt;code&gt;limit_req&lt;/code&gt; 是有状态的，它的计数器存在共享内存里。如果你有多台 nginx 做负载均衡，每台的计数是独立的，实际允许的速率是单台的倍数。这种情况得在更上层做限流，或者用 Redis 存共享计数。&lt;/p&gt;&#xA;&lt;h2 id=&#34;最后的手段&#34;&gt;最后的手段&#xA;&lt;/h2&gt;&lt;p&gt;限流只能减缓，挡不住真正执着的爬虫。&lt;/p&gt;&#xA;&lt;p&gt;我在限流之后又加了一层，针对那些明显是爬虫的请求，直接返回 403：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;12&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;13&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;14&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;map&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$http_user_agent&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$bad_bot&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;      &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;&amp;#34;~*python-requests&amp;#34;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;&amp;#34;~*scrapy&amp;#34;&lt;/span&gt;          &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;&amp;#34;~*curl/7&amp;#34;&lt;/span&gt;          &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;&amp;#34;~*Go-http-client&amp;#34;&lt;/span&gt;  &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;server&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$bad_bot&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kn&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;403&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#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;这个写法比较粗暴，会误伤一些用 curl 的正常用户。但我的站是给人看的，不是给脚本用的，我觉得可以接受。&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;if&lt;/code&gt; 在 nginx 里是不推荐用的，因为它在 &lt;code&gt;location&lt;/code&gt; 里的行为有陷阱。但放在 &lt;code&gt;server&lt;/code&gt; 级别做这种简单的判断，是官方文档里明确说可以用的场景。&lt;/p&gt;&#xA;&lt;h2 id=&#34;现在的状态&#34;&gt;现在的状态&#xA;&lt;/h2&gt;&lt;p&gt;这套配置跑了几个月，流量稳定在每天两个 G 左右，没有再出现异常。&lt;/p&gt;&#xA;&lt;p&gt;偶尔还是会有爬虫来，但它们被限速之后，爬完整个站要很久，大多数爬到一半就放弃了。&lt;/p&gt;&#xA;&lt;p&gt;回头看，这件事的本质是，我的站没有任何成本地暴露在公网上，谁都能来拿。限流是在给它加一个成本，让无差别抓取变得不划算。&lt;/p&gt;&#xA;&lt;p&gt;这个思路可以用在很多地方。API 也好，下载站也好，只要能定义&amp;quot;正常使用的频率&amp;quot;，就能用同样的方法保护自己。&lt;/p&gt;&#xA;</description>
        </item></channel>
</rss>
