广告
返回顶部
首页 > 资讯 > 数据库 >深入理解Redis内存淘汰策略
  • 245
分享到

深入理解Redis内存淘汰策略

Redis内存淘汰 2022-07-05 12:07:52 245人浏览 独家记忆
摘要

目录一、内存回收二、设置内存三、内存淘汰策略四、LRU4.1 LRU算法4.2 Redis中的LRU算法五、LFU一、内存回收 长时间不使用的缓存 降低io性能物理内存不够 很多人了解了Redis的好处之后,于是把任何数

一、内存回收

长时间不使用的缓存

  • 降低io性能
  • 物理内存不够

很多人了解了Redis的好处之后,于是把任何数据都往Redis中放,如果使用不合理很容易导致数据超过Redis的内存,这种情况会出现什么问题呢?

  • Redis中有很多无效的缓存,这些缓存数据会降低数据IO的性能,因为不同的数据类型时间复杂度算法不同,数据越多可能会造成性能下降
  • 随着系统的运行,redis的数据越来越多,会导致物理内存不足。通过使用虚拟内存(VM),将很少访问的数据交换到磁盘上,腾出内存空间的方法来解决物理内存不足的情况。虽然能够解决物理内存不足导致的问题,但是由于这部分数据是存储在磁盘上,如果在高并发场景中,频繁访问虚拟内存空间会严重降低系统性能。

所以遇到这类问题的时候,我们一般有几种方法。

  • 对每个存储到redis中的key设置过期时间,这个根据实际业务场景来决定。否则,再大的内存都会随着系统运行被消耗完
  • 增加内存
  • 使用内存淘汰策略

二、设置内存

在实际生产环境中,服务器不仅仅只有Redis,为了避免Redis内存使用过多对其他程序造成影响,我们一般会设置最大内存。Redis默认的最大内存 maxmemory=0 ,表示不限制Redis内存的使用。我们可以修改 redis.conf 文件,设置Redis最大使用的内存。

# 单位为byte
maxmemory <bytes> 2147483648(2G)

如何查看当前Redis最大内存设置呢,进入到Redis-Cli控制台,输入下面这个命令。

config get maxmemory

当Redis中存储的内存超过maxmemory时,会怎么样呢?下面我们做一个实验

在redis-cli控制台输入下面这个命令,把最大内存设置为1个字节。

config set maxmemory 1

通过下面的命令存储一个string类型的数据

set name mvp

此时,控制台会得到下面这个错误信息

(error) OOM command not allowed when used memory > 'maxmemory'.

三、内存淘汰策略

设置了maxmemory的选项,redis内存使用达到上限。可以通过设置LRU算法来删除部分key,释放空间。默认是按照过期时间的,如果set时候没有加上过期时间就会导致数据写满maxmemory。Redis中提供了一种内存淘汰策略,当内存不足时,Redis会根据相应的淘汰规则对key数据进行淘汰。Redis一共提供了8种淘汰策略,默认的策略为noeviction,当内存使用达到阈值的时候,所有引起申请内存的命令会都会报错。

  • volatile-lru,针对设置了过期时间的key,使用lru算法进行淘汰。
  • allkeys-lru,针对所有key使用lru算法进行淘汰。
  • volatile-lfu,针对设置了过期时间的key,使用lfu算法进行淘汰。
  • allkeys-lfu,针对所有key使用lfu算法进行淘汰。
  • volatile-random,从所有设置了过期时间的key中使用随机淘汰的方式进行淘汰。
  • allkeys-random,针对所有的key使用随机淘汰机制进行淘汰。
  • volatile-ttl,针对设置了过期时间的key,越早过期的越先被淘汰。
  • noeviction,不会淘汰任何数据,当使用的内存空间超过 maxmemory 值时,再有写请求来时返回错误。

前缀为volatile-和allkeys-的区别在于二者选择要清除的键时的字典不同,volatile-前缀的策略代表从redisDb中的expire字典中选择键进行清除;allkeys-开头的策略代表从dict字典中选择键进行清除。
内存淘汰算法的具体工作原理是:

  • 客户端执行一条新命令,导致数据库需要增加数据(比如set key value)
  • Redis会检查内存使用情况,如果内存使用超过 maxmemory,就会按照内存淘汰策略删除一些 key
  • 新的命令执行成功

四、LRU

4.1 LRU算法

LRU是Least Recently Used的缩写,也就是表示最近很少使用,也可以理解成最久没有使用。也就是说当内存不够的时候,每次添加一条数据,都需要抛弃一条最久时间没有使用的旧数据。标准的LRU算法为了降低查找和删除元素的时间复杂度,一般采用Hash表和双向链表结合的数据结构,hash表可以赋予链表快速查找到某个key是否存在链表中,同时可以快速删除、添加节点,如下图所示。

深入理解Redis内存淘汰策略


双向链表的查找时间复杂度是O(n),删除和插入是O(1),借助HashMap结构,可以使得查找的时间复杂度变成O(1)。
Hash表用来查询在链表中的数据位置,链表负责数据的插入,当新数据插入到链表头部时有两种情况。

  • 链表满了,把链表尾部的数据丢弃掉,新加入的缓存直接加入到链表头中。
  • 当链表中的某个缓存被命中时,直接把数据移到链表头部,原本在头节点的缓存就向链表尾部移动。

这样,经过多次Cache操作之后,最近被命中的缓存,都会存在链表头部的方向,没有命中的,都会在链表尾部方向,当需要替换内容时,由于链表尾部是最少被命中的,我们只需要淘汰链表尾部的数据即可。
java代码实现简单的LRU算法

import java.util.HashMap;

public class LRUCache {

    private node head;
        private Node tail;

        private final HashMap<String,Node> nodeHashMap;
        private int capacity; //容量

    public LRUCache(int capacity) {
        this.capacity = capacity;
        nodeHashMap=new HashMap<>();
        tail=new Node();
        head=new Node();
        head.next=tail;
        tail.prev=head;
    }

    //移除节点
    private void removeNode(Node node){
        if(node==tail){
            tail=tail.prev;
            tail.next=null;
        }else if(node==head){
            head=head.next;
            head.prev=null;
        }else{
            node.prev.next=node.next;
            node.next.prev=node.prev;
        }
    }
    private void addNodeToHead(Node node){
        node.next=head.next;
        head.next.prev=node;
        node.prev=head;
        head.next=node;
    }

    private void moveNodeToHead(Node node){
        removeNode(node);
        addNodeToHead(node);
    }
    public String get(String key){
        Node node=nodeHashMap.get(key);
        if(node==null){
            return null;
        }
        //刷新当前key的位置
        moveNodeToHead(node);
        return node.value;
    }
    public void put(String key,String value){
        Node node=nodeHashMap.get(key);
        if(node==null){ //如果不存在,则添加到链表
            if(nodeHashMap.size()>=capacity){ //大于容量,则需要移除老的数据
                removeNode(tail); //移除尾部节点(tail节点是属于要被淘汰数据)
                nodeHashMap.remove(tail.key); //从hashmap中移除
            }
            node=new Node(key,value);
            nodeHashMap.put(key,node);
            addNodeToHead(node);
        }else{
            node.value=value;
            moveNodeToHead(node);
        }
    }

    class Node{
        private String key;
        private String value;
        Node prev;
        Node next;

        public Node(){}

        public Node(String key,String value){
            this.key=key;
            this.value=value;
        }
    }
}

4.2 redis中的LRU算法

实际上,Redis使用的LRU算法其实是一种不可靠的LRU算法,它实际淘汰的键并不一定是真正最少使用的数据,它的工作机制是:

  • 随机采集淘汰的key,每次随机选出5个key
  • 然后淘汰这5个key中最少使用的key

这5个key是默认的个数,具体的数值可以在redis.conf中配置

maxmemory-samples 5

当近似LRU算法取值越大的时候就会越接近真实的LRU算法,因为取值越大获取的数据越完整,淘汰中的数据就更加接近最少使用的数据。这里其实涉及一个权衡问题,如果需要在所有的数据中搜索最符合条件的数据,那么一定会增加系统的开销,Redis是单线程的,所以耗时的操作会谨慎一些。为了在一定成本内实现相对的LRU,早期的Redis版本是基于采样的LRU,也就是放弃了从所有数据中搜索解改为采样空间搜索最优解。Redis3.0版本之后,Redis作者对于基于采样的LRU进行了一些优化

  • Redis中维护一个大小为16的候选池,当第一次随机选取采用数据时,会把数据放入到候选池中,并且候选池中的数据会根据key的空闲时间进行排序
  • 当第二次以后选取数据时,只有大于候选池内最小空闲时间的key才会被放进候选池。
  • 当候选池的数据满了之后,那么空闲时间最大的key就会被挤出候选池。当执行淘汰时,直接从候选池中选取空闲时间最大的key进行淘汰。

如下图所示,首先从目标字典中采集出maxmemory-samples个键,缓存在一个samples数组中,然后从samples数组中一个个取出来,和回收池中的键进行键的空闲时间比较,从而更新回收池。在更新过程中,首先利用遍历找到的每个键的实际插入位置x,然后根据不同情况进行处理。

深入理解Redis内存淘汰策略

  • 回收池满了,并且当前插入的key的空闲时间最小(也就是回收池中的所有key都比当前插入的key的空闲时间都要大),则不作任何操作。
  • 回收池未满,并且插入的位置x没有键,则直接插入即可
  • 回收池未满,且插入的位置x原本已经存在要淘汰的键,则把第x个以后的元素都往后挪一个位置,然后再执行插入操作。
  • 回收池满了,将当前第x个以前的元素往前挪一个位置(实际就是淘汰了),然后执行插入操作。

这样做的目的是能够选出最真实的最少被访问的key,能够正确选择不常使用的key。因为在Redis3.0之前是随机选取样本,这样的方式很有可能不是真正意义上的最少访问的key。LRU算法有一个弊端,假如一个key值访问频率很低,但是最近一次被访问到了,那LRU会认为它是热点数据,不会被淘汰。同样,经常被访问的数据,最近一段时间没有被访问,这样会导致这些数据被淘汰掉,导致误判而淘汰掉热点数据,于是在Redis 4.0中,新加了一种LFU算法。

五、LFU

LFU(Least Frequently Used),表示最近最少使用,它和key的使用次数有关,其思想是:根据key最近被访问的频率进行淘汰,比较少访问的key优先淘汰,反之则保留。LFU的原理是使用计数器来对key进行排序,每次key被访问时,计数器会增大,当计数器越大,意味着当前key的访问越频繁,也就是意味着它是热点数据。 它很好的解决了LRU算法的缺陷:一个很久没有被访问的key,偶尔被访问一次,导致被误认为是热点数据的问题。LFU的实现原理如下图所示,LFU维护了两个链表,横向组成的链表用来存储访问频率,每个访问频率的节点下存储另外一个具有相同访问频率的缓存数据。具体的工作原理是:

  • 当添加元素时,找到相同访问频次的节点,然后添加到该节点的数据链表的头部。如果该数据链表满了,则移除链表尾部的节点
  • 当获取元素或者修改元素时,都会增加对应key的访问频次,并把当前节点移动到下一个频次节点

添加元素时,访问频率默认为1,随着访问次数的增加,频率不断递增。而当前被访问的元素也会随着频率增加进行移动。

深入理解Redis内存淘汰策略

 到此这篇关于深入理解Redis内存淘汰策略的文章就介绍到这了,更多相关Redis内存淘汰内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

您可能感兴趣的文档:

--结束END--

本文标题: 深入理解Redis内存淘汰策略

本文链接: https://www.lsjlt.com/news/33201.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 深入理解Redis内存淘汰策略
    目录一、内存回收二、设置内存三、内存淘汰策略四、LRU4.1 LRU算法4.2 redis中的LRU算法五、LFU一、内存回收 长时间不使用的缓存 降低IO性能物理内存不够 很多人了解了Redis的好处之后,于是把任何数...
    99+
    2022-07-05
    Redis内存淘汰
  • Redis过期键与内存淘汰策略深入分析讲解
    目录一、Redis数据库的组织方式1.1 redisServer结构定义1.2 redisDb 结构定义1.3 redisdb初始化二、过期键2.1 设置键的过期时间2.2 过期键的判定2.3 过期键的删除策略2.3.1...
    99+
    2022-11-28
    Redis过期键 Redis内存淘汰策略
  • Redis的过期策略和内存淘汰策略
    文章前言 提到内存管理,我们就需要考虑Redis的内存过期策略和内存淘汰机制。该文章便从这两方面入手,分享一些在Redis内存方面相关的基础知识。 文章中使用的示例版本为Redis5.0版本。 内存过期策略 内存过期策略主要的...
    99+
    2020-12-25
    Redis的过期策略和内存淘汰策略
  • 关于Redis的内存淘汰策略详解
    目录一、什么是内存淘汰?二、Redis 内存上限三、Redis 内存淘汰策略四、内存淘汰的具体工作步骤五、LRU 算法及在 Redis 中的改进5.1 LRU 算法5.2 Redis 中的 LRU 算法六、LFU一、什么...
    99+
    2023-05-19
    Redis 策略 Redis 内存淘汰
  • Redis中LRU淘汰策略的深入分析
    前言 Redis作为缓存使用时,一些场景下要考虑内存的空间消耗问题。Redis会删除过期键以释放空间,过期键的删除策略有两种: 惰性删除:每次从键空间中获取键时,都检查取得的键是否过期,如果过期的话,...
    99+
    2022-10-18
  • Redis过期删除策略与内存淘汰策略
    目录过期删除策略设置Redis中key的过期时间 (单位:秒)常见的三种过期删除策略Redis使用用的过期删除策略Redis的定期删除的流程内存淘汰策略设置Redis最大运行内存Redis 内存淘汰策略有哪些?LRU 算...
    99+
    2022-09-02
  • Redis中如何使用内存淘汰策略
    Redis中如何使用内存淘汰策略,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。Redis配置内存1、通过配置文件配置 通过在R...
    99+
    2022-10-18
  • Redis深入了解内存淘汰与事务操作
    目录Redis内存淘汰策略六种淘汰策略Redis中的自动过期机制Redis中的事务操作watch和Multi的区别Redis内存淘汰策略 为什么要有淘汰策略? 答:将Redis用作缓存时,Redis数据存在内存中,如果内...
    99+
    2022-07-28
    Redis内存淘汰 Redis事务操作
  • Redis 过期删除策略和内存淘汰机制
          Redis 设置过期时间 Redis 有四个不同的命令可以用于设置键的生存时间(键可以存在多久)或过期时间(键什么时候会被删除): EXPIRE ——将键 key 的生存时间设置为 ttl 秒。 PEXPIRE ——...
    99+
    2015-02-08
    Redis 过期删除策略和内存淘汰机制
  • Redis 的内存淘汰策略和过期删除策略的区别
    目录前言过期删除策略如何设置过期时间?如何判定 key 已过期了?过期删除策略有哪些?Redis 过期删除策略是什么?内存淘汰策略如何设置 Redis 最大运行内存?Redis 内存淘汰策略有哪些?LRU 算法和 LFU...
    99+
    2022-07-04
    Redis 内存淘汰策略 Redis 过期删除策略
  • Redis 的内存淘汰策略和过期删除策略的区别
    目录前言过期删除策略如何设置过期时间?如何判定 key 已过期了?过期删除策略有哪些?Redis 过期删除策略是什么?内存淘汰策略如何设置 Redis 最大运行内存?Redis 内存...
    99+
    2022-11-13
  • Redis缓存的淘汰策略是什么
    这篇文章主要讲解了“Redis缓存的淘汰策略是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Redis缓存的淘汰策略是什么”吧!Redis(Remote...
    99+
    2022-10-18
  • 浅谈Redis中的内存淘汰策略和过期键删除策略
    目录8种淘汰策略过期键的删除策略总结 redis是我们现在最常用的一个工具,帮助我们建设系统的高可用,高性能。 而且我们都知道redis是一个完全基于内存的工具,这也是redis速...
    99+
    2022-11-12
  • Redis缓存中的淘汰策略有哪些
    本篇内容主要讲解“Redis缓存中的淘汰策略有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Redis缓存中的淘汰策略有哪些”吧!我们知道Redis缓存使用...
    99+
    2022-10-18
  • 浅谈Redis缓存有哪些淘汰策略
    目录Redis过期策略 定时删除 惰性删除 定期删除 Redis的内存淘汰机制 LRU和LFU的区别 LRU LFU Redis重启如何恢复数据呢? 总结Redis过期策略 我们首...
    99+
    2022-11-12
  • Redis的过期策略和内存淘汰策略最全总结与分析
    文章前言 提到内存管理,我们就需要考虑Redis的内存过期策略和内存淘汰机制。该文章便从这两方面入手,分享一些在Redis内存方面相关的基础知识。 文章中使用的示例版本为Redis5.0版本。 内存过期策略 内存过期策略主要的作用就是,...
    99+
    2016-07-21
    Redis的过期策略和内存淘汰策略最全总结与分析
  • Redis的内存淘汰策略和过期删除策略有什么区别
    本文小编为大家详细介绍“Redis的内存淘汰策略和过期删除策略有什么区别”,内容详细,步骤清晰,细节处理妥当,希望这篇“Redis的内存淘汰策略和过期删除策略有什么区别”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧...
    99+
    2023-07-02
  • redis 的 maxmemory 配置以及 缓存淘汰策略
    1. maxmemory 相关介绍 maxmemory 的作用 设置 redis 可用内存的上限。 maxmemory 的配置 将 maxmemory 设置为零将导致没有内存限制。这是 64 位系统的默认行为,而32位系统使用 3G...
    99+
    2015-05-05
    redis maxmemory 配置以及 缓存淘汰策略
  • Redis的内存淘汰策略和过期删除策略的区别是什么
    这篇文章主要介绍“Redis的内存淘汰策略和过期删除策略的区别是什么”,在日常操作中,相信很多人在Redis的内存淘汰策略和过期删除策略的区别是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方...
    99+
    2022-10-19
  • redis缓存中怎么实施数据淘汰策略
    这篇文章将为大家详细讲解有关redis缓存中怎么实施数据淘汰策略,文章内容质量较高,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。在 redis 中,允许用户设置最大使用内存大小通过配置re...
    99+
    2022-10-18
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作