2024-09-09 15:17:21
限流(Rate Limitting)在服务降级中扮演着关键角色,旨在通过控制系统的输入和输出流量,确保服务器稳定运行并避免过载。在公网环境下,网站面临来自用户、网络爬虫、恶意攻击和大促等导致流量激增的情况,这可能导致服务器响应延迟甚至崩溃。因此,当并发请求数超过服务器处理能力时,采用限流策略,限制部分请求,以确保服务器能够正确响应其他请求。
Nginx 提供多种限流方式,包括限制请求速率、限制连接数量以及对下载/上传速度的限制。这些机制通过模拟实际系统的工作流程,确保流量管理策略的有效实施。
Nginx 的 ngx_http_limit_req_module 模块通过模仿漏桶算法(leaky bucket algorithm)实现请求速率限制。想象一个桶,桶上方持续进水,下方匀速出水。当桶内水位达到上限时,任何新增的水都只能被拒绝,不会流入桶内。类比于网络请求处理,进水代表客户端请求,桶代表请求队列,出水代表请求被服务器处理,溢出代表请求被拒绝。
配置 Nginx 限流涉及两个主要指令:imit_req_zone 和 limit_req。imit_req_zone 用于定义限流区域和参数,limit_req 用于激活限流策略。例如,通过设置 `limit_req_zone test 5m 10r`,表示在名为 "test" 的区域内,每5秒处理10个请求。
假设在请求 HTML 文件时执行上述配置,当1秒内发送10次请求,前500毫秒发送1次,后500毫秒发送9次时,只有前500毫秒的请求和后500毫秒的第一个请求能够响应,其他请求将被拒绝。
为了应对突发流量,可以在 limit_req 中设置 `burst` 参数。例如,`burst=5` 表示在超过每秒2个请求后,可以额外处理5个请求。若同时有10个请求到达,Nginx 会处理第1个请求,其余9个中,前5个被放入队列等待,其余4个被拒绝。之后,每500毫秒从队列中处理一个请求,队列中的请求按照每500毫秒释放的速率处理。增加 `nodelay` 参数可立即处理队列中的请求,但不会改变队列的处理速率。
对于特定的 IP 地址,可以通过 Nginx 的 ngx_http_geo_module 和 ngx_http_map_module 模块设置白名单,取消限流限制。使用 `geo` 指令和 `map` 指令定义 IP 地址与限流规则之间的映射,允许白名单内的 IP 地址不受限流策略影响。
同一 `location` 下的多个 `limit_req` 配置会合并生效。例如,配置了 `myLimit` 和 `myLimit2` 两个规则,白名单用户会根据 `mylimit2` 的配置被限制为10r/s。对于不在白名单的用户,则同时应用两个配置,取最严格的限制条件。
通过 `ngx_http_limit_conn_module`,Nginx 可以限制并发连接数。配置 `limit_conn_zone key zone` 指令定义区域,`limit_conn` 指令激活限制策略。需要注意的是,只有在请求被后端服务器处理后,连接计数才生效。
`limit_rate` 指令用于限制客户端与服务器之间的传输字节数,常用于下载/上传限速。Nginx 的 `ngx_http_core_module` 包含 `limit_rate` 和 `limit_rate_after` 指令。`limit_rate_after` 允许在传输一定数据后进行限速,适用于分段下载或流媒体视频场景。
`limit_rate` 可以结合变量和 `map` 指令实现动态限速。例如,根据时间或用户变量调整限速策略。可以使用 Nginx 内置的 `ssi` 模块的时间变量,通过 `map` 指令和正则表达式匹配不同的时间段,实现基于时间的限速。此外,还可以根据用户特定的变量(如 cookie)动态调整限速,确保不同用户获得不同的服务体验。