热门标签 | HotTags
当前位置:  开发笔记 > 后端 > 正文

redis内存回收,过期策略,LRU

一、内存回收机制redis并不总是将空闲内存立即归还给操作系统例如:当前内存10G,删除里1G的key后,你会发现内存并没有变化因为操作系统是以页为单位回收内存的,这个页上只要有一

一、内存回收机制

redis并不总是将空闲内存立即归还给操作系统

例如:当前内存10G,删除里1G的key后,你会发现内存并没有变化

因为操作系统是以页为单位回收内存的,这个页上只要有一个key在使用,那么他就不能被回收。

如果执行flushdb,再去观察内存,会发现内存确实被回收了,因为所有的key被干掉了,内存被回收了

通过第三方库进行管理内存:jemalloc


二、过期策略

概述:redis所有的数据结构都可以设置过期时间,时间一到,就会自动删除。


1.问题:同一时间,过多key过期,占用线程处理时间,导致线程读写卡顿,redis如何处理这个问题的?

设置了过期时间的key,单独放入一个字典中。

定时策略 + 惰性策略

(1).定时扫描策略(集中处理)

redis默认每秒扫描10次(每次约100ms),过期扫描,不会扫描全部过期的key,而是采用贪心策略:



  • 从过期字典中,随机挑选20个key

  • 删除这20个key中已经过期的key

  • 如果过期的key超过25%,那就重复步骤1

(2).惰性删除(零散处理)

在客户端访问这个key时,redis对key的过期时间进行检查,如果过期了就立即删除。


2.问题:如果所有的key在同一时间过期,会有怎样的结果?

导致读写请求出现卡顿。

原因:一、过期扫描时,出现循环过度,导致卡顿;

二、频繁回收内存页,产生cpu消耗


3.怎么做?

过期时间随机化。在过期时间设置一个范围,不能同一时间过期。


4.从节点的过期策略

从节点不会进行定时扫描,从节点的处理是被动的

主节点在key到期时,在AOF中会增加一条del指令,同步到所有从节点,从节点通过执行指令来删除过期key


5.惰性删除

删除指令,del会直接释放对象的内存,这个指令非常快,没有明显的延迟。

如果被删除的key是一个非常大的对象,比如包含了上千万个元素的hash,就不能通过del指令了,否则会造成卡顿

解决:4.0版本,引入了unlink指令,它能对删除操作进行懒处理,丢给后台进程来异步回收内存。


三、LRU

Redis配置中和LRU有关的有三个:



  • maxmemory: 配置Redis存储数据时指定限制的内存大小,比如100m。当缓存消耗的内存超过这个数值时, 将触发数据淘汰。该数据配置为0时,表示缓存的数据量没有限制, 即LRU功能不生效。64位的系统默认值为0,32位的系统默认内存限制为3GB

  • maxmemory_policy: 触发数据淘汰后的淘汰策略

  • maxmemory_samples: 随机采样的精度,也就是随即取出key的数目。该数值配置越大, 越接近于真实的LRU算法,但是数值越大,相应消耗也变高,对性能有一定影响,样本值默认为5。


可选策略



  • noeviction:如果缓存数据超过了maxmemory限定值,并且客户端正在执行的命令(大部分的写入指令,但DEL和几个指令例外)会导致内存分配,则向客户端返回错误响应

  • allkeys-lru: 对所有的键都采取LRU淘汰

  • volatile-lru: 仅对设置了过期时间的键采取LRU淘汰

  • allkeys-random: 随机回收所有的键

  • volatile-random: 随机回收设置过期时间的键

  • volatile-ttl: 仅淘汰设置了过期时间的键---淘汰生存时间TTL(Time To Live)更小的键

volatile-lru, volatile-random和volatile-ttl这三个淘汰策略使用的不是全量数据,有可能无法淘汰出足够的内存空间。在没有过期键或者没有设置超时属性的键的情况下,这三种策略和noeviction差不多。

一般的经验规则:



  • 使用allkeys-lru策略:当预期请求符合一个幂次分布(二八法则等),比如一部分的子集元素比其它其它元素被访问的更多时,可以选择这个策略。

  • 使用allkeys-random:循环连续的访问所有的键时,或者预期请求分布平均(所有元素被访问的概率都差不多)

  • 使用volatile-ttl:要采取这个策略,缓存对象的TTL值最好有差异


LRU算法

最常见的实现是使用一个链表保存缓存数据,详细算法实现如下:

image



  1. 新数据插入到链表头部;

  2. 每当缓存命中(即缓存数据被访问),则将数据移到链表头部;

  3. 当链表满的时候,将链表尾部的数据丢弃。

    分析

    【命中率】

    当存在热点数据时,LRU的效率很好,但偶发性的、周期性的批量操作会导致LRU命中率急剧下降,缓存污染情况比较严重。

    【复杂度】

    实现简单。

    【代价】

    命中时需要遍历链表,找到命中的数据块索引,然后需要将数据移到头部。


近似LRU算法

随机获取5个key,淘汰掉最旧的key,判断内存是否超出maxmemory,若超出,则继续循环

redis3.0以后,新增了淘汰池(一个数组)

每一次淘汰循环中,新的随机得出的key列表会和淘汰池的key列表进行融合,淘汰掉最旧的一个key,保留剩余的数据存在淘汰池中,等待下一次循环淘汰



推荐阅读
  • 基于Node.js的高性能实时消息推送系统通过集成Socket.IO和Express框架,实现了高效的高并发消息转发功能。该系统能够支持大量用户同时在线,并确保消息的实时性和可靠性,适用于需要即时通信的应用场景。 ... [详细]
  • 数据结构与算法:HyperLogLog 统计、布隆过滤器应用、缓存机制挑战及解决方案、Redis 性能优化与监控、哨兵模式、版本控制工具 Git
    本文探讨了数据结构与算法在实际应用中的多个方面。首先介绍了HyperLogLog算法,用于高效地进行基数统计,能够准确估算大规模数据集中的唯一元素数量。接着讨论了布隆过滤器的应用,该过滤器在空间效率和查询速度上具有显著优势,适用于大数据场景下的快速成员检测。此外,文章分析了缓存机制面临的挑战及其解决方案,包括LRU和LFU等策略,并详细阐述了Redis的性能优化与监控方法,如使用哨兵模式实现高可用性。最后,介绍了版本控制工具Git的基本操作和最佳实践,帮助开发者有效管理代码版本。 ... [详细]
  • Jedis接口分类详解与应用指南
    本文详细解析了Jedis接口的分类及其应用指南,重点介绍了字符串数据类型(String)的接口功能。作为Redis中最基本的数据存储形式,字符串类型支持多种操作,如设置、获取和更新键值对等,适用于广泛的应用场景。 ... [详细]
  • 本章节在上一章的基础上,深入探讨了如何通过引入机器人实现自动聊天、表情包回应以及Adidas官方账号的自动抽签功能。具体介绍了使用wxpy库进行微信机器人的开发,优化了智能回复系统的性能和用户体验。通过详细的代码示例和实践操作,展示了如何实现这些高级功能,进一步提升了机器人的智能化水平。 ... [详细]
  • 在 Angular Google Maps 中实现图片嵌入信息窗口的功能,可以通过使用 `@agm/core` 库来实现。该库提供了丰富的 API 和组件,使得开发者可以轻松地在地图上的信息窗口中嵌入图片。本文将详细介绍如何配置和使用这些组件,以实现动态加载和显示图片的功能。此外,还将探讨一些常见的问题和解决方案,帮助开发者更好地集成这一功能。 ... [详细]
  • MySQL索引详解及其优化策略
    本文详细解析了MySQL索引的概念、数据结构及管理方法,并探讨了如何正确使用索引以提升查询性能。文章还深入讲解了联合索引与覆盖索引的应用场景,以及它们在优化数据库性能中的重要作用。此外,通过实例分析,进一步阐述了索引在高读写比系统中的必要性和优势。 ... [详细]
  • 本文详细介绍了在 SQL Server 2005 中优化和实现分页存储过程的方法。通过创建一个名为 `[dbo].[GetUsers]` 的存储过程,该过程接受两个参数:`@RowIndex`(当前指定的页数)和 `@RecordCount`(每页显示的记录数)。文章不仅提供了具体的代码示例,还深入探讨了性能优化技巧,包括索引使用和查询优化策略,以提高分页查询的效率和响应速度。 ... [详细]
  • 在 Python 中,列表(list)是一种内置的数据类型,属于有序且可变的集合,支持随时添加或删除元素。此外,Python 还提供了多种独特的数据结构,如字典(dict)、集合(set)和元组(tuple),每种数据结构都有其特定的应用场景和优势。了解这些数值类型和数据结构对于高效编程至关重要。 ... [详细]
  • 本文深入解析了Python在处理HTML过滤时的实现方法及其应用场景。通过具体实例,详细介绍了如何利用Python代码去除HTML字符串中的标签和其他无关信息,确保内容的纯净与安全。此外,文章还探讨了该技术在网页抓取、数据清洗等领域的实际应用,为开发者提供了宝贵的参考。 ... [详细]
  • 投融资周报 | Circle 达成 4 亿美元融资协议,唯一艺术平台 A 轮融资超千万美元 ... [详细]
  • 本文全面解析了 gRPC 的基础知识与高级应用,从 helloworld.proto 文件入手,详细阐述了如何定义服务接口。例如,`Greeter` 服务中的 `SayHello` 方法,该方法在客户端和服务器端的消息交互中起到了关键作用。通过实例代码,读者可以深入了解 gRPC 的工作原理及其在实际项目中的应用。 ... [详细]
  • 在MFC框架中,存在多个全局函数,用于在不同对象间获取信息或创建新对象。其中,`afxGetApp`函数尤为关键,它能够帮助开发者轻松获取当前应用程序的实例指针。本文将详细解析`afxGetApp`函数的内部机制及其在MFC应用程序中的具体应用场景,探讨其在提升代码可维护性和灵活性方面的优势。此外,还将介绍其他常用全局函数如`AfxWinInit()`和`AfxBeginThread()`的功能和使用方法,为开发者提供全面的参考。 ... [详细]
  • FastDFS Nginx 扩展模块的源代码解析与技术剖析
    FastDFS Nginx 扩展模块的源代码解析与技术剖析 ... [详细]
  • 本文作为探讨PHP依赖注入容器系列文章的开篇,将首先通过具体示例详细阐述依赖注入的基本概念及其重要性,为后续深入解析容器的实现奠定基础。 ... [详细]
  • 字节跳动深圳研发中心安全业务团队正在火热招募人才! ... [详细]
author-avatar
手机用户2602890925
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有