跳转到主内容
极星编程网:以代码为星,赴技术山海!

网关鉴权为何耗尽Redis连接_加Caffeine本地缓存缓解

根本原因是高频鉴权请求未做本地缓存兜底,导致Redis连接池耗尽;引入Caffeine缓存后90%+请求不再打Redis,连接数回落至安全水位。 网关鉴权耗尽 Redis 连接,根本原因不是 Redis 性能差,而是高频请求反复穿透到 Redis 层——每个请求都查一次 token、权限、白名单,没做本地缓存兜底。加 Caffeine 本地缓存后,90%+ 的鉴权请求不再打 Redis,连接数直接回落到安全水位。 为什么网关鉴权会压垮 Redis 连接池 Spring Cloud Gateway 默认不带鉴权缓存,每次
Authorization
头解析后,都要查 Redis 判断 token 是否有效、角色是否有权限、是否在黑名单里。当 QPS 上万时,哪怕单次 Redis 查询只要 1ms,每秒也要建立上万个连接(或复用连接但触发大量
GET
命令),而默认的 Lettuce 连接池
max-active: 20
很快就排队阻塞,出现
Cannot obtain redis connection
或超时异常。 鉴权是「读多写少」场景:token 有效期内基本不变,但每毫秒都在被重复校验 Redis 是网络调用,哪怕同机房 RTT 也稳定在 0.3–0.8ms;Caffeine 查内存是纳秒级,差三个数量级 网关是流量入口,一旦 Redis 阻塞,整个链路雪崩,错误率飙升,和数据库慢查询一个后果 Caffeine 缓存鉴权数据的关键配置点 不是所有数据都适合放本地缓存,token、用户权限这类「变更低频、失效明确」的数据才合适。重点不是缓存大小,而是过期策略必须和业务语义对齐:
expireAfterWrite(30, TimeUnit.MINUTES)
:token 本身有效期 30 分钟,本地缓存不能比它长,否则可能返回已过期却未清理的权限 不要只配
expireAfterAccess
:鉴权是被动触发,
access
不代表 token 仍有效,容易导致脏数据滞留 务必开启
recordStats()
:上线后用
localCache.stats().hitRate()
监控命中率,低于 85% 就要检查 key 设计或过期时间是否合理 缓存 key 要包含租户/环境维度,比如
"auth:prod:token:" + md5(token)
,避免测试环境 token 冲突污染生产缓存 网关过滤器里怎么嵌入两级缓存逻辑 在自定义
GlobalFilter
中实现「先查 Caffeine → 未命中再查 Redis → Redis 命中则回填 Caffeine」,注意三个易错点: Redis 8.2.3 Redis 8.2.3 是一款安全优先的高性能键值存储系统。该版本紧急修复了可能引发远程代码执行(RCE)的高危漏洞(CVE-2025-62507),并解决了 HyperLogLog 及 Cuckoo Filter 等数据结构在特定场景下的崩溃问题。建议所有用户立即升级,以保障生产环境的系统稳定与数据安全。 下载 不要在
cache.getIfPresent(key)
返回
null
后直接 fallback 到 Redis —— 必须加双重检查锁(如
cache.get(key, k -> loadFromRedis(k))
),否则并发请求会重复刷 Redis Redis 查询结果为
null
(比如 token 已删除)也要写入 Caffeine,设短过期(如 30 秒),防止缓存穿透,key 可标记为
"auth:null:" + token
如果 Redis 查询失败(连接超时、序列化异常),不要抛异常中断请求,应降级走直连后端鉴权,同时记录告警日志,避免网关因 Redis 故障整体不可用 示例片段:
Object authData = localCache.get(token, t -> {
Object fromRedis = redisTemplate.opsForValue().get("auth:" + t);
return fromRedis != null ? fromRedis : NULL_PLACEHOLDER;
});
本地缓存失效时的一致性陷阱 用户登出、权限变更、token 强制下线这些操作,只会删 Redis 里的 key,Caffeine 本地缓存并不感知——这是最隐蔽的「脏读」来源。解决方法不是强同步,而是轻量兜底: 对敏感操作(如管理员踢人),额外发一条
PUBLISH auth:invalidate token_abc
到 Redis,各网关实例订阅该 channel 并主动
localCache.invalidate(token_abc)
更低成本的做法:在 Caffeine 配置里加上
refreshAfterWrite(2, TimeUnit.MINUTES)
,让缓存每两分钟自动异步重载一次,牺牲一点实时性换一致性 绝对不要用「全量清除
localCache.invalidateAll()
」来应对单个 token 失效——这会瞬间击穿全部本地缓存,效果比不加缓存还差 真正难的不是加 Caffeine,而是让缓存行为和业务生命周期对齐:token 过期时间、权限变更频率、运维强删动作,都得映射到缓存的
expire
、
refresh
、
invalidate
三类操作上。漏掉任意一环,缓存就从加速器变成定时炸弹。

相关文章