Redis 的数据清理策略详解

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: 背景摸清 Redis 的数据清理策略,给内存使用高的被动缓存场景,在遇到内存不足时怎么做是最优解提供决策依据。 本文整理 Redis 的数据清理策略所有代码来自 Redis version : 5.0, 不同版本的 Redis 策略可能有调整

背景
摸清 Redis 的数据清理策略,给内存使用高的被动缓存场景,在遇到内存不足时

怎么做是最优解提供决策依据。

本文整理 Redis 的数据清理策略所有代码来自 Redis version : 5.0, 不同版本的 Redis 策略可能有调整

清理策略
Redis 的清理策略,总结概括为三点,被动清理、定时清理、驱逐清理

被动清理
访问 Key 时,每次都会检查该 Key 是否已过期,如果过期则删除该 Key ,get 、scan 等指令都会触发 Key 的过期检查。

关键代码如下, expireIfNeeded (redisDb db, robj key) 函数会触发检查并删除

robj lookupKeyReadWithFlags(redisDb db, robj key, int flags) {
robj
val;

if (expireIfNeeded(db,key) == 1) {
    /* Key expired. If we are in the context of a master, expireIfNeeded()
     * returns 0 only when the key does not exist at all, so it's safe
     * to return NULL ASAP. */
    if (server.masterhost == NULL) {
        server.stat_keyspace_misses++;
        return NULL;
    }
    if (server.current_client &&
        server.current_client != server.master &&
        server.current_client->cmd &&
        server.current_client->cmd->flags & CMD_READONLY)
    {
        server.stat_keyspace_misses++;
        return NULL;
    }
}
val = lookupKey(db,key,flags);
if (val == NULL)
    server.stat_keyspace_misses++;
else
    server.stat_keyspace_hits++;
return val;

}
定时清理
通过 serverCron 定期触发清理,可以通过 hz 参数,配置每秒执行多少次清理任务,流程如下

1、Redis 配置项 hz 定义了 serverCron 任务的执行周期,默认为 10,即 CPU 空闲时每秒执行 10 次

2、每次过期 Key 清理的 timelimit 不超过 CPU 时间的 25% ,即若 hz = 1,则一次清理时间最大为 250ms,若 hz = 10,则一次清理时间最大为 25ms,计算逻辑(timelimit = 1000000*ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC/server.hz/100;)

3、清理时依次遍历所有的 db;

4、从 db 中随机取 20 个 key,判断是否过期,若过期,则逐出;

5、若有 5 个以上 key 过期,则重复步骤 4,否则遍历下一个 db;

6、在清理过程中,若达到了 timelimit 时间,退出清理过程;

关键代码如下,activeExpireCycle (int type) 会执行上述逻辑

int serverCron(struct aeEventLoop eventLoop, long long id, void clientData) {
...
databasesCron();
...
}

void databasesCron(void) {
/* Expire keys by random sampling. Not required for slaves

 * as master will synthesize DELs for us. */
if (server.active_expire_enabled) {
    if (server.masterhost == NULL) {
        activeExpireCycle(ACTIVE_EXPIRE_CYCLE_SLOW);
    } else {
        expireSlaveKeys();
    }
}
...

}
ps: activeExpireCycle 还会在主事件循环 eventLoop 中被调用,此时 type = ACTIVE_EXPIRE_CYCLE_FAST, 控制了最多执行 timelimit = 1000us 的快速清理,也会删除部分 Key 。

驱逐清理
Redis 在命令处理函数 processCommand 会进行内存的检查和驱逐,任何命令都会出触发,包括 ping 命令。

如果配置了 maxmemory ,且当前内存超过 maxmemory 时,则会执行 maxmemory_policy 筛选出需要清理的 Key,继而判断 lazyfree-lazy-eviction 是否开启来进行 Key 的同步还是异步删除。无论是同步删除还是异步删除,最后都会继续校验内存是否超限,直到内存低于 maxmemory。驱逐只会在 Master 节点进行。

maxmemory_policy 可选如下:

volatile-lru:从已设置过期时间的数据集中挑选【最近最少使用】的 Key 进行删除

volatile-ttl:从己设置过期时间的数据集中挑选【将要过期】的 Key 进行删除

volatile-lfu:从己设置过期时间的数据集中选择【最不常用】的 Key 进行删除

volatile-random:从己设置过期时间的数据集中【任意选择】Key 进行删除

allkeys-lru:从数据集中挑选【最近最少使用】的 Key 进行删除

allkeys-lfu:从数据集中【优先删除掉最不常用】的 Key

allkeys-random:从数据集中【任意选择】 Key 进行删除

no-enviction:禁止驱逐数据

如上图,6.2 后的版本支持通过逐出因子 maxmemory-eviction-tenacity 来控制逐出阻塞的时间。具体的阻塞耗时间可以通过 latency-monitor 里的 eviction-cycle、eviction-del 来观测。

关键代码如下,freeMemoryIfNeeded () 函数会执行上述逻辑

int processCommand(client *c) {
...
if (server.maxmemory && !server.lua_timedout) {
int out_of_memory = freeMemoryIfNeededAndSafe() == C_ERR;
...
}
...
}

int freeMemoryIfNeededAndSafe(void) {
if (server.lua_timedout || server.loading) return C_OK;
return freeMemoryIfNeeded();
}
ps: 当触发 aof 文件重写,fork 操作会阻塞主进程,此时积压的指令需要的内存,在 fork 结束后,需要一次性 eviction 出来,这时的 eviction-cycle 耗时会恶化的很严重,达到秒级的阻塞,此时可通过 latency-monitor 观测 eviction-cycle 、fork 总是成对出现。

总结
回到开篇的背景问题,当遇到内存使用高的被动缓存场景,可用内存不足时:

离线分析内存,是否存在大量【已过期】的内存来不及定时清理,此时可调大 hz 参数来加速过期内存的主动清理。hz 参数最大 500 ,不过要观察 CPU 的影响,不要因为 hz 影响读写流量

如果调整 hz 还是没法及时清理已过期的内存,则可以使用 scan 指令来被动访问 key 的方式手动删除,注意执行 scan 时的 count ,同时观测 CPU 使用情况,scan 的 count 越大,CPU 消耗会越高,完成一次 sacn 删除的时间最快。为了减少对线上的影响,可以在业务低峰期,周期性的执行。

通过 latency-monitor 观测 eviction-cycle、eviction-del 指标,是否因内存驱逐阻塞严重,可开启 lazyfree-lazy-eviction 来缓解阻塞。

业务上可以考虑关闭 aof 的影响,关闭 aof 可以减少驱逐清理 eviction-cycle 延迟带来的读写超时影响。

可升级到 7.x 版本的 Redis ,通过 maxmemory-eviction-tenacity 参数主动控制每次驱逐的阻塞时间

如果还是很慢,可考虑升级内存规格

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
17天前
|
缓存 NoSQL 数据库
探秘Redis读写策略:CacheAside、读写穿透、异步写入
本文介绍了 Redis 的三种高可用性读写模式:CacheAside、Read/Write Through 和 Write Behind Caching。CacheAside 简单易用,但可能引发数据不一致;Read/Write Through 保证数据一致性,但性能可能受限于数据库;Write Behind Caching 提高写入性能,但有数据丢失风险。开发者应根据业务需求选择合适模式。
65 2
探秘Redis读写策略:CacheAside、读写穿透、异步写入
|
1月前
|
缓存 NoSQL 算法
17- 数据库有1000万数据 ,Redis只能缓存20w数据, 如何保证Redis中的数据都是热点数据 ?
保证Redis中的20w数据为热点数据,可以通过设置Redis的LFU(Least Frequently Used)淘汰策略。这样,当数据库有1000万数据而Redis仅能缓存20w时,LFU会自动移除使用频率最低的项,确保缓存中的数据是最常使用的。
63 8
|
3天前
|
存储 NoSQL 算法
深入浅出Redis(三):Redis数据的存储、删除以及淘汰
深入浅出Redis(三):Redis数据的存储、删除以及淘汰
|
4天前
|
存储 NoSQL Java
熟悉Redis吗,那Redis的过期键删除策略是什么
对于Redis,我们业务开发一般都只关心Redis键值对的查询、修改操作,可能因为懒或者只想能用就行,呵呵。很少关心键值对存储在什么地方、键值对过期了会怎么样、Redis有没什么策略处理过期的键、Redis处理过期键又有什么作用?但这些问题却是Java程序员在Redis上进阶的必备知识,不要埋怨Java要学习的系统知识为什么这么多,因为这些确确实实是进阶的程序员所必须掌握的。我们往下看看~
25 2
熟悉Redis吗,那Redis的过期键删除策略是什么
|
7天前
|
缓存 监控 NoSQL
Redis缓存雪崩及应对策略
缓存雪崩是分布式系统中一个常见但危险的问题,可以通过合理的缓存策略和系统设计来降低发生的概率。采用多层次的缓存架构、缓存预热、合理的缓存失效时间等措施,都可以有效应对缓存雪崩,提高系统的稳定性和性能。在实际应用中,及时发现并解决潜在的缓存雪崩问题,是保障系统可用性的关键一环。
38 14
|
7天前
|
存储 NoSQL 测试技术
Redis数据存储系统为什么快?
Redis的快速并非偶然,而是深思熟虑的设计理念的结果。通过将数据存储于内存、采用单线程模型、实现非阻塞I/O等独特的技术选择,Redis在高并发和低延迟方面展现了卓越的表现。
34 16
|
16天前
|
缓存 NoSQL Redis
揭秘Redis的高效失效策略,提升可用性
Redis是广泛使用的开源内存数据库,其高性能和多样性使其在现代应用中不可或缺。然而,内存限制和数据管理是关键挑战。本文探讨了Redis的失效策略,包括内存淘汰(如LRU和LFU)和缓存失效策略(定时清除、惰性清除和定时扫描清除),以应对内存耗尽、数据过期等问题,确保系统性能和稳定性。通过合理配置这些策略,可以优化内存使用,防止数据不一致,提升系统效率。
53 0
揭秘Redis的高效失效策略,提升可用性
|
17天前
|
存储 缓存 NoSQL
Redis入门到通关之Redis内存淘汰(内存过期)策略
Redis入门到通关之Redis内存淘汰(内存过期)策略
31 3
|
17天前
|
存储 缓存 NoSQL
Redis入门到通关之Redis缓存数据实战
Redis入门到通关之Redis缓存数据实战
22 0
|
17天前
|
存储 运维 监控