type
status
date
slug
summary
tags
category
password

1、Redis键空间

默认情况下,Redis 中有 16 个数据库,编号从 0-15。每个 Redis 数据库使用一个 redisDb 对象来表示,每个 redisDb 对象实际上是一个 dict 结构的数据集合。
其中 dict 保存了该 db 中的所有键值对。键值对中键是一个字符串对象,每个值可以是字符串对象、列表对象、哈希表对象、集合对象和有序集合对象在内的任意一种 RedisObject。
notion image
redis 通过全局哈希表保存所有的 key 值,所以查找 key 的时间为 O(1)。redis 一下次写入太多数据有可能会产生哈希冲突,全局哈希表也是通过渐进式 rehash 来解决 hash 冲突的问题。

2、过期删除策略

过期删除策略就是指 key 过期后 Redis 会如何删除。我们可以设置 Redis 中缓存的 key 的过期时间。通常有以下策略:
过期策略
描述
优点
缺点
定时删除
每个设置过期时间的key都需要创建一个定时器,到过期时间就会立即清除。
节省内存
CPU不友好,频繁的删除可能会影响性能
惰性删除
访问一个key时,会先判断该key是否已过期,过期则清除。
节省CPU资源,只在访问时进行过期检查,不会因为删除大量过期键而影响系统性能
如果键长期不被访问,即使已过期也会占用内存,导致内存浪费
定期删除
定期随机检查一批设置了过期时间的key,删除其中已过期的key
前两者的一个折中方案,使得CPU和内存资源达到最优的平衡效果。
需要找到合适的执行频率平衡点
Redis同时使用了惰性过期和定期过期两种过期策。每当我们为一个 key 设置过期时间,Redis 就会将该 key 带上过期时间存放到一个过期字典中。
  1. 惰性删除:当我们查询一个键时,Redis 先检查该 key 是否存在过期字典中,如果存在再判断其是否已经过期。如果已经过期,那么 Redis 会立即删除这个键,并返回 nil(就像这个键不存在一样)。然后再执行后续操作。
  1. 定期删除:Redis 默认会每 100ms 扫描一次过期字典:
    1. 从过期字典中随机选 20 个 key。
    2. 删除这 20 个 key 中已经过期的 key。
    3. 如果过期的 key 比率超过 25%,那就重复步骤 1,直到过期键的比例低于 25% 或者本次执行时间过长(超过预设的时间限制)才停止。

3、内存淘汰策略

内存淘汰策略是指在内存不足时如何删除 key 来释放空间。虽然我们有过期策略来淘汰已过期的数据,但是如果大量数据过期时间还没到,但此时内存已经快被占满了,我们就需要通过内存淘汰策略选择淘汰哪些数据。
内存淘汰策略整体分为三类:
  • 不进行数据淘汰
  • 在设置了过期时间的数据中进行淘汰
  • 在所有数据范围内进行淘汰
notion image
内存淘汰策略
描述
适用场景
noeviction
默认策略,不淘汰数据,当内存不足时,新写入操作会返回错误(如 OOM command not allowed when used memory > 'maxmemory')。
确保数据不丢失,但需应用程序自行处理写入失败。
volatile-ttl
在设置了过期时间的键中,优先删除剩余存活时间最短的键。如果无过期键,则退化为 noeviction。
希望优先淘汰即将过期的键。
volatile-random
在设置了过期时间的键中,进行随机删除。
无明确访问规律,随机淘汰降低开销。
volatile-lru
在设置了过期时间的键中,使用 LRU 算法,删除最近最长时间不使用的key。Redis 对 LRU 的优化:每次随机选出N个数据,比较该N个数据的最近访问的时间戳,然后最长时间不访问的数据。
热点数据分布明显,希望保留高频访问的键。
volatile-lfu
在设置了过期时间的键值对,使用 LFU 算法,删除使用次数最少的key。
长期未被访问的冷数据优先淘汰。
allkeys-random
从所有键值对中随机删除。
无明确访问规律,随机淘汰降低开销。
allkeys-lru
在所有数据中进行筛选,使用 LRU 算法,删除最近最长时间不使用的key。
热点数据分布明显,希望保留高频访问的键。
allkeys-lfu
在所有数据中进行筛选,使用 LFU 算法,删除使用次数最少的key。
长期未被访问的冷数据优先淘汰。
LRU和LFU算法比较:
  • LRU(Least Recently Used)淘汰最长时间未被使用的页面,强调的是最近访问时间。链表按访问时间进行排序,表头是最近访问的页面。如果访问命中了页面,就把页面移动到链表表头;如果没有命中就从表尾删除页面,然后把新页面放在表头,是比较符合正常思维逻辑的算法。
  • LFU(Least Frequently Used)淘汰最近被访问次数最少的页,强调的是最近访问频率。链表按访问次数进行排序,表头是访问次数最多的页面。如果访问命中了页面,就把页面的访问次数加一,此时如果该页面的访问次数大于前一个页面就互相交换位置;如果没有命中页面就从表尾删除数据。这种算法有一个明显的问题:如果某页面开始访问次数较多,但后面没有再被访问,这些页面无法被删除。所以 LFU 算法用的比较少。
淘汰策略选择建议:
  • 优先使用 allkeys-lru 策略。如果你的业务数据中有明显的冷热数据区分,希望可以保存高频访问的热点数据,那么可以使用 allkeys-lru 策略。这样可以充分利用 LRU 这一经典缓存算法的优势,把最近最常访问的数据留在缓存中,提升应用的访问性能。
  • 如果业务应用中的数据访问频率相差不大,没有明显的冷热数据区分,建议使用 allkeys-random 策略, 随机选择淘汰的数据就行。
  • 如果你的业务中有置顶的需求,比如置顶新闻、置顶视频,那么,可以使用 volatile-lru 策略,同时不给这些置顶数据设置过期时间。这样一来,这些需要置顶的数据一直不会被删除,而其他数据会在过期时根据 LRU 规则进行筛选。
Redis系列:持久化机制Redis系列:数据结构和对象
Loading...