利用Nginx、Lua脚本与Redis构建高效IP访问频率限制系统

使用 Nginx、Lua 脚本和 Redis 可以实现一个自动封禁访问频率过高 IP 的功能。这种架构非常适合处理高并发场景下的访问控制。以下是一个简单的实现步骤:

图片[1]_利用Nginx、Lua脚本与Redis构建高效IP访问频率限制系统_知途无界

1. 环境准备

  • Nginx:安装并配置 Nginx。
  • LuaJIT:安装 LuaJIT,因为 Nginx 的 Lua 模块需要 LuaJIT。
  • Nginx Lua 模块:安装 lua-nginx-module 和 ngx_devel_kit
  • Redis:安装并配置 Redis,用于存储访问频率数据。

2. 安装 Nginx 和 Lua 模块

你可以通过源码编译 Nginx 并添加 Lua 模块。以下是一个简单的编译步骤:

# 下载 Nginx 源码  
wget http://nginx.org/download/nginx-1.21.3.tar.gz  
tar -zxvf nginx-1.21.3.tar.gz  
cd nginx-1.21.3/  
  
# 下载 LuaJIT 和 Nginx Lua 模块  
wget https://github.com/openresty/lua-nginx-module/archive/v0.10.20.tar.gz -O lua-nginx-module-0.10.20.tar.gz  
wget https://github.com/simpl/ngx_devel_kit/archive/v0.3.1.tar.gz -O ngx_devel_kit-0.3.1.tar.gz  
tar -zxvf lua-nginx-module-0.10.20.tar.gz  
tar -zxvf ngx_devel_kit-0.3.1.tar.gz  
  
# 下载 LuaJIT  
wget https://github.com/LuaJIT/LuaJIT/archive/v2.1.0-beta3.tar.gz -O LuaJIT-2.1.0-beta3.tar.gz  
tar -zxvf LuaJIT-2.1.0-beta3.tar.gz  
cd LuaJIT-2.1.0-beta3  
make PREFIX=/usr/local/luajit  
make install PREFIX=/usr/local/luajit  
export LUAJIT_LIB=/usr/local/luajit/lib  
export LUAJIT_INC=/usr/local/luajit/include/luajit-2.1  
  
# 编译 Nginx  
cd ../nginx-1.21.3  
./configure --prefix=/usr/local/nginx \  
            --add-module=../ngx_devel_kit-0.3.1 \  
            --add-module=../lua-nginx-module-0.10.20 \  
            --with-ld-opt="-Wl,-rpath,/usr/local/luajit/lib" \  
            --with-http_ssl_module  
make  
make install

3. 配置 Nginx 和 Lua 脚本

在 Nginx 配置文件中(通常是 /usr/local/nginx/conf/nginx.conf),添加 Lua 脚本和访问控制逻辑。

http {  
    lua_shared_dict my_limit_store 10m;  
    lua_package_path "/path/to/lua/scripts/?.lua;;";  
  
    server {  
        listen 80;  
  
        location / {  
            access_by_lua_file /path/to/lua/scripts/rate_limit.lua;  
            proxy_pass http://your_backend;  # 替换为你的后端地址  
        }  
    }  
}

4. 编写 Lua 脚本

在 /path/to/lua/scripts/rate_limit.lua 中编写 Lua 脚本,用于访问控制和 Redis 交互。

local limit_req = require "resty.limit.req"  
  
-- 初始化限制对象,参数为 Redis 实例、存储的 key 前缀、存储的桶大小(滑动窗口大小)、速率(每秒多少请求)  
local lim, err = limit_req.new("my_limit_store", "zone_key", 10, 20)  
if not lim then  
    ngx.log(ngx.ERR, "failed to instantiate a resty.limit.req object: ", err)  
    return ngx.exit(500)  
end  
  
local key = ngx.var.binary_remote_addr  -- 使用客户端 IP 作为 key  
local delay, err = lim:incoming(key, true)  
if not delay then  
    if err == "rejected" then  
        ngx.log(ngx.ERR, "request got rejected due to rate limiting")  
        return ngx.exit(429)  -- 返回 429 Too Many Requests  
    else  
        ngx.log(ngx.ERR, "failed to limit request: ", err)  
        return ngx.exit(500)  
    end  
end  
  
-- 如果请求被限速,delay 会返回需要延迟的时间(秒),可以将其转化为毫秒后 sleep  
if delay >= 0.001 then  
    ngx.sleep(delay)  
end  
  
-- 可以在这里添加额外的逻辑,比如记录日志到 Redis 或其他系统

5. 启动和测试

  • 启动 Nginx:/usr/local/nginx/sbin/nginx
  • 启动 Redis:redis-server

现在,Nginx 将根据配置对访问频率进行限制,并自动封禁访问频率过高的 IP。你可以通过并发请求测试工具(如 ab 或 wrk)来验证这一功能。

6. 进一步优化

  • 动态配置:可以通过 Lua 脚本读取配置文件或环境变量来动态调整限速策略。
  • 日志记录:可以将被限速的 IP 记录到 Redis 或其他日志系统中,以便后续分析。
  • 白名单:添加白名单逻辑,允许特定 IP 不受限速策略的影响。

通过上述步骤,你可以使用 Nginx、Lua 脚本和 Redis 实现一个高效的访问频率限制系统。

© 版权声明
THE END
喜欢就点个赞,支持一下吧!
点赞12 分享
评论 抢沙发
头像
欢迎您留下评论!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容