跳转至

redis-ratelimit: 限制多个 NGINX 实例之间的请求处理速率,后端使用 Redis

安装

如果您尚未设置 RPM 仓库订阅,请 注册。然后您可以继续以下步骤。

CentOS/RHEL 7 或 Amazon Linux 2

yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install lua-resty-redis-ratelimit

CentOS/RHEL 8+、Fedora Linux、Amazon Linux 2023

dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-redis-ratelimit

要在 NGINX 中使用此 Lua 库,请确保已安装 nginx-module-lua

本文档描述了 lua-resty-redis-ratelimit v0.3,发布于 2019 年 10 月 03 日。


此 Lua 库是 ngx_lua 的请求处理速率限制模块:

http://wiki.nginx.org/HttpLuaModule

它用于限制多个 NGINX 实例之间每个定义键的请求处理速率。限制是通过 "漏桶" 方法实现的。

此模块使用 Redis (>= 2.6.0) 作为后端存储,因此您还需要 lua-resty-redis 库与之配合使用。

注意: 如果您不使用 duration 功能,并且传入流量是 均匀分布 的,建议使用模块 resty.limit.req 以避免不必要的网络延迟。

概述

server {

    listen 9090;

    location /t {
        access_by_lua_block {
            local ratelimit = require "resty.redis.ratelimit"

            local lim, err = ratelimit.new("one", "2r/s", 0, 2)
            if not lim then
                ngx.log(ngx.ERR,
                        "无法实例化 resty.redis.ratelimit 对象: ", err)
                return ngx.exit(500)
            end

            -- 注意:以下调用必须是每个请求。

            -- local redis = require "resty.redis"
            -- local red = redis:new()

            -- red:set_timeout(1000)

            -- local ok, err = red:connect("127.0.0.1", 6379)
            -- if not ok then
            --     ngx.log(ngx.ERR, "连接 Redis 失败: ", err)
            --     return ngx.exit(500)
            -- end

            local red = { host = "127.0.0.1", port = 6379, timeout = 1 }

            local key = ngx.var.binary_remote_addr
            local delay, err = lim:incoming(key, red)
            if not delay then
                if err == "rejected" then
                    return ngx.exit(503)
                end
                ngx.log(ngx.ERR, "请求限制失败: ", err)
                return ngx.exit(500)
            end

            if delay >= 0.001 then
                -- 第二个返回值表示指定键每秒的超出请求数量。
                local excess = err

                ngx.sleep(delay)
            end
        '}

        echo Logged in;
    }

}

方法

new

语法: obj, err = class.new(zone, rate, burst, duration)

实例化该类的对象。类值由调用 require "resty.redis.ratelimit" 返回。

此方法接受以下参数:

  • zone:设置命名空间,特别是我们使用 <zone>:<key> 字符串作为 Redis 中的唯一状态标识符。
  • rate:速率以每秒请求数 (r/s) 指定。如果希望的速率少于每秒一个请求,则以每分钟请求数 (r/m) 指定。例如,每秒半个请求为 30r/m。
  • burst:定义可以超出 zone 指定速率的请求数量,默认为 0。
  • duration:在恢复到正常状态之前的时间延迟(以秒为单位),在此期间,请求始终被 rejected,默认为 0。

如果失败,此方法返回 nil 和描述错误的字符串。

incoming

语法: delay, err = obj:incoming(key, redis)

触发新的请求到达事件,并计算当前请求在指定键上所需的延迟(如果有的话),或者用户是否应该立即拒绝它。

此方法接受以下参数:

  • key:键是指定变量的任何非空值。
  • redis:设置 Redis 配置,包括 hostporttimeout 等(见下文);您也可以直接设置连接的 Redis object
- redis.host:默认值 127.0.0.1。
- redis.port:默认值 80。
- redis.timeout:默认值 1s。
- redis.pass:请求在受密码保护的 Redis 服务器上的身份验证。
- redis.dbid:选择 Redis 逻辑数据库。

返回值取决于以下情况:

  1. 如果请求未超过 new 方法中指定的 rate 值,则此方法返回 0 作为延迟和当前时间的(零)超出请求数量。
  2. 如果请求超过了 new 方法中指定的 rate 限制,但未超过 rate + burst 值,则此方法返回当前请求的适当延迟(以秒为单位),以使其仍符合 rate 阈值,就好像稍后而不是现在到达。第二个返回值指示此时每秒的超出请求数量(包括当前请求)。
  3. 如果请求超过了 rate + burst 限制,则此方法返回 nil 和错误字符串 "rejected"
  4. 如果发生错误,则此方法返回 nil 和描述错误的字符串。例如,"failed to create redis - connection refused"

此方法本身不会休眠。它仅在必要时返回延迟,并要求调用者稍后调用 ngx.sleep 方法进行休眠。

set_burst

语法: obj:set_burst(burst)

覆盖 new 方法中指定的 burst 阈值。

另请参阅

GitHub

您可以在 nginx-module-redis-ratelimit 的 GitHub 仓库 中找到此模块的其他配置提示和文档。