作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO
联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬
学习必须往深处挖,挖的越深,基础越扎实!
阶段1、深入多线程
阶段2、深入多线程设计模式
阶段3、深入juc源码解析
码哥源码部分
码哥讲源码-原理源码篇【2024年最新大厂关于线程池使用的场景题】
码哥讲源码-原理源码篇【揭秘join方法的唤醒本质上决定于jvm的底层析构函数】
码哥源码-原理源码篇【Doug Lea为什么要将成员变量赋值给局部变量后再操作?】
码哥讲源码【谁再说Spring不支持多线程事务,你给我抽他!】
打脸系列【020-3小时讲解MESI协议和volatile之间的关系,那些将x86下的验证结果当作最终结果的水货们请闭嘴】
redis 是内存数据库,可以通过 redis.conf
配置 maxmemory
,限制 redis 内存使用量。当 redis 主库内存超出限制时,命令处理将会触发数据淘汰机制,淘汰(key-value
)数据,直至当前内存使用量小于限制阈值。
1. 数据淘汰策略概述
redis.conf
配置 | 描述 |
---|---|
maxmemory | 将内存使用限制设置为指定的字节数。 |
redis 申请和回收内存基本上都是通过 zmalloc
接口统一管理的,可以通过接口统计 redis 的内存使用量。当 redis 超出了内存的使用限制 maxmemory,服务在处理命令时会触发 redis 内部的数据淘汰机制。淘汰目标数据一共有两种:
- 数据库所有(
key-value
)数据。 - 数据库所有被设置了过期时间的(key-value)数据。
aof 缓存,主从同步的积压缓冲区这些数据是不会被淘汰的,也没有计算在 maxmemory 里面。
针对这两种目标数据,它有几种淘汰策略:
- 随机淘汰。
- 先淘汰到期或快到期数据。
- 近似 LRU 算法(最近最少使用)
- 近似 LFU 算法 (最近使用频率最少)
关于近似的 lru
和 lfu
淘汰策略,英文好的朋友,可以去看看 antirez 的这两篇文章: Using Redis as an LRU cache, Random notes on improving the Redis LRU algorithm ,redis.conf 也有不少阐述。再结合源码,基本能理解它们的实现思路。
maxmemory 核心数据淘汰策略在函数 freeMemoryIfNeeded
中,可以仔细阅读这个函数的源码。
2. 配置
当 redis.conf 配置了 maxmemory,可以根据配置采用相应的数据淘汰策略。volatile-xxx
这种类型配置,都是只淘汰设置了过期时间的数据,allkeys-xxx
淘汰数据库所有数据。如果 redis 在你的应用场景中,只是作为缓存,任何数据都可以淘汰,可以设置 allkeys-xxx
。
配置 | 描述 |
---|---|
noeviction | 不要淘汰任何数据,大部分写操作会返回错误。 |
volatile-random | 随机删除设置了过期时间的键。 |
allkeys-random | 删除随机键,任何键。 |
volatile-ttl | 删除最接近到期时间(较小的TTL)的键。 |
volatile-lru | 使用近似的LRU淘汰数据,仅设置过期的键。 |
allkeys-lru | 使用近似的LRU算法淘汰长时间没有使用的键。 |
volatile-lfu | 在设置了过期时间的键中,使用近似的LFU算法淘汰使用频率比较低的键。 |
allkeys-lfu | 使用近似的LFU算法淘汰整个数据库的键。 |
#define MAXMEMORY_FLAG_LRU (1<<0)
#define MAXMEMORY_FLAG_LFU (1<<1)
#define MAXMEMORY_FLAG_ALLKEYS (1<<2)
#define MAXMEMORY_VOLATILE_LRU ((0<<8)|MAXMEMORY_FLAG_LRU)
#define MAXMEMORY_VOLATILE_LFU ((1<<8)|MAXMEMORY_FLAG_LFU)
#define MAXMEMORY_VOLATILE_TTL (2<<8)
#define MAXMEMORY_VOLATILE_RANDOM (3<<8)
#define MAXMEMORY_ALLKEYS_LRU ((4<<8)|MAXMEMORY_FLAG_LRU|MAXMEMORY_FLAG_ALLKEYS)
#define MAXMEMORY_ALLKEYS_LFU ((5<<8)|MAXMEMORY_FLAG_LFU|MAXMEMORY_FLAG_ALLKEYS)
#define MAXMEMORY_ALLKEYS_RANDOM ((6<<8)|MAXMEMORY_FLAG_ALLKEYS)
#define MAXMEMORY_NO_EVICTION (7<<8)
3. 数据淘汰时机
在事件循环处理命令时触发检查
int processCommand(client *c) {
...
if (server.maxmemory && !server.lua_timedout) {
int out_of_memory = freeMemoryIfNeededAndSafe() == C_ERR;
if (server.current_client == NULL) return C_ERR;
if (out_of_memory &&
(c->cmd->flags & CMD_DENYOOM ||
(c->flags & CLIEN