如何通过 OpenResty 和 Redis 实现高效动态 IP 黑名单同步?
- 内容介绍
- 文章标签
- 相关推荐
本文共计959个文字,预计阅读时间需要4分钟。
直接封锁IP本体不难,困难的是封锁了即时生效。多worker不重复查Redis,解锁自动触发且不漏。这三点处理不好,就容易出现封锁了还通、解封不及时、高并发下Redis手忙脚乱的问题。
access_by_lua_file 里必须用 shared dict 缓存黑名单结果
每次请求都去 Redis 查 banned:1.2.3.4,QPS 上千时 Redis 连接和延迟会成瓶颈。OpenResty 的 shared dict 是跨 worker 共享的内存字典,适合缓存「封禁状态 + 过期时间」。
- 在
http块里定义:lua_shared_dict ip_ban_cache 10m; - Lua 脚本里先查
ip_ban_cache:get(ip),命中就直接ngx.exit(403) - 未命中再查 Redis;若 Redis 返回被封,就用
ip_ban_cache:set(ip, true, ttl)写入(ttl 要比 Redis 的 TTL 小 1–2 秒,避免缓存比 Redis 多留几秒) - 注意:shared dict 的过期是惰性删除,不能依赖它自动清理,得靠 Redis 的 TTL 主动控制生命周期
获取真实客户端 IP 必须按 X-Real-IP → X-Forwarded-For → remote_addr 顺序 fallback
反向代理(如 SLB、CDN、Nginx 前置)会覆盖 remote_addr 为上一跳地址,直接用它封错 IP 是最常见失误。
本文共计959个文字,预计阅读时间需要4分钟。
直接封锁IP本体不难,困难的是封锁了即时生效。多worker不重复查Redis,解锁自动触发且不漏。这三点处理不好,就容易出现封锁了还通、解封不及时、高并发下Redis手忙脚乱的问题。
access_by_lua_file 里必须用 shared dict 缓存黑名单结果
每次请求都去 Redis 查 banned:1.2.3.4,QPS 上千时 Redis 连接和延迟会成瓶颈。OpenResty 的 shared dict 是跨 worker 共享的内存字典,适合缓存「封禁状态 + 过期时间」。
- 在
http块里定义:lua_shared_dict ip_ban_cache 10m; - Lua 脚本里先查
ip_ban_cache:get(ip),命中就直接ngx.exit(403) - 未命中再查 Redis;若 Redis 返回被封,就用
ip_ban_cache:set(ip, true, ttl)写入(ttl 要比 Redis 的 TTL 小 1–2 秒,避免缓存比 Redis 多留几秒) - 注意:shared dict 的过期是惰性删除,不能依赖它自动清理,得靠 Redis 的 TTL 主动控制生命周期
获取真实客户端 IP 必须按 X-Real-IP → X-Forwarded-For → remote_addr 顺序 fallback
反向代理(如 SLB、CDN、Nginx 前置)会覆盖 remote_addr 为上一跳地址,直接用它封错 IP 是最常见失误。

