3. Redis 缓存基础回顾:数据结构、过期策略、内存淘汰机制

在深入多租户 SaaS 鉴权拦截链路之前,必须夯实 Redis 缓存的核心基础。本章将系统回顾 Redis 的五大常用数据结构、键的过期策略以及内存淘汰机制,为后续的令牌验证优化提供理论支撑。

3.1 五大核心数据结构与适用场景

Redis 并非简单的键值存储,其丰富的数据结构决定了不同的缓存效率。下表对比了五种最常用的数据类型及其在鉴权场景中的典型应用:

数据结构 底层编码 核心操作命令 鉴权场景示例
String int / embstr / raw SET / GET / INCR / EXPIRE 单租户令牌(Token)缓存、API 限流计数器
Hash ziplist / hashtable HSET / HGET / HGETALL / HDEL 存储用户会话信息(userId、角色、过期时间)
List quicklist LPUSH / RPUSH / LPOP / BRPOP 异步鉴权日志队列、令牌黑名单广播
Set intset / hashtable SADD / SISMEMBER / SMEMBERS / SCARD 租户权限集合、已吊销令牌集合
Sorted Set ziplist / skiplist ZADD / ZRANGEBYSCORE / ZREMRANGEBYSCORE 令牌按过期时间戳排序,实现自动清理
架构建议: 在多租户鉴权中,Hash 结构最适合存储租户级配置(如签名密钥、令牌有效期),而 Sorted Set 可用于构建“令牌过期时间索引”,实现高效的批量淘汰。

3.2 过期策略:被动与主动结合

Redis 的过期删除并非实时扫描所有键,而是采用 惰性删除 + 定期删除 的混合策略,以平衡 CPU 与内存开销。

  • 惰性删除(Lazy Deletion): 当客户端访问一个键时,Redis 会检查其是否已过期。若过期则立即删除并返回 nil。这种策略对 CPU 友好,但可能导致已过期但未被访问的键长期占用内存。
  • 定期删除(Active Deletion): Redis 每隔 100ms 随机抽取一部分设置了过期时间的键进行检查,如果过期则删除。通过调整 hz 参数(默认 10)可控制扫描频率。

下图展示了两种策略的协同工作流程:

Redis 过期策略协同流程 客户端请求 Key 检查 Key 是否过期 删除 Key,返回 nil 过期 返回 Value 未过期 定期删除(每 100ms) 随机抽取过期 Key 并删除 惰性删除保证及时性,定期删除防止内存泄漏,两者互补
注意: 如果大量键在同一时间点过期,Redis 的定期删除可能因扫描频率限制而滞后,导致瞬时内存压力。建议在设置令牌过期时间时加入随机偏移量(如 ±10%),避免“雪崩”效应。

3.3 内存淘汰机制:当缓存写满时

当 Redis 使用的内存达到 maxmemory 限制时,会根据配置的淘汰策略(maxmemory-policy)决定如何腾出空间。对于多租户鉴权系统,选择合适的策略至关重要。

Redis 8 种淘汰策略可分为三类:

类别 策略名称 淘汰逻辑 鉴权场景适用性
不淘汰 noeviction 不淘汰任何数据,写入操作直接返回错误 ❌ 不推荐,会导致鉴权写入失败
allkeys-lru 从所有键中淘汰最近最少使用的键 ✅ 推荐,自动淘汰低频访问的旧令牌
基于 LRU allkeys-lfu 从所有键中淘汰最不经常使用的键 ✅ 适合访问模式稳定的场景
volatile-lru 从设置了过期时间的键中淘汰最近最少使用的 ⚠️ 需确保所有令牌都设置了过期时间
volatile-lfu 从设置了过期时间的键中淘汰最不经常使用的 ⚠️ 同上,需配合过期时间使用
基于 TTL volatile-ttl 从设置了过期时间的键中淘汰即将过期的 ✅ 适合令牌缓存,优先淘汰快过期的
volatile-random 从设置了过期时间的键中随机淘汰 ❌ 不确定性高,可能导致有效令牌被误删
随机 allkeys-random 从所有键中随机淘汰 ❌ 不推荐,缺乏业务语义
最佳实践: 对于多租户 SaaS 鉴权缓存,推荐使用 allkeys-lru 或 volatile-ttl。前者能自动适应访问模式变化,后者则与令牌的过期语义天然匹配。务必避免使用 noeviction,否则高并发下鉴权服务可能因写入失败而雪崩。

3.4 数据结构与淘汰策略的协同设计

在实际的鉴权拦截链路中,数据结构的选型与淘汰策略需要协同考虑。下图展示了如何利用 Sorted Set 结合 volatile-ttl 策略实现精准的令牌生命周期管理:

Sorted Set 令牌过期索引 + 淘汰协同 令牌 Hash 存储 Key: token:{id} Sorted Set 过期索引 Key: token:expire:index score = 过期时间戳 内存淘汰触发 volatile-ttl 策略 定时任务 ZREMRANGEBYSCORE 定期清理已过期索引 通过 Sorted Set 索引,淘汰策略可以优先淘汰 score 最小的令牌,实现 O(log N) 级别的精准淘汰

通过上述设计,Redis 的内存淘汰机制不再是“盲目”的,而是与业务语义(令牌过期时间)深度绑定,从而在缓存压力下优先保留最“新鲜”的令牌,提升鉴权命中率。