使用 Nginx、Lua 脚本和 Redis 可以实现一个自动封禁访问频率过高 IP 的功能。这种架构非常适合处理高并发场景下的访问控制。以下是一个简单的实现步骤:
![图片[1]_利用Nginx、Lua脚本与Redis构建高效IP访问频率限制系统_知途无界](https://zhituwujie.com/wp-content/uploads/2024/10/d2b5ca33bd20241027112124.png)
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.gztar -zxvf nginx-1.21.3.tar.gzcd 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.gzwget https://github.com/simpl/ngx_devel_kit/archive/v0.3.1.tar.gz -O ngx_devel_kit-0.3.1.tar.gztar -zxvf lua-nginx-module-0.10.20.tar.gztar -zxvf ngx_devel_kit-0.3.1.tar.gz# 下载 LuaJITwget https://github.com/LuaJIT/LuaJIT/archive/v2.1.0-beta3.tar.gz -O LuaJIT-2.1.0-beta3.tar.gztar -zxvf LuaJIT-2.1.0-beta3.tar.gzcd LuaJIT-2.1.0-beta3make PREFIX=/usr/local/luajitmake install PREFIX=/usr/local/luajitexport LUAJIT_LIB=/usr/local/luajit/libexport LUAJIT_INC=/usr/local/luajit/include/luajit-2.1# 编译 Nginxcd ../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_modulemakemake install# 下载 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# 下载 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; # 替换为你的后端地址}}}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; # 替换为你的后端地址 } } }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 thenngx.log(ngx.ERR, "failed to instantiate a resty.limit.req object: ", err)return ngx.exit(500)endlocal key = ngx.var.binary_remote_addr -- 使用客户端 IP 作为 keylocal delay, err = lim:incoming(key, true)if not delay thenif err == "rejected" thenngx.log(ngx.ERR, "request got rejected due to rate limiting")return ngx.exit(429) -- 返回 429 Too Many Requestselsengx.log(ngx.ERR, "failed to limit request: ", err)return ngx.exit(500)endend-- 如果请求被限速,delay 会返回需要延迟的时间(秒),可以将其转化为毫秒后 sleepif delay >= 0.001 thenngx.sleep(delay)end-- 可以在这里添加额外的逻辑,比如记录日志到 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 或其他系统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
暂无评论内容