一、确认 Redis 的最大内存容量
根据“二八原则”,20% 的数据提供了 80% 的访问量,这也被称之为“长尾效应”,但是这个是根据大量的数据统计出来的而一个结果,在实际的应用中并不能确定,因此要根据实际的数据访问特征和成本开销来确定实际设置的 Redis 缓存的数据实际容量是总数据量的百分之几,一般建议设置为 15%~30% 不等,设置大量的缓存容量虽然可以提高缓存命中率,但是其内存开销的成本过大,而小的缓存内存也不一定就不能提高访问数据的效率,当然不可能将大量的数据全部存储到缓存中,因此就肯定会有缓存缺失,需要利用数据淘汰机制来选择淘汰一些应用程序可能长时间不会再使用的数据,将这些数据写回后端数据库,并读取后端数据库中应用程序需要使用的数据写入缓存中。
二、Redis 缓存中有哪些数据淘汰策略?
- 不进行数据淘汰的策略
- noeviction(没有受害者策略) 策略:当 Redis 实例中内存已经满时,当再有新的写操作,Redis 就不再提供写命令的服务,而是直接返回错误,因此这种策略不会使用在 Redis 作为缓存时的策略。
- 进行数据淘汰的策略
- 区分是否设置了过期时间(使用 EXPIRE 命令对键值对设置过期的时间,此时无论 Redis 缓存所占用内存是否达到了 maxmemory 值,都会根据以下四种策略的淘汰策略针对被设置了过期时间的键值对进行筛选并淘汰)(volatile:不稳定的)
- volatile-random:针对设置了过期时间的键值对,进行随机的删除
- volatile-ttl:针对设置了过期时间的键值对,筛选出最早过期的键值对进行淘汰。
- volatile-lru:针对设置了过期时间的键值对,根据 LRU 算法计算出这些数据中最长未被使用的数据进行淘汰。(LRU 算法考虑数据的时效性来进行筛选即将淘汰的数据)
- volatile-lfu:针对设置了过期时间的键值对,根据 LFU 算法计算出最少访问次数的键值对进行淘汰,如果最少访问的次数相同的数据就会再使用 LRU 算法计算出其中最长未被使用的键值对进行淘汰。(即 LFU 算法首先考虑数据的访问次数,在考虑数据的时效性)
- 不区分设置了过期时间(使用以下的策略中筛选出来的数据即使键值对的过期时间没有到也会被删除,当然对于设置了过期时间的数据一旦到达了的过期的时间,不会受其影响,正常的从 Redis 缓存中删除)
- allkeys-random:在所有的键值对中随机删除一些数据
- allkeys-lfu:在所有的键值对中根据数据的访问次数及其数据的时效性(最久未被访问的数据优先)筛选出即将被淘汰的数据
- allkeys-lru:在所有的键值对中根据数据的时效性筛选出即将被淘汰的数据。
- 区分是否设置了过期时间(使用 EXPIRE 命令对键值对设置过期的时间,此时无论 Redis 缓存所占用内存是否达到了 maxmemory 值,都会根据以下四种策略的淘汰策略针对被设置了过期时间的键值对进行筛选并淘汰)(volatile:不稳定的)
三、Redis 缓存中简化版的 LRU 算法
在 URL 算法中需要对其保存的数据构成连链表的形式保存起来,这就需要额外的空间开销,同时在对链表中保存的数据进行访问的时候还涉及到链表的移动,比较耗时,链表的维护会给 Redis 缓存带来影响,因此为了避免这些问题,Redis 对 URL 算法进行了简化。让键值对中的 RedisObject 结构体中的 lru 字段中保存该键值对最近访问的时间戳,当 Redis 进行数据淘汰的时候就会随机挑选 N 个键值对数据,,将这些数据组成一个候选集合,然后根据这随机的 N 个数据的 url 字段保存的时间戳挑选出最小的那个,即最近被访问的时间戳最早的那个键值对筛选出来,然后淘汰掉。其中挑选的数据的个数 N 的值由 maxmemory-samples(最大内存-样品) 参数来配置。并且之后 Redis 再进行数据淘汰时,就会挑选新的键值对到第一次生成的候选数据集中,其中放入候选数据集的数据的挑选标准就是被挑选放入候选集合中的键值对的 lru 字段的值小于候选集和中最小的 url 字段值,直至候选集和中的数据的个数达到了设置的 maxmemory-samples 的值,就会从候选集合中挑选 url 字段最小的数据进行淘汰。这样的简化方式就减少了对 URL 链表的维护及其保存链表的空间开销和链表移动的开销,减少对 Redis 的性能上的影响。
四、Redis 选择淘汰策略的方式
- 如果业务数据中有明显的冷热数据的区分,那么就建议使用 allkeys-lru 数据淘汰策略,这样可以充分的利用到经典的缓存算法 URL 的优势,将最近访问的数据保存的缓存中,对于热数据而言,就会经常地被访问,因此就可以长时间地缓存在 Redis 中,从而提高 Redis 的缓存命中率,进而使得应用程序的访问速率得到提升
- 如果业务数据中没有明现的冷热数据的区分,那么就建议使用 allkeys-random 数据淘汰策略,随机的从缓存中筛选数据进行淘汰,因为使用 allkeys-lru 策略需要额外的内存空间及其链表移动维护等开销,如果没有明现的冷热数据区分的话,URL 算法的优势发挥的作用并不大。
- 如果业务数据中存在一些需要置顶的数据,例如置顶的新闻,置顶的视频,那么就可以使用针对设置了过期时间的键值对的淘汰机制,这样就可以将一些置顶的数据不设置其过期的时间,从而避免从 Redis 缓存中被淘汰掉,可以一直保存在 Redis 缓存中。
五、如何处理被淘汰掉的数据?
如果被淘汰的数据数据是干净数据,那么就可以直接从 redis 缓存中删除即可,如果该数据属于脏数据,那么就需要将该最新的数据写回到后端数据库中,避免数据丢失。