redis近似lru在小数据集“乱删”是因为采用随机采样+局部比较(默认5个样本),样本量越小误判越严重;增大maxmemory-samples、改用volatile-lru或allkeys-random可缓解,但本质是算法取舍。

Redis近似LRU为什么在小数据集里“乱删”
因为Redis根本没用真LRU,它用的是随机采样+局部比较的近似算法,样本量越小,选错“最久未用”的概率越高——不是bug,是设计取舍。
典型现象:maxmemory设为100MB,只存了20个key,却把刚SET进去的key立刻淘汰了,而几个小时没碰的老key还活着。
- Redis默认每秒做10次淘汰尝试(由
hz配置控制),每次随机选5个key(maxmemory-samples默认值)比访问时间 - 5个里挑出
idle最大的那个删掉,不遍历全量key,也不维护全局时间链表 - 当总key数接近甚至小于5时,“随机5个”就退化成“几乎全量随机”,再叠加时钟精度(毫秒级)和
idle更新延迟,新key的idle可能被误判为极大
如何让新写入的数据更大概率活下来
核心思路:压低新key的初始idle值,同时抬高老key的淘汰优先级——但不能关淘汰,否则OOM。
- 增大
maxmemory-samples到10或15(注意:值越大CPU开销越高,尤其在大内存实例上) - 避免在写密集场景下用
allkeys-lru,改用volatile-lru并给新key统一加短过期时间(如SETEX key 300 value),让淘汰逻辑只在有EXPIRE的key里发生,避开无过期时间的新key - 如果业务允许,用
allkeys-random替代allkeys-lru——至少“乱删”是真随机,不会系统性针对新key
从INFO输出看懂当前LRU偏差程度
INFO memory里的两个字段直接暴露近似LRU的“失真度”:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
-
mem_allocator无关,忽略 - 重点看
lru_clock:这是Redis内部的LRU时钟(单位秒,每秒自增),它不等于系统时间,但能反映时钟推进是否稳定 - 更关键的是
evicted_keys和expired_keys的比值:如果evicted_keys远高于expired_keys(比如10:1),说明淘汰压力大且LRU策略正在高频介入,此时小样本误差会被放大
执行INFO memory | grep -E "(lru_clock|evicted_keys|expired_keys)",连续观察几分钟,若lru_clock跳变不规律(如隔几秒才+1),说明hz被压低或主线程卡顿,进一步恶化采样质量。
真正要警惕的不是“删新”,而是冷热混存下的隐性抖动
当缓存里同时存在长期有效的元数据(如用户配置)和临时计算结果(如接口聚合数据),近似LRU会不断在两者间错误置换——不是某次删错了,而是每次采样都在强化这种误判。
- 不要指望调参彻底解决,这是算法本质决定的
- 业务层做分离:用不同Redis DB(或不同实例),让
volatile-lru专管临时数据,noeviction保底存核心配置 - 监控
keyspace_hits和keyspace_misses的比率突降,往往比淘汰数本身更能提前暴露LRU失准带来的缓存雪崩前兆
近似LRU在万级key以上才接近理想行为,几百个key时,它的“淘汰顺序”基本等价于“随机+轻微时间偏置”,接受这点,比硬调参数更省事。










