笔者在线上使用redis缓存的时候发现即使某些查询已经设置了无过期时间的缓存,但是查询仍然非常耗时。经过排查,发现缓存确实已经不存在,导致了缓存击穿,查询直接访问了mysql数据库。因为我们用的是公司公共的redis缓存服务器,在和运维人员交流后发现可能是redis的内存淘汰策略引起。
1. 什么是内存淘汰
redis是基于内存的key-value数据库,内存是有限的宝贵资源,当内存耗尽的时候,redis有如下5种处理方式来应对
No-eviction
在该策略下,如果继续向redis中添加数据,那么redis会直接返回错误
Allkeys-lru
从所有的key中使用LRU算法进行淘汰
Volatile-lru
从设置了过期时间的key中使用LRU算法进行淘汰
Allkeys-random
从所有key中随机淘汰数据
Volatile-random
从设置了过期时间的key中随机淘汰
Volatile-ttl
从设置了过期时间的key中,选择剩余存活时间最短的key进行淘汰
除上述6种淘汰策略外,Redis 4.0新增了两种淘汰策略
Volatile-lfu
从设置了过期时间的key中选择key进行淘汰
Allkeys-lfu
从所有的key中使用lfu进行淘汰
2. 内存淘汰算法选择
上述总共谈到了8种内存淘汰策略,但是如何选择呢?
从缓存类型来说,其中名称中带volatile的策略确定了被淘汰的缓存仅从设置了过期时间的key中选择,如果没有任何key被设置过期时间,那么Volatile-lru,Volatile-random,Volatile-lfu表现得就分别和allkeys-lru,allkeys-random,allkey-lfu算法相同。
如果缓存有明显的热点分布,那么应该选择lru类型算法,如果缓存被访问几率相同,那么应该选择随机淘汰算法。
在使用中,lru和lfu效果差不多,而且lru可能更有优势一些,笔者在下文详细的对比了lru和lfu
3. 配置使用
我们可以通过redis.conf文件配置如下两个参数
maxmemory 10mb
maxmemory-policy allkeys-random
如果maxmemory被设置为0则代表无限制redis的内存使用,但是这种方案可能会导致redis耗尽内存从而造成磁盘数据交换,这种情况下可能会造成频繁的访问中断,redis也失去了高性能的优势。Redis上述的两个参数也支持运行情况下修改,比如使用如下命令将内存使用限制为100MB,
CONFIG SET maxmemory 100MB
4. LRU
LRU即最近最久未使用算法,它利用局部性原理管理数据,它根据历史访问记录淘汰数据,如果数据最近被访问过,那