正确做法是在 init_by_lua_block 中初始化 Redis 连接池并复用,而非每次请求 new();须设超时、密码认证、真实 IP 多级解析、封禁接口三重校验,并在高并发时结合布隆过滤器与本地缓存降载。

access_by_lua_block 里不能直接 new Redis 实例
每次请求都 redis:new() 会快速耗尽连接数,还可能触发 Redis 的连接拒绝。OpenResty 官方明确建议复用连接池,而不是按需新建。
正确做法是在 init_by_lua_block 中初始化一次连接,并存入 ngx.ctx 或全局变量(注意线程安全);实际拦截时只复用它。
- 必须调用
red:set_timeout(100),否则默认超时是 60000ms,长阻塞会拖垮整个 worker - 如果 Redis 启用了密码,
red:auth("yourpass")必须在connect()之后、任何命令之前执行 - 连接失败时,
red:connect()返回false, err,应记录日志并 fallback 到允许访问,避免因 Redis 不可用导致全站 500
真实 IP 获取必须绕过代理污染
直接读 ngx.var.remote_addr 在有 CDN 或反向代理时大概率拿到的是中间节点 IP,封错对象。
要按优先级顺序取值:先看 ngx.var.http_x_real_ip,再 fallback 到 ngx.var.http_x_forwarded_for 的第一个非私有地址,最后才是 remote_addr。
使用ydata-profiling(前身为pandas-profiling)生成全面的数据质量报告,包含相关性分析、缺失值模式和基数检测。导出交互式HTML仪表板和JSON摘要。
- 确保 Nginx 编译时启用了
--with-http_realip_module,并在配置中设置set_real_ip_from指定可信代理段 -
X-Forwarded-For可被客户端伪造,所以不能无条件信任,必须结合real_ip_header X-Forwarded-For+real_ip_recursive on做可信链解析 - 私有地址段如
10.0.0.0/8、172.16.0.0/12、192.168.0.0/16要跳过,否则可能把内网 IP 当成攻击源误封
HTTP API 封禁接口必须带 TTL 和校验
一个裸露的 POST /api/block?ip=1.2.3.4 接口等于给攻击者送了一把万能钥匙。
至少要加三道防线:IP 格式校验、TTL 上限限制、调用方身份认证。
- 用
string.match(ip, "^%d+%.%d+%.%d+%.%d+$")做基础格式检查,再用iputils:is_private()(需引入 Lua 库)排除非法段 - TTL 必须限制最大值(比如 86400),防止长期封禁影响业务,命令统一走
SETEX blacklist:1.2.3.4 86400 "1" - 接口必须校验
Authorization: Bearer xxx或签名 header,Token 存 Redis 并设过期,不能硬编码在代码里
高频误封时布隆过滤器不是银弹
当黑名单 IP 数量超过 10 万且 QPS 过万时,单纯靠 GET blacklist:xxx 会产生大量 Redis 请求,容易打满带宽或触发慢日志。
本地缓存 + 布隆过滤器(BloomFilter)可降载,但要注意它的假阳性特性。
- 布隆过滤器只能回答“可能在黑名单中”或“绝对不在”,一旦返回“可能在”,仍需查 Redis 确认,不能直接 403
- 不支持删除,如果要解封某个 IP,必须重建整个过滤器,适合“封禁多、解封少”的场景
- OpenResty 下推荐用
resty.bloomfilter(需自己编译加载),别用纯 Lua 实现——性能差一个数量级

















