GKLBB

当你经历了暴风雨,你也就成为了暴风雨

导航

软件开发 --- OpenResty 之初体验

OpenResty 业务场景示例:实现高效的 API Rate Limiting(API 请求速率限制)

在很多 Web 服务中,特别是对于公共 API,通常需要对访问进行限制,以防止恶意请求或者过度使用服务资源。OpenResty 提供了非常强大的 Lua 脚本支持,可以非常高效地实现请求速率限制(Rate Limiting),不仅能在服务端控制请求频率,还能避免数据库或后端系统的过度负载。

业务场景:实现一个 API 请求速率限制系统

假设你有一个公共 API 服务,要求每个用户在一分钟内最多只能请求 60 次。超过此限制的请求应该返回 429 HTTP 状态码,表示 "请求过多"(Too Many Requests)。

步骤 1:配置 Nginx 和 OpenResty

我们将使用 OpenResty 来实现这一业务逻辑,通过 Lua 脚本实现速率限制。

1.1 修改 Nginx 配置文件

打开 OpenResty 的 Nginx 配置文件(通常位于 /usr/local/openresty/nginx/conf/nginx.conf):

sudo nano /usr/local/openresty/nginx/conf/nginx.conf

1.2 添加以下配置:

http {
    # 创建一个共享内存空间,用于存储每个用户的请求次数
    lua_shared_dict rate_limit_cache 10m;  # 设置 10MB 的共享内存,用于存储请求计数

    server {
        listen 80;

        location /api/ {
            # 每个请求进入时,都会执行 Lua 脚本来检查请求速率
            access_by_lua_block {
                local rate_limit_cache = ngx.shared.rate_limit_cache
                local client_ip = ngx.var.remote_addr  -- 获取客户端的 IP 地址
                local current_time = ngx.now()         -- 获取当前时间
                local key = "rate_limit:" .. client_ip  -- 用客户端 IP 作为键

                -- 获取该 IP 地址上次请求的时间和请求次数
                local last_request_time = rate_limit_cache:get(key .. ":time")
                local request_count = rate_limit_cache:get(key .. ":count")

                if last_request_time then
                    -- 如果距离上次请求的时间小于 1 分钟(60秒)
                    if current_time - last_request_time < 60 then
                        if request_count >= 60 then
                            -- 如果在 1 分钟内请求次数超过限制,返回 429 错误
                            ngx.status = 429
                            ngx.say("Too Many Requests: Please try again later.")
                            ngx.exit(ngx.HTTP_OK)
                        else
                            -- 请求次数未超过限制,更新计数器
                            rate_limit_cache:incr(key .. ":count", 1)
                        end
                    else
                        -- 如果请求时间间隔大于 1 分钟,重置计数器
                        rate_limit_cache:set(key .. ":time", current_time)
                        rate_limit_cache:set(key .. ":count", 1)
                    end
                else
                    -- 第一次请求该 IP,初始化时间和计数器
                    rate_limit_cache:set(key .. ":time", current_time)
                    rate_limit_cache:set(key .. ":count", 1)
                end
            }

            # 正常处理请求
            content_by_lua_block {
                ngx.say("Request successfully processed")
            }
        }
    }
}

步骤 2:解释代码

2.1 lua_shared_dict rate_limit_cache 10m;

  • 这里创建了一个共享内存区域 rate_limit_cache,大小为 10MB,用于存储每个用户的请求计数和请求时间。共享内存允许 OpenResty 在多个请求之间共享数据。

2.2 access_by_lua_block

  • access_by_lua_block 是 OpenResty 中的一个指令,允许在请求处理的初期阶段通过 Lua 脚本执行逻辑。我们使用 Lua 来实现速率限制。
  • 该 Lua 脚本根据客户端的 IP 地址 (ngx.var.remote_addr) 来存储和获取该 IP 的请求记录。
  • 对于每个请求,我们检查客户端的 IP 是否在过去的 60 秒内已经超过了最大请求次数(60 次)。如果是,返回 HTTP 429 错误;如果没有,继续处理请求并更新请求计数。

2.3 ngx.shared.rate_limit_cache

  • ngx.shared.rate_limit_cache 是我们在 Nginx 配置中定义的共享内存区域。我们通过 Lua 脚本访问它,存储和读取请求计数和时间。

2.4 rate_limit_cache:incrrate_limit_cache:set

  • rate_limit_cache:incr 用于递增指定键的值,代表请求计数。
  • rate_limit_cache:set 用于设置指定键的值,初始化请求计数和时间。

2.5 速率限制逻辑

  • if current_time - last_request_time < 60:判断当前请求和上一次请求之间的时间差是否小于 60 秒。
  • rate_limit_cache:incr(key .. ":count", 1):如果请求次数在限制内,增加计数。
  • 如果请求次数超过 60 次,则返回 HTTP 429 错误,表示请求过多。

步骤 3:启动 OpenResty

  1. 启动 OpenResty 服务
sudo /usr/local/openresty/nginx/sbin/nginx
  1. 检查是否启动成功
curl http://localhost/api/

你会看到返回:

Request successfully processed
  1. 超过请求次数时的响应
  • 在一分钟内多次访问 API,例如:
curl http://localhost/api/
curl http://localhost/api/
...
  • 如果请求次数超过了限制,服务会返回:
Too Many Requests: Please try again later.

步骤 4:停止 OpenResty

如果需要停止 OpenResty,可以使用以下命令:

sudo /usr/local/openresty/nginx/sbin/nginx -s stop

总结

在这个 API 请求速率限制 的业务场景中,我们使用 OpenResty 和 Lua 脚本来实现:

  • 客户端 IP 限制:每个 IP 每分钟只能请求 60 次。
  • 高效的缓存机制:通过共享内存 lua_shared_dict 来存储请求数据,避免了数据库和外部存储的压力。
  • 动态响应控制:在请求超过限制时,通过 Lua 脚本灵活控制返回 429 错误。

这个示例展示了 OpenResty 在高并发 Web 应用中如何结合 Lua 实现复杂的业务逻辑,同时保持高效性和灵活性。

posted on 2024-12-11 07:31  GKLBB  阅读(6)  评论(0编辑  收藏  举报