Redis 的数据清理策略详解
背景
摸清 Redis 的数据清理策略,给内存使用高的被动缓存场景,在遇到内存不足时
-
怎么做是最优解提供决策依据。
本文整理 Redis 的数据清理策略所有代码来自 Redis version : 5.x, 不同版本的 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(); }
总结
回到开篇的背景问题,当遇到内存使用高的被动缓存场景,可用内存不足时:
-
离线分析内存,是否存在大量【已过期】的内存来不及定时清理,此时可调大 hz 参数来加速过期内存的主动清理。hz 参数最大 500 ,不过要观察 CPU 的影响,不要因为 hz 影响读写流量
-
如果调整 hz 还是没法及时清理已过期的内存,则可以使用 scan 指令来被动访问 key 的方式手动删除,注意执行 scan 时的 count ,同时观测 CPU 使用情况,scan 的 count 越大,CPU 消耗会越高,完成一次 sacn 删除的时间最快。为了减少对线上的影响,可以在业务低峰期,周期性的执行。
-
通过 latency-monitor 观测 eviction-cycle、eviction-del 指标,是否因内存驱逐阻塞严重,可开启 lazyfree-lazy-eviction 来缓解阻塞,如果还是很慢,可升级内存规格
-
可升级到 7.x 版本的 Redis ,通过 maxmemory-eviction-tenacity 参数主动控制每次驱逐的阻塞时间
参考:
-
快手Redis架构演进实践_脱敏.pdf

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
见微知著:从企业售后技术支持看云计算发展
售后业务中的细微变化 作为阿里云企业容器技术支持的一员,每天会面对全球各地企业级客户提出的关于容器的各种问题,通过这几年的技术支持的经历,逐步发现容器问题客户的一些惯性,哪些是重度用户,哪些是轻度客户,这些客户大概分布在什么行业等等。 在渐渐地接触过程中,发现有些重度容器使用客户,所提出的问题场景也在逐步变化中,由于涉及法律法规,下面数据无法完整提供,只是提供相关简要说明。 纵向维度 从去年底开始,关于边缘集群的工单数量逐渐开始上升,增长幅度较大。其中涉及问题的边缘集群,超过一半左右来的客户集群规模比较大,集群节点规模数量级在几百个节点,甚至几千个节点规模。 横向维度 客户一: 该用户是目前是国内 ToC 端个性化推荐服务提供商之一,该客户在今年才开始使用 容器服务 Edge 版 ACK Edge 产品,到目前为止边缘集群的节点数已经快速破百。 客户二: 该用户是目前是国内电动汽车行业先驱者,并且一直处于新能源热门话题榜中,该客户第一次使用容器服务 Edge 版 ACK Edge 产品,到目前为止,边缘集群的节点数已经破千,占该客户所有容器集群节点数的近一半。 客户三: 该用户是全球著...
- 下一篇
重磅!中国开源社区landscape 8月月报来啦!
关于中国开源社区 Landscape 社区 COSCLC:中国开源社区 Landscape 社区,是以国内开源社区为单位的社区,旨在通过凝聚社区力量,推动国内开源生态发展。 Gitee仓库地址:https://gitee.com/oschina/china-opensource-community-landscape
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS7安装Docker,走上虚拟化容器引擎之路
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- CentOS8安装Docker,最新的服务器搭配容器使用
- Hadoop3单机部署,实现最简伪集群
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- CentOS8编译安装MySQL8.0.19