Redis学习笔记—Redis的缓存过期和淘汰策略
1.性能简介
- Redis性能高:
- 官方数据
- 读:110000次/s
- 写:81000次/s
- 长期使用,key会不断增加,Redis作为缓存使用,物理内存也会满
- 内存与硬盘交换(swap) 虚拟内存 ,频繁IO 性能急剧下降
2.maxmemory:作为redis最大物理内存
-
不设置的场景,作为DB使用
- Redis的key是固定的,不会增加
- Redis作为DB使用,保证数据的完整性,不能淘汰 , 可以做集群,横向扩展
- 缓存淘汰策略:禁止驱逐 (默认)
-
设置的场景
- Redis是作为缓存使用,不断增加Key
- maxmemory : 默认为0 不限制
-
:达到物理内存后性能急剧下架,甚至崩溃,这是为什么?问题
:内存与硬盘交换(swap) 虚拟内存 ,频繁IO 性能急剧下降答
-
设置多少?
- 与业务有关
- 1个Redis实例,保证系统运行 1 G ,剩下的就都可以设置Redis,物理内存的3/4
- slaver : 留出一定的内存
- 在redis.conf 设置属性
,如果数字后面没有单位一律按照B结尾maxmemory 1024mb
-
: 获得maxmemory数 `CONFIG GET maxmemory命令
- 设置maxmemory后,当趋近maxmemory时,通过缓存淘汰策略,从内存中删除对象
- 不设置maxmemory 无最大内存限制 maxmemory-policy noeviction (禁止驱逐) 不淘汰
- 设置maxmemory,在配置文件中maxmemory-policy(淘汰策略) 要配置
3. expire数据结构
- 在
中可以使用Redis
命令设置一个键的存活时间expire
,过了这段时间,该键就会自动被删除。(ttl: time to live)
4.expire原理
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL5NGVPBTR61UNNpHW4Z0MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL3YzM2ADM1UTM0AzNwEjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
- 上面的代码是Redis 中关于数据库的结构体定义,这个结构体定义中除了 id 以外都是指向字典的指针,其中我们只看 dict 和 expires。
- dict 用来维护一个 Redis 数据库中包含的所有 Key-Value 键值对,expires则用于维护一个 Redis 数据库中设置了失效时间的键(即key与失效时间的映射)。
- 当我们使用 expire命令设置一个key的失效时间时,Redis 首先到 dict 这个字典表中查找要设置的key是否存在,如果存在就将这个key和失效时间添加到 expires 这个字典表。
- 当我们使用 setex命令向系统插入数据时,Redis 首先将 Key 和 Value 添加到 dict 这个字典表中,然后将 Key 和失效时间添加到 expires 这个字典表中。
- 简单地总结来说就是,设置了失效时间的key和具体的失效时间全部都维护在 expires 这个字典表中。
5.删除策略
- Redis的数据删除有定时删除、惰性删除和主动删除三种方式。
- Redis目前采用惰性删除+主动删除的方式。
- 定时删除
- 在设置键的过期时间的同时,创建一个定时器,让定时器在键的过期时间来临时,立即执行对键的删除操作。
- 需要创建定时器,而且消耗CPU,一般不推荐使用。
- 惰性删除
- 在key被访问时如果发现它已经失效,那么就删除它。
- 调用expireIfNeeded函数,该函数的意义是:读取数据之前先检查一下它有没有失效,如果失效了就删除它。
- 主动删除
- 在redis.conf文件中可以配置主动删除策略,默认是no-enviction(不删除)
- 在redis.conf文件中可以配置
maxmemory-policy allkeys-lru
6.LRU简介
- LRU (Least recently used) 最近最少使用,算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。
- 最常见的实现是使用一个链表保存缓存数据,详细算法实现如下:
- 新数据插入到链表头部;
- 每当缓存命中(即缓存数据被访问),则将数据移到链表头部;
- 当链表满的时候,将链表尾部的数据丢弃。
- 在Java中可以使用LinkHashMap(哈希链表)去实现LRU
- 让我们以用户信息的需求为例,来演示一下LRU算法的基本思路:
- 假设我们使用哈希链表来缓存用户信息,目前缓存了4个用户,这4个用户是按照时间顺序依次从链表右端插入的。
7.LRU数据淘汰机制
- 在服务器配置中保存了 lru 计数器 server.lrulock,会定时(redis 定时程序 serverCorn())更新,server.lrulock 的值是根据 server.unixtime 计算出来的。
- 另外,从redisObject 中可以发现,每一个 redis 对象都会设置相应的 lru。可以想象的是,每一次访问数据的时候,会更新 redisObject.lru。
- LRU 数据淘汰机制是这样的:在数据集中随机挑选几个键值对,取出其中 lru 最大的键值对淘汰。
- 不可能遍历key 用
越大 说明 访问间隔时间越长当前时间-最近访问
8. 缓存淘汰策略的选择
-
: 不删除策略, 达到最大内存限制时, 如果需要更多内存, 直接返回错误信息。 大多数写命令都会导致占用更多的内存(有极少数会例外, 如 DEL )。noeviction
-
: 所有key通用; 优先删除最近最少使用(less recently used ,LRU) 的 key,在不确定时一般采用策略。 冷热数据交换allkeys-lru
-
: 只限于设置了 expire 的部分; 优先删除最近最少使用(less recently used ,LRU) 的 key,比allkeys-lru性能差,存过期时间volatile-lru
-
: 希望请求符合平均分布(每个元素以相同的概率被访问)allkeys-random
-
: 只限于设置了 expire 的部分; 随机删除一部分 key。volatile-random
-
:自己控制,只限于设置了 expire 的部分; 优先删除剩余时间(time to live,TTL) 短的key,缓存穿透volatile-ttl