• Redis中的内存淘汰策略和过期删除策略


    Redis的内存淘汰策略
    长时间不使用的缓存
    降低IO性能
    物理内存不够
    其实在Redis中是可以设置内存最大限制的,因此我们不用担心Redis占满机器的内存影响其他服务,这个参数maxmemory是可以配置的:
    127.0.0.1:6379> config set maxmemory 1GB

    maxmemory参数默认值为0。我们在使用redis 最好根据实际情况设置其内存大小。放在。redis占用太多内存,导致其他程序不可用。

    内存淘汰策略
    Redis中共有下面八种内存淘汰策略:

    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:默认策略,当内存达到设置的最大值时,所有申请内存的操作都会报错(如set,lpush等),只读操作如get命令可以正常执行;

    内存淘汰算法的具体工作原理是:
    客户端执行一条新命令,导致数据库需要增加数据(比如set key value)
    Redis会检查内存使用,如果内存使用超过 maxmemory,就会按照置换策略删除一些 key
    新的命令执行成功
    了解LRU算法
    LRU是Least Recently Used的缩写,也就是表示最近很少使用,也可以理解成最久没有使用。也就是说
    当内存不够的时候,每次添加一条数据,都需要抛弃一条最久时间没有使用的旧数据。
    标准的LRU算法为了降低查找和删除元素的时间复杂度,一般采用Hash表和双向链表结合的数据结构,
    hash表可以赋予链表快速查找到某个key是否存在链表中,同时可以快速删除、添加节点,如图4-21所
    示。
    双向链表的查找时间复杂度是O(n),删除和插入是O(1),借助HashMap结构,可以使得查找的时
    间复杂度变成O(1)
     
    
    
    Hash表用来查询在链表中的数据位置,链表负责数据的插入,当新数据插入到链表头部时有两种情况。
    链表满了,把链表尾部的数据丢弃掉,新加入的缓存直接加入到链表头中。
    当链表中的某个缓存被命中时,直接把数据移到链表头部,原本在头节点的缓存就向链表尾部移动

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

    Redis中的LRU算法
    实际上,Redis使用的LRU算法其实是一种不可靠的LRU算法,它实际淘汰的键并不一定是真正最少使用
    的数据,它的工作机制是:
    随机采集淘汰的key,每次随机选出5个key(官方推荐5个就足够了,最多不超过10个,越大就越消耗CPU的资源)
    然后淘汰这5个key中最少使用的key
    这5个key是默认的个数,具体的数值可以在redis.conf中配置
    maxmemory-samples 5
    当近似LRU算法取值越大的时候就会越接近真实的LRU算法,因为取值越大获取的数据越完整,淘汰中
    的数据就更加接近最少使用的数据。这里其实涉及一个权衡问题,
    如果需要在所有的数据中搜索最符合条件的数据,那么一定会增加系统的开销,Redis是单线程的,所
    以耗时的操作会谨慎一些。
    为了在一定成本内实现相对的LRU,早期的Redis版本是基于采样的LRU,也就是放弃了从所有数据中搜
    索解改为采样空间搜索最优解。Redis3.0版本之后,Redis作者对于基于采样的LRU进行了一些优化:
    Redis中维护一个大小为16的候选池,当第一次随机选取采用数据时,会把数据放入到候选池中,
    并且候选池中的数据会更具时间进行排序。
    当第二次以后选取数据时,只有小于候选池内最小时间的才会被放进候选池。
    当候选池的数据满了之后,那么时间最大的key就会被挤出候选池。当执行淘汰时,直接从候选池
    中选取最近访问时间小的key进行淘汰。
    LFU算法
    LFU(Least Frequently Used),表示最近最少使用,它和key的使用次数有关,其思想是:根据key最
    近被访问的频率进行淘汰,比较少访问的key优先淘汰,反之则保留。
    LRU的原理是使用计数器来对key进行排序,每次key被访问时,计数器会增大,当计数器越大,意味着
    当前key的访问越频繁,也就是意味着它是热点数据。 它很好的解决了LRU算法的缺陷:一个很久没有
    被访问的key,偶尔被访问一次,导致被误认为是热点数据的问题。
    LFU的实现原理如图4-23所示,LFU维护了两个链表,横向组成的链表用来存储访问频率,每个访问频
    率的节点下存储另外一个具有相同访问频率的缓存数据。具体的工作原理是:
    当添加元素时,找到相同访问频次的节点,然后添加到该节点的数据链表的头部。如果该数据链表
    满了,则移除链表尾部的节点
    当获取元素或者修改元素是,都会增加对应key的访问频次,并把当前节点移动到下一个频次节
    点。
    添加元素时,访问频率默认为1,随着访问次数的增加,频率不断递增。而当前被访问的元素也会
    随着频率增加进行移动。
     

    TTL淘汰

    Redis 数据集数据结构中保存了键值对过期时间的表,即 redisDb.expires。与 LRU 数据淘汰机制类似,
    TTL 数据淘汰机制中会先从过期时间的表中随机挑选几个键值对,取出其中 ttl ***的键值对淘汰。同样,
    TTL淘汰策略并不是面向所有过期时间的表中最快过期的键值对,而只是随机挑选的几个键值对。

    过期删除策略

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

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

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

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

    1.随机取20个设置了过期策略的key;
    2.检查20个key中过期时间中已过期的key并删除;
    3.如果有超过25%的key已过期则重复第一步;

    这种循环随机操作会持续到过期key可能仅占全部key的25%以下时,并且为了保证不会出现循环过多的情况,默认扫描时间不会超过25ms;

    AOF和RDB的过期删除策略

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

    在RDB持久化模式中我们可以使用save和bgsave命令进行数据持久化操作
    在AOF持久化模式中使用rewriteaof和bgrewriteaof命令进行持久化操作

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

    为了保证一致性,在AOF持久化模式中,当key过期时候,会同时发送DEL命令给AOF文件和所有节点;
    
    从节点不会主动的删除过期key除非它升级为主节点或收到主节点发来的DEL命令;
  • 相关阅读:
    namespace for c++
    [爬虫]Python爬虫基础
    为什么局域网IP是192.168开头?
    [Python基础]Python中remove,del和pop的区别
    权限控制(delphi actionlist)
    Delphi ActionList详解
    充分利用HTML标签元素 – 简单的xtyle前端框架
    好用的侧边栏菜单/面板jQuery插件
    最新的手机/移动设备jQuery插件
    有用的jQuery布局插件推荐
  • 原文地址:https://www.cnblogs.com/xiaowangbangzhu/p/16159367.html
Copyright © 2020-2023  润新知