前言
我们都知道在Redis 所有的数据结构都可以设置过期时间,时间一到,就会自动删除。想象一下里面有一个专门删除过期数据的线程,如果数据已过期就立马删除。这个时候可以思考一下,会不会因为同一时间太多的 key 过期,以至于线程忙不过来。同时因为 Redis 是单线程的,删除的时间也会占用线程的处理时间,如果删除的太过于繁忙,会不会导致线上读写指令出现卡顿。
redis.conf中的maxmemory
当redis使用内存达到了一个maxmemory的参数配置阈值的时候,那么redis就会根据配置的内存淘汰策略,把访问频率不高的key从内存里面移除掉,maxmemory的默认值是服务器的最大内存。
maxmemory <bytes>
maxmemory的默认值是0,也就是不限制内存的使用。
32bit系统如果使用默认配置或配置为maxmemory 0则最大使用3G内存。
maxmemory的值没有最小限制(但是如果低于1MB,会打一条WARNING日志)。
如果设置了maxmemory选项(值 >= 1),redis在接收命令时总是会判断当前是否已经超出最大内存限制,如果超过限制会根据驱逐策略去释放内存(如果是同步释放且释放内存很大,则会阻塞其他命令的执行)。
单位问题:
- maxmemory 100 裸数字情况:单位是字节。
- maxmemory 1K K:代表1000字节。
- maxmemory 1KB KB:代表1024字节。
- maxmemory 1M M:代表1000000字节。
- maxmemory 1MB MB: 代表1048576字节。
- maxmemory 1G G:代表1000000000字节。
- maxmemory 1GB GB: 代表1073741824字节。
过期key删除策略
立即删除
定时删除也就是立即删除。
在设置key的过期时间的同时,为该key创建一个定时器,让定时器在key的过期时间来临时,对key进行删除。
优点: 立即删除能保证内存中数据的最大新鲜度,因为它保证过期键值会在过期后马上被删除,其所占用的内存也会随之释放。对内存来说是非常友好的。
缺点: 立即删除对cpu是最不友好的。因为删除操作会占用cpu的时间,如果刚好碰上了cpu很忙的时候,比如正在做交集或排序等计算的时候,就会给cpu造成额外的压力。
总结:用cpu性能换取内存空间(时间换空间)。
惰性删除
当数据到达过期时间时,先不做处理。等到下次访问该数据时,如果数据已过期,再对数据进行删除。
优点 :对于cpu来说是非常友好的,减少了cpu资源的占有。
缺点:: 如果一个键已经过期,而这个键又仍然保留在redis中,那么只要这个过期键不被删除,它所占用的内存就不会释放。因此对于内存是很不友好的。
总结:用内存换取cpu处理时间(空间换时间)。
定期删除
定期删除策略是前两种策略的折中:定期删除策略每隔一段时间执行一次删除过期键操作并通过限制删除操作执行时长和频率来减少删除操作对CPU时间的影响。
每隔一段时间执行一次删除过期key操作。
- 通过限制删除操作的时长和频率,来减少删除操作对CPU时间的占用(处理"定时删除"的缺点)
- 定期删除过期key(处理"惰性删除"的缺点)
过期key的集合
redis 会将每个设置了过期时间的 key 放入到一个独立的字典中,以后会定时遍历这个 字典来删除到期的 key。除了定时遍历之外,它还会使用惰性策略来删除过期的 key。定期删除是集中处理,惰性删除是零散处理。
- 如果删除操作执行次数过多、执行时间太长,就会导致和定时删除同样的问题:占用大量cpu资源去进行删除操作
- 如果删除操作次数太少、执行时间短,就会导致和惰性删除同样的问题:内存资源被持续占用,得不到释放。
所以定时删除最关键的就在于执行时长和频率的设置,可在redis的配置文件中配置
缓存淘汰策略
当redis的内存占用过多的时候,此时会进行内存淘汰,redis6以后有如下一些策略:
- noeviction:不会继续服务写请求 (DEL 请求可以继续服务),读请求可以继续进行。这样 可以保证不会丢失数据,但是会让线上的业务不能持续进行。这是默认的淘汰策略。
- volatile-lru:尝试淘汰设置了过期时间的 key,最少使用的 key 优先被淘汰。没有设置过 期时间的 key: 不会被淘汰,这样可以保证需要持久化的数据不会突然丢失。
- allkeys-lru: 区别于 volatile-lru,这个策略要淘汰的 key 对象是全体的 key 集合,而不 只是过期的 key 集合。这意味着没有设置过期时间的 key 也会被淘汰。
- volatile-ttl: 跟上面一样,除了淘汰的策略不是 LRU,而是 key 的剩余寿命 ttl 的值,ttl 越小越优先被淘汰。
- volatile-random:对所有设置了过期时间的key随机淘汰。
- allkeys-random:对所有key随机淘汰
- volatile-lfu:对设置了过期时间的key使用lfu算法进行删除
- allkeys-lfu:对所有key使用lfu算法进行删除
总结:volatile-xxx: 策略只会针对带过期时间的 key 进行淘汰,allkeys-xxx 策略会对所有的 key 进行淘汰。如果你只是拿 Redis 做缓存,那应该使用 allkeys-xxx,客户端写缓存时 不必携带过期时间。
- LRU:最近最少使用页面置换算法,淘汰最长时间未被使用的页面,看页面最后一次被使用到发生调度的时间长短,首先淘汰最长时间未被使用的页面。
- LFU:最近最不常用页面置换算法,淘汰一定时期内被访问次数最少的页,看一定时间段内页面被使用的频率,淘汰一定时期内被访问次数最少的页