前言
我们都知道Redis的数据都是存储在内存中,当内存的被占满了,Reids将会怎么办?Redis提供了一套过期删除缓存的策略,以便新的数据能够放到redis中,那么生产环境我们将如何选择Redis的内存淘汰策略呢?
简介
Redis提供了过期key的淘汰策略和内存淘汰策略,具体如下:
Redis的Key过期策略
Redis为Key设置过期时间,当到达过期时间后,Redis要将这个key删除掉,Redis过期Key提供了三种策略,分别为:定时删除、定期删除、惰性删除。
定时删除
在设置某个Key的过期时间同时,Reids创建一个定时器,让定时器在该过期时间到来时,立即执行对其进行删除的操作。这种策略对内存友好,因为过期了会立马删除,但是对CPU不友好,在过期键比较多的时候,删除过期键会占用一部分CPU时间,对服务器的响应时间和吞吐量造成影响。
惰性删除:
惰性删除是客户端访问Key,Redis对key的过期时间进行检查,如果过期了就立即删除,然后返回null。惰性删除策略的缺点是, 它对内存是最不友好的。如果一个键已经过期,而这个键又仍然保留在redis中,那么只要这个过期键不被删除,它所占用的内存就不会释放。
定期删除
Redis会将每个设置了过期时间的Key放入到一个独立的字典中,以后会定期遍历这个字典来删除到期的key。Redis默认每秒进行10次过期扫描(100ms一次,可以通过修改配置文件redis.conf 的 hz 选项来调整这个次数),但这个扫描并不会扫描过期字典中所有的key,而是通过一种贪心策略来随机筛选删除key,步骤如下:
- 从过期字典中随机选出20个key;
- 删除这20个key中已经过期的key;
- 如果过期的key的比例超过了1/4,那就重复从步骤1开始执行。
之所以采用这种扫描策略,为了性能考虑。假如过期字典中有数百万个key,每隔100ms就扫描百万个Key,会给CPU造成很大的负荷,所以Redis会随机筛选部分key,然后按照过期比例来判断是否需要重复执行筛选过期的动作。
正是由于使用了这种扫描策略,定期删除可能会造成很多已经过期的key无法及时删除。
小结
- 定时删除:对CPU不友好,影响CPU的性能。
- 定期删除:定期抽样key,判断是否过期,会存在遗漏的情况。
- 惰性删除:对内存不友好,用存储空间换取处理器的性能。
内存淘汰策略
Redis的6.0版本中提供了八种内存淘汰策略,具体如下:
不进行数据淘汰的策略
- noeviction(没有受害者策略) 策略:当 Redis 实例中内存已经满时,当再有新的写操作,Redis 就不再提供写命令的服务,而是直接返回错误,因此这种策略不会使用在 Redis 作为缓存时的策略。
数据淘汰的策略
设置了过期时间
通过使用EXPIRE命令对键值对设置过期的时间,此时无论 Redis 缓存所占用内存是否达到了 maxmemory 值,都会根据以下四种策略的淘汰策略针对被设置了过期时间的键值对进行筛选并淘汰)
- volatile-random:针对设置了过期时间的键值对,进行随机的删除
- volatile-ttl:针对设置了过期时间的键值对,筛选出最早过期的键值对进行淘汰。
- volatile-lru:针对设置了过期时间的键值对,根据 LRU 算法计算出这些数据中最长未被使用的数据进行淘汰。(LRU 算法考虑数据的时效性来进行筛选即将淘汰的数据)
- volatile-lfu:针对设置了过期时间的键值对,根据 LFU 算法计算出最少访问次数的键值对进行淘汰,如果最少访问的次数相同的数据就会再使用 LRU 算法计算出其中最长未被使用的键值对进行淘汰。(即 LFU 算法首先考虑数据的访问次数,在考虑数据的时效性)
不设置了过期时间
使用以下的策略中筛选出来的数据即使键值对的过期时间没有到也会被删除,当然对于设置了过期时间的数据一旦到达了的过期的时间,不会受其影响,正常的从 Redis 缓存中删除.
- allkeys-random:在所有的键值对中随机删除一些数据
- allkeys-lfu:在所有的键值对中根据数据的访问次数及其数据的时效性(最久未被访问的数据优先)筛选出即将被淘汰的数据
- allkeys-lru:在所有的键值对中根据数据的时效性筛选出即将被淘汰的数据。
Redis内存淘汰算法配置
Redis内存设置
Redis通过maxmemory来设置内存大小,默认情况下Reids的内存在64位操作系统下的大小是不受限制的,而在32位操作系统下最大内存位3G。
- maxmemory:设置内存大小,单位是bytes字节,单机Redis的内存不宜设置过大,内存大小尽量控制在2~4G作用,一般推荐Redis设置内存为最大物理内存的四分之三。
查询Redis使用内存
登录Redis客户端,执行info memory命令
info memory
说明:
- used_memory:通过libc或者jemalloc方法分配的字节数大小
- used_memory_human:将used_memory格式转化为人类可读的值,以MB为单位
- used_memory_rss:常驻集大小(resident set size,简写为rss)指的是在操作系统中看到的内存分配,以及通过UNIX工具top显示的结果
- used_memory_peak:Redis使用的峰值内存,以字节为单位
- used_memory_peak_human:将used_memory_peak格式转化为人类可读的格式。以MB为单位
- used_memory_lua:Redis的lua子系统使用的字节数
- mem_fragmentation_ratio:used_memory_rss与used_memory的比率
- mem_allocator:在编译期redis使用的分配器。
Redis淘汰算法设置
在配置文件redis.conf 中,通过设置 maxmemory-policy 来指定使用哪种内存淘汰策略:
- maxmemory-policy:设置具体的淘汰算法
- maxmemory-samples 5:Redis的LRU算法的时候,Redis每次会随机选择N个key放入淘汰池中,这个
N的就是通过maxmemory-samples选项来配置的.
业务如何选择淘汰策略
-
业务数据中有明显的冷热数据的区分,那么就建议使用 allkeys-lru 数据淘汰策略,这样可以充分的利用到经典的缓存算法 URL 的优势,将最近访问的数据保存的缓存中,对于热数据而言,就会经常地被访问,因此就可以长时间地缓存在 Redis 中,从而提高 Redis 的缓存命中率,进而使得应用程序的访问速率得到提升。
-
业务数据中没有明现的冷热数据的区分,那么就建议使用 allkeys-random 数据淘汰策略,随机的从缓存中筛选数据进行淘汰,因为使用 allkeys-lru 策略需要额外的内存空间及其链表移动维护等开销,如果没有明现的冷热数据区分的话,URL算法的优势发挥的作用并不大。
-
业务数据中存在一些需要置顶的数据,例如置顶的新闻,置顶的视频,那么就可以使用针对设置了过期时间的键值对的淘汰机制,这样就可以将一些置顶的数据不设置其过期的时间,从而避免从 Redis 缓存中被淘汰掉,可以一直保存在 Redis缓存中。
总结
本文讲解了Redis的过期Key和内存淘汰策略,需要根据具体的业务场景来选择淘汰策略,如有疑问请随时反馈。