缓存数据库redis之三:内存淘汰策略及优化(代码片段)

云来云去-起飞 云来云去-起飞     2022-12-18     704

关键词:

目录

一、Redis的内存淘汰策略

    1.1. 概念

    1.2.策略一:全局的键空间选择性移除

    1.3.策略二:设置过期时间的键空间选择性移除

   1.4.LRU、LFU和volatile-ttl都是近似随机算法

 1.4.1.LRU算法

 1.4.2.LFU算法

1.5.过期删除策略

1.6.AOF和RDB的过期删除策略

二、REDIS的消耗及优化

        2.1.消耗状态

         2.2.优化

2.2.1.Redis的内存优化

2.2.2.避免使用KEYS

2.2.3.设置 key 有效期

2.2.4.选择回收策略

2.2.5.限制redis的内存大小

2.2.6.部署和场景应用优化


一、Redis的内存淘汰策略

    1.1. 概念

       Redis的内存淘汰策略是指在Redis的用于缓存的内存不足时,怎么处理需要新写入且需要申请额外空间的数据。

    1.2.策略一:全局的键空间选择性移除

  • - noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。
  • - allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。(这个是**最常用**的)
  • - allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key。

    1.3.策略二:设置过期时间的键空间选择性移除

  • - volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key。
  • - volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key。
  • - volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。

     注:Redis的内存淘汰策略的选取并不会影响过期的key的处理。内存淘汰策略用于处理内存不足时的需要申请额外空间的数据;过期策略用于处理过期的缓存数据。

   1.4.LRU、LFU和volatile-ttl都是近似随机算法

     使用下面的参数maxmemory-policy配置淘汰策略:

#配置文件
maxmemory-policy noeviction
 
#命令行
127.0.0.1:6379> config get maxmemory-policy
1) "maxmemory-policy"
2) "noeviction"
127.0.0.1:6379> config set maxmemory-policy allkeys-random
OK
127.0.0.1:6379> config get maxmemory-policy
1) "maxmemory-policy"
2) "allkeys-random"
  •      在缓存的内存淘汰策略中有FIFO、LRU、LFU三种,其中LRU和LFU是Redis在使用的。
  •      FIFO是最简单的淘汰策略,遵循着先进先出的原则,这里简单提一下:

 1.4.1.LRU算法

       LRU(Least Recently Used)表示最近最少使用,该算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。

  • LRU算法的常见实现方式为链表:

    新数据放在链表头部 ,链表中的数据被访问就移动到链头,链表满的时候从链表尾部移出数据。

        而在Redis中使用的是近似LRU算法,为什么说是近似呢?Redis中是随机采样5个(可以修改参数maxmemory-samples配置)key,然后从中选择访问时间最早的key进行淘汰,因此当采样key的数量与Redis库中key的数量越接近,淘汰的规则就越接近LRU算法。但官方推荐5个就足够了,最多不超过10个,越大就越消耗CPU的资源。

       但在LRU算法下,如果一个热点数据最近很少访问,而非热点数据近期访问了,就会误把热点数据淘汰而留下了非热点数据,因此在Redis4.x中新增了LFU算法。

注:在LRU算法下,Redis会为每个key新增一个3字节的内存空间用于存储key的访问时间;


1.4.2.LFU算法

        LFU(Least Frequently Used)表示最不经常使用,它是根据数据的历史访问频率来淘汰数据,其核心思想是“如果数据过去被访问多次,那么将来被访问的频率也更高”。

      解决LRU算法的漏洞:LFU算法反映了一个key的热度情况,不会因LRU算法的偶尔一次被访问被误认为是热点数据。

  • LFU算法的常见实现方式为链表:

       新数据放在链表尾部 ,链表中的数据按照被访问次数降序排列,访问次数相同的按最近访问时间降序排列,链表满的时候从链表尾部移出数据。

1.5.过期删除策略

     前面介绍的LRU和LFU算法都是在Redis内存占用满的情况下的淘汰策略,那么当内存没占满时在Redis中过期的key是如何从内存中删除以达到优化内存占用的呢? 

    在Redis中过期的key不会立刻从内存中删除,而是会同时以下面两种策略进行删除:

  • 惰性删除:当key被访问时检查该key的过期时间,若已过期则删除;已过期未被访问的数据仍保持在内存中,消耗内存资源;
  • 定期删除:每隔一段时间,随机检查设置了过期的key并删除已过期的key;维护定时器消耗CPU资源;

   扫描周期:Redis每10秒进行一次过期扫描:

  • 随机取20个设置了过期策略的key;
  • 检查20个key中过期时间中已过期的key并删除;
  • 如果有超过25%的key已过期则重复第一步;
  • 这种循环随机操作会持续到过期key可能仅占全部key的25%以下时,并且为了保证不会出现循环过多的情况,默认扫描时间不会超过25ms;

1.6.AOF和RDB的过期删除策略

       前面介绍了Redis的持久化策略RDB和AOF,当Redis中的key已过期未删除时,如果进行RDB和AOF的持久化操作时候会怎么操作呢?

  • 在RDB持久化模式中我们可以使用savebgsave命令进行数据持久化操作
  • 在AOF持久化模式中使用rewriteaofbgrewriteaof命令进行持久化操作

   注: 这四个命令都不会将过期key持久化到RDB文件或AOF文件中,可以保证重启服务时不会将过期key载入Redis。

    为了保证一致性,在AOF持久化模式中,当key过期时候,会同时发送DEL命令给AOF文件和所有节点从节点不会主动的删除过期key除非它升级为主节点或收到主节点发来的DEL命令;

二、REDIS的消耗及优化

        2.1.消耗状态

         Redis主要消耗什么物理资源?那自然是内存,大家都知道,内存资源一旦使用完,那么Redis会怎么样呢?

       如果达到设置的上限,Redis的写命令会返回错误信息(但是读命令还可以正常返回)或者你可以配置内存淘汰机制,当Redis达到内存上限时会冲刷掉旧的内容。

         2.2.优化

2.2.1.Redis的内存优化

        利用Hash,list,sorted set,set等集合类型数据,因为通常情况下很多小的Key-Value可以用更紧凑的方式存放到一起。尽可能使用散列表(hashes),散列表(是说散列表里面存储的数少)使用的内存非常小,所以你应该尽可能的将你的数据模型抽象到一个散列表里面。比如你的web系统中有一个用户对象,不要为这个用户的名称,姓氏,邮箱,密码设置单独的key,而是应该把这个用户的所有信息存储到一张散列表里面。

  • redis内存碎片查询
[root@localhost ~]# redis-cli

127.0.0.1:6379> info memory #查看内存使用总量和内存碎片率

# Memory

used_memory:11315280 #内存使用总量

used_memory_human:10.79M

mem_fragmentation_ratio:1.76 #内存碎片率

mem_fragmentation_bytes:8566768
  • 内存碎片率稍大于1是合理的,这个值表示内存碎片率比较低
  • 内存碎片率超过1.5,说明redis消耗了实际需要物理内存的150%,其中50%是内存碎片率
  • 内存碎片率低于1的,说明Redis内存分配超出了物理内存,操作系统正在进行内存交换(内存碎片率稍大于1是最佳,低于1访问速度会慢,高于1.5说明碎片太多)

       注:那么内存使用率超过可用最大内存,redis响应速度会变慢,这个时候操作系统将开始进行内存与swap空间交换,就需要设置内存淘汰策略

2.2.2.避免使用KEYS

  •         keys *, 这个命令是阻塞的,即操作执行期间,其它任何命令在你的实例中都无法执行。可以去使用[SCAN]来代替。
  •        keys指令会导致线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。这个时候可以使用scan指令,scan指令可以无阻塞的提取出指定模式的key列表,但是会有一定的重复概率,在客户端做一次去重就可以了,但是整体所花费的时间会比直接用keys指令长 。

2.2.3.设置 key 有效期

      应该尽可能的利用key有效期。比如一些临时数据(短信校验码),过了有效期Redis就会自动为你清除!

2.2.4.选择回收策略

      当 Redis 的实例空间被填满了之后,将会尝试回收一部分key。根据你的使用方式,强烈建议使用 volatile-lru(默认)策略——前提是你对key已经设置了超时。

2.2.5.限制redis的内存大小

        数据量不可预估,并且内存也有限的话,尽量限制下redis使用的内存大小,这样可以避免redis使用swap分区或者出现OOM错误。使用swap分区,性能较低,如果限制了内存,当到达指定内存之后就不能添加数据了,否则会报OOM错误。可以设置maxmemory-policy,内存不足时删除数据。

2.2.6.部署和场景应用优化

  • 尽可能地使用slot哈希存储,哈希槽(以集群方式部署)。
  • 当业务场景不需要数据持久化时,关闭所有的持久化方式可以获得最佳的性能。

缓存数据库redis之三:内存淘汰策略及优化(代码片段)

目录一、Redis的内存淘汰策略  1.1.概念  1.2.策略一:全局的键空间选择性移除  1.3.策略二:设置过期时间的键空间选择性移除  1.4.LRU、LFU和volatile-ttl都是近似随机算法 1.4.1.LRU算法 1.4.2.LFU算法1.5.过期删除策略1.6.AOF... 查看详情

redis过期删除策略和内存淘汰策略(代码片段)

...3.1.1立即删除3.1.2惰性删除3.1.3定期删除3.3.4总结四、redis缓存淘汰策略4.1有哪些4.2你平时用哪一种五、总结一、面试题生产上你们你们的redis内存设置多少?如何配置、修改redis的内存大小如果内存满了你怎么办redis清理内存的方式&... 查看详情

java从零开始手写redislru缓存淘汰策略详解(代码片段)

前言java从零手写实现redis(一)如何实现固定大小的缓存?java从零手写实现redis(三)redisexpire过期原理java从零手写实现redis(三)内存数据如何重启不丢失?java从零手写实现redis(四)添加监听器java从零手写实现redis(五)过... 查看详情

redis——内存淘汰策略

一、缓存耗尽的原因1、每台机器的内存是一定的2、key未设置过期时间key不设置过期时间则在内存中一直存在,直到我们明确删除它。3、过度或不合理的持久化无论RDB快照或者AOF日志,都会在内存和磁盘中反复操作,需要一定的... 查看详情

你说,redis如何实现键值自动清理?(代码片段)

Redis缓存作为提高系统性能最好的方式相信大家对其一定不陌生,各位秃头老码农不仅需要掌握Redis的基础用法还得了解Redis的相关原理,比如Redis过期策略和内存淘汰机制。大家都知道,Redis缓存使用的是内存资源ÿ... 查看详情

源码讲解redis中内存优化的数据结构是如何设计的(代码片段)

...体嵌入式字符串ziplist设计intset设计共享对象Redis作为内存数据库,如何高效地使用内存非常重要。为了提升内存的使用率,主要采取数据结构优化设计及使用以及内存数据按照规则淘汰。内存数据按照淘汰规则主要通过Re... 查看详情

吃透redis:缓存淘汰篇-lru算法(代码片段)

...行?算法具体如何执行三、总结一、概述redis是内存数据库,当内存使用达到了一定阈值,就会触发缓存淘汰策略,这和Redis配置文件redis.conf中的两个配置参数有关:maxmemory,该配置项设定了Redisserver可以... 查看详情

day750.redis缓存淘汰替换策略:redis是如何工作的-redis核心技术与实战(代码片段)

...Redis缓存使用内存来保存数据,避免业务应用从后端数据库中读取数据,可以提升应用的响应速度。那么,如果把所有要访问的数据都放入缓存,是不是一个很好的设计选择呢?其实,这样做的性价比反而... 查看详情

聊聊redis内存淘汰策略(代码片段)

...edis五种数据结构底层实现》这一期咱们一起来看看Redis的内存淘汰策略~为什么要有内存淘汰机制  大家都知道Redis中的键会设置过期时间,当到达过期时间时会通过一定策略清除对应key,但是redis内存是由上限的,当达到内存上... 查看详情

redis提供6种数据淘汰策略(代码片段)

淘汰策略的原因在redis中,允许用户设置最大使用内存大小server.maxmemory,在内存限定的情况下是很有用的。譬如,在一台8G机子上部署了4个redis服务点,每一个服务点分配1.5G的内存大小,减少内存紧张的情况,由此获取更为稳健... 查看详情

redis中的lru淘汰策略分析(代码片段)

...过期,就返回该键。定期删除:每隔一段时间,程序就对数据库进行一次检查,删除里面的过期键。另外,Redis也可以开启LRU功能来自动淘汰一些键值对。LRU算法当需要从缓存中淘汰数据时,我们希 查看详情

缓存系列之三:redis安装及基本数据类型命令使用

一:Redis是一个开源的key-value存储系统。与Memcached类似,Redis将大部分数据存储在内存中,支持的数据类型包括:字符串、哈希表、链表、集合、有序集合以及基于这些数据类型的相关操作。Redis使用C语言开发,在大多数像Linux、... 查看详情

redis高级:数据删除与淘汰策略,主从复制,哨兵模式,集群以及企业级解决方案(代码片段)

...汰策略1.1过期数据1.1.1Redis中的数据特征Redis是一种内存级数据库,所有数据均存放在内存中,内存中的数据可以通过TTL指令获取其状态TTL返回的值有三种情况:正数,-1,-2正数:代表该数据 查看详情

吃透redis:缓存淘汰篇-lru算法(代码片段)

...行?算法具体如何执行三、总结一、概述redis是内存数据库,当内存使用达到了一定阈值,就会触发缓存淘汰策略,这和Redis配置文件redis.conf中的两个配置 查看详情

吃透redis:缓存淘汰篇-lru算法(代码片段)

...行?算法具体如何执行三、总结一、概述redis是内存数据库,当内存使用达到了一定阈值,就会触发缓存淘汰策略,这和Redis配置文件redis.conf中的两个配置 查看详情

redis之缓存穿透击穿雪崩问题与缓存删除淘汰策略(代码片段)

一、缓存问题与解决缓存穿透缓存穿透是指查询缓存和DB中都不存在的数据。缓存穿透示例:publicStationfindProjectStation(LongstationId)//从缓存中查询Stationstation=(Station)redisTemplate.boundHashOps("project_station").get(stationId);if(station==null)// 查看详情

redis之缓存穿透击穿雪崩问题与缓存删除淘汰策略(代码片段)

一、缓存问题与解决缓存穿透缓存穿透是指查询缓存和DB中都不存在的数据。缓存穿透示例:publicStationfindProjectStation(LongstationId)//从缓存中查询Stationstation=(Station)redisTemplate.boundHashOps("project_station").get(stationId);if(station==null)// 查看详情

redis源码六-redis中的缓存淘汰策略处理分析(代码片段)

...redis的过期策略。这次我来探究一下。我们都知道redis的缓存淘汰策略有以下几种:noeviction无过期策略,内存满了就直接异常volatile-lru对有过期时间的key进行lru淘汰(越长时间没有被访问,越容易被淘汰)allkeys-lru... 查看详情