作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO
联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬
学习必须往深处挖,挖的越深,基础越扎实!
阶段1、深入多线程
阶段2、深入多线程设计模式
阶段3、深入juc源码解析
码哥源码部分
码哥讲源码-原理源码篇【2024年最新大厂关于线程池使用的场景题】
码哥讲源码-原理源码篇【揭秘join方法的唤醒本质上决定于jvm的底层析构函数】
码哥源码-原理源码篇【Doug Lea为什么要将成员变量赋值给局部变量后再操作?】
码哥讲源码【谁再说Spring不支持多线程事务,你给我抽他!】
打脸系列【020-3小时讲解MESI协议和volatile之间的关系,那些将x86下的验证结果当作最终结果的水货们请闭嘴】
redis 可能存在大量过期数据,一次性遍历检查不太现实。
redis 有丰富的数据结构,key-value
, value
数据结构对象可能存储大量数据,key
过期了,value
也不建议在进程中实时回收。
为了保证系统高性能,每次处理一点点,逐渐完成大任务,“分而治之” 这是 redis 处理大任务的一贯作风。
1. 流程
主服务检查过期/删除过期逻辑 -> 删除过期键值 -> 异步/同步删除数据 -> 主从同步。
redis 数据库,数据内容和过期时间是分开保存。expires
保存了键值对应的过期时间。
typedef struct redisDb {
dict *dict; /* The keyspace for this DB */
dict *expires; /* Timeout of keys with a timeout set */
...
} redisDb;
2. 策略概述
2.1. 过期检查
过期数据检查有三个策略:
-
访问键值触发检查。访问包括外部读写命令,内部逻辑调用。
不可能每个过期键都能实时被访问触发,所以要结合其它策略。
-
事件驱动处理事件前触发快速检查。
将过期检查负载一点点分摊到每个事件处理中。
-
时钟定期慢速检查。
2.2. 数据回收
数据回收有同步和异步两种方式,配置文件可以设置,一般默认异步回收数据。
异步数据回收有两个策略:
-
小数据实时回收。
-
大数据放到任务队列,后台线程处理任务队列异步回收内存。
可以看看
bio.c
的实现。
2.2.1. 同步
int dbSyncDelete(redisDb *db, robj *key) {
/* Deleting an entry from the expires dict will not free the sds of
* the key, because it is shared with the main dictionary. */
if (dictSize(db->expires) > 0)
dictDelete(db->expires, key->ptr);
if (dictDelete(db->dict, key->ptr) == DICT_OK) {
if (server.cluster_enabled)
slotToKeyDel(key);
return 1;
} else {
return 0;
}
}