1、定时删除

做法:对键设置过期时间时,同步设置一个定时器,当达到定时时间时间时,立即删除键;

优点:省内存,立即删除,释放内存;

缺点:CPU使用率高,容易造成系统卡顿;

Redis并不推荐的方式;

2、惰性删除

做法:不主动删除key,在每次读写之前,调用expireIfNeeded函数确定key是否过期,如果过期删除,没有就不做处理,之后执行命令;

优点:直接删除效率大部分非常快,只有非常大的对象回收时可能存在卡顿,CPU处理次数少;

缺点:很多到了过期时间的key还占用着内存;

内存够多,不存在非常多设置了失效时间的大对象可以使用;

3、定期删除

做法:定时删除和定期删除的折中做法,把设置了过期时间的key放入一个特定的字典中,周期性调用activeExpireCycle函数,周期时间可以设定,默认100ms执行一次,从特定的某个库开始轮训,db0,db1…,保证每一个redis的库都被执行到,随机选出一定量的key,删除达到了过期时间的key,并判断删除的key是否大于某一个值,比如1/4,如果超过1/4,则表示有很多的key需要失效,重复随机选择key,删除key操作,知道删除的key小于1/4;

优点:省内存对CPU执行大概率也不会非常频繁;

缺点:可能存在过期的key被使用,如果一段时间非常多的key失效,导致循环次数过多,也会造成系统卡顿;

一般推荐方式;

3.1、定期删除为什么不扫描所有key

如果过期的key过多,扫描时间和删除时间过大,如果多次大于1/4,系统就会一直卡死,导致客户端查询一直不可用,所以Redis为每次扫描设置了扫描上限时间,默认25ms,这样也就不能扫描所有的key,时间上不够;

3.2、为什么不建议多个失效key使用相同的时间,而是使用随机时间

多个key同时失效,删除会一直循环,系统卡住,而且多个key同时失效,会造成缓存雪崩,大量的查询直接查询数据库,最后导致数据库性能急剧下降;

3.3、为什么Redis设置了扫描上限时间25ms,还是会出现卡顿

因为Redis执行指令是单线程,循环次数过多,每次25ms,100次就是2.5s,所以会存在卡顿;

4、异步删除策略,这样就不会阻碍主线程的操作

unlink 指令,它能对删除操作进行懒处理,丢给后台线程来异步回收内存。

unlink key

flushall 清理数据库

flushdb async 
flushall async

从库接受完 rdb 文件后的 flush 操作

slave-lazy-flush 

内存达到 maxmemory 时进行淘汰

lazyfree-lazy-eviction 

过期删除

lazyfree-lazy-expire key 

指令删除 destKey

lazyfree-lazy-server-del rename 

5、设置了内存最大值,需要同步设置内存淘汰侧率

noeviction:当内存超出 maxmemory,写入请求会报错,但是删除和读请求可以继续,业务上基本不能使用。

allkeys-lru:当内存超出 maxmemory,在所有的 key 中,移除最少使用的key,只把 Redis既当缓存时可以使用这种策略。

allkeys-random:当内存超出 maxmemory,在所有的 key 中,随机移除某个 key,过于危险,不可控。

volatile-lru:当内存超出 maxmemory,在设置了过期时间 key 的字典中,移除最少使用的 key。把 Redis既当缓存,又做持久化的时候使用这种策略。

volatile-random:当内存超出 maxmemory,在设置了过期时间 key 的字典中,随机移除某个key。

volatile-ttl:当内存超出 maxmemory,在设置了过期时间 key 的字典中,优先移除 ttl 小的。

6、Redis的近似LRU和LFU算法

LRU算法:删除最近使用时间最早的数据;
逻辑:维持一个按照最近访问时间的双向链表,内存达到最大值,循环移除链表后面的数据,直到内存小于最大值,如果key被访问,把当前key放在链表头部,当一个只访问过一次的key,它被淘汰删除的时间会很长;
LFU算法:在一段时间内访问最少的key最先删除;
逻辑:每一个key保存访问次数;

// redis 的对象头
typedef struct redisObject {
    unsigned type:4; // 对象类型如 zset/set/hash 等等
    unsigned encoding:4; // 对象编码如 ziplist/intset/skiplist 等等
    unsigned lru:24; // 对象的「热度」
    int refcount; // 引用计数
    void *ptr; // 对象的 body
} robj;

Redis在内存大于设定的最大值时,根据配置的过期算法和策略,获取key信息,之后根据Redis对象的头部信息,判断使用时间和次数,根据具体的算法删除数据。

7、Redis持久化RDB(Redis DataBase)和AOF(Append Only File)

RDB:根据指定的时间做持久化,默认方式,redis.conf配置路径,生成dump.rdb二进制文件;
方式:启动一个子进程,子进程有父进程的内存快照,在持久化过程中,父进程修改内容,子进程不能感知,每次备份都是全量备份;
优点:可以在Redis空闲的时候持久化,还原速度快; 缺点:服务宕机,只能恢复上次持久化的数据,指定持久化时间越短,需要更多的存储空间;

AOF:保存所有的对Redis做更新的命令到磁盘,还原时重新执行一次所有的更新炒作;
方式:Redis将执行完的命令、命令的参数、命令的参数个数等信息发送到AOF程序中,AOF程序根据接收到的命令数据,将命令转换为网络通讯协议的格式,然后将协议内容追加到服务器的AOF缓存中,AOF缓存中的内容被写入到AOF文件末尾,如果设定的AOF保存条件被满足的话,fsync函数或者fdatasync函数会被调用,将写入的内容真正地保存到磁盘中。
优点:恢复时数据保存完整; 缺点:恢复数据慢,而且每次更新操作都持久化,少量命令,耗时可控,批量命令,大对象,性能降低;

7.1AOF需要手动开启,RDB默认开启,开启方式

# 可以通过修改redis.conf配置文件中的appendonly参数开启
appendonly yes
# AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的。
dir ./
# 默认的文件名是appendonly.aof,可以通过appendfilename参数修改
appendfilename appendonly.aof
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐