当前位置: 首页 > news >正文

Redis淘汰策略与持久化

淘汰策略

        我们知道Redis是内存数据库,而内存虽然存取速度快,但他不比磁盘有大量的存储空间,如果我们不制定键值淘汰策略,当使用到达最大内存时就无法继续设置新的键。在Redis中可以使用expire命令指定key的存活时长,到期会自动释放,但仅有此法是不够的,因为我们不知道在过期时间内会有多少个key被创建,这样治标不治本。常见的淘汰策略如下:

  • 淘汰过期key,LRU(最长时间没有使用)、LFU(最少次数使用)、TTL(最近要过期)、RANDOM(随机)。
  • 所有key,LRU、LFU、TANDOM。
  • 不淘汰,达到最大内存再增加数据就报错。

        在Redis中会为每个键值对中的值对象记录一个对象空转时长。对象的空转时长在Redis中是一个重要的概念,它指的是一个键值对中的值对象自最后一次被命令访问以来所经过的时间。这个时间长度是通过OBJECT IDLETIME命令来获取的,该命令会返回当前时间与键的值对象的lru属性(最后一次被访问的时间)之间的差值。值得注意的是,使用OBJECT IDLETIME命令查看空转时长时,并不会修改对象的lru属性,这意味着即使查看了空转时长,该时长也不会重置为0。在Redis的内存管理中,空转时长还有一个重要作用。如果Redis配置了maxmemory选项,并且内存回收策略设置为volatile-lruallkeys-lru,那么当内存使用量超过maxmemory限制时,Redis会优先考虑释放那些空转时长较长的键,以此来回收内存。这种机制有助于确保Redis服务器能够高效地使用内存资源,同时避免长时间未使用的数据占用宝贵的内存空间。

持久化

背景

        我们为什么要进行持久化?这不难理解,Redis是内存数据库,而内存特性就是断电就死,程序宕机、服务器重启等情况下我们无法进行数据恢复。此外,某些键值对会占用大量空间,这就导致内存紧张,无法创建新的key,但大key在不能淘汰的情况下,持久化就是刚需。

        Redis大多数持久化的方式是通过fork进程进行持久化,叫写时复制。首先redis进程会fork出子进程,但磁盘复制的消耗是比较大的,于是先只复制页表,也就是数据的地址,然后将页表设置为只读状态,当下一次写数据发现页表只读时就会触发缺页中断,这时候linux就开始复制磁盘数据,子进程的页表就重新指向新的磁盘空间,最后再将redis进程的页表设置为可读可写。

持久化方法-aof

        Redis的aof持久化方法是一种记录Redis服务器接收到的每个写操作命令,并追加到aof文件中的持久化方式。这种方式能够提供更好的数据持久化保证,因为它记录了每一个会导致数据变化的命令。基本原理是将所有修改数据的命令追加到aof文件的末尾。这种方式可以确保数据的完整性,因为即使Redis服务器发生故障,也可以通过重新执行aof文件中的命令来恢复数据。aof文件通常以文本形式存储,里面的内容是一系列可以执行的Redis命令。

        Linux本身具有刷盘机制,但是你不知道写入的数据什么时候会刷盘,在还没有刷盘时就宕机这样就白干了。Redis通过设置系统调用fsync(将写缓冲区的数据写入磁盘)的时机刷盘,这样就能实现不同的刷盘方式。aof刷盘的三种方法如下:

  • always:每次调用完write后马上调用fsync,这种方式稳定性最高,但是代价也最高,因为系统调用在主线程。
  • every_sec:每秒调用一次fsync,代价较低,因为它由bio_aof_fsync线程负责。这也是常用的方法,但是有可能会丢失一两秒的数据。
  • no:交给系统自己刷盘,主打一个随心所欲,数据丢失可能性就比较大。
  • aof-rewrite

        aof文件非常大,数据恢复特别慢,因为aof以重新指向命令的方式进行数据恢复,但是对于一个key我们只需要最后的状态就可以,fork进程后根据内存数据生成aof文件,避免同一个key的历史数据冗余。aof文件的重写(rewrite)是一个重要的机制,它用于减小aof文件的大小,去除冗余的命令,例如重复的SET命令可以合并为一个。重写过程中,Redis会创建一个新的aof文件,将当前的数据状态用最少的命令记录,然后替换旧的aof文件。只有当文件大于一个设定阈值时才会触发重写。

持久化方法-rdb

        aof是通过重新执行命令的方式持久化,效率低的可怕。吾有一计,直接拿着内存数据写到磁盘,这就是rdb,也称快照,拿着内存数据持久化,数据是二进制的,落盘速度就更快。但是rdb是5min一次,而且每次是将全部数据刷盘。所以rbd丢数据会很多,这样一看,aof保险,rdb高效。rdb工作原理:

  1. 创建快照:Redis通过fork()系统调用创建一个子进程。这个子进程会获得父进程数据的副本
  2. 写入文件:子进程将内存中的数据写入到一个临时的RDB文件中。这个过程是原子的,意味着在任何时候,要么快照成功,要么失败,不会留下一个损坏的文件。
  3. 替换旧文件:一旦子进程完成数据的写入,它会替换掉旧的RDB文件。这个替换过程也是原子的,确保了数据的一致性。
  4. 释放资源:子进程完成工作后会退出,操作系统会回收其使用的资源。

        aof保险,rdb高效。那可不可以rdb+aof混用。Redis的混合持久化是Redis 4.0引入的一种新的持久化方式,它结合了rdb和aof两种持久化方式的优点。在混合持久化模式下,当aof文件重写时,Redis会将内存中的数据以rdb格式写入到aof文件的开头,然后再将新的写操作以aof格式追加到文件的末尾。这样,aof文件就包含了全量的数据快照和一个操作日志。它既能够提供较快的数据恢复速度,又能保持较高的数据安全性。但是,对于需要高度可读性和简单持久化方案的场景,传统的aof或rdb可能更为合适。选择合适的持久化策略需要根据具体的业务需求和系统环境来决定。

持久化选择

        简单总结一下。aof数据可靠,丢失少。持久化过程代价较低。文件过大,数据恢复慢。rdb文件小,数据恢复快。数据丢失多,持久化过程代价高。

        此外,我们再来讨论一下大key对持久化的影响(面试题):

  • Always: 在这种模式下,每次写操作后都会调用fsync()函数将AOF日志数据同步到硬盘。如果写入的是大key,那么在执行fsync()时主线程可能会阻塞较长时间,因为大量数据同步到硬盘是一个耗时过程。
  • Everysec: 这种模式下,Redis会先写入AOF日志到内核缓冲区,然后每隔一秒将缓冲区内容写回硬盘。由于fsync()是异步执行的,大key的持久化不会阻塞主线程,减少了对性能的影响。
  • No: 在这种模式下,Redis不会主动调用fsync(),而是让操作系统决定何时将数据写回硬盘。这意味着大key的持久化过程不会影响主线程,但数据安全性较低,因为操作系统可能会在数据积累到一定程度后才进行硬盘写入。
  • RDB持久化通过创建数据快照的方式工作。当Redis中存在大量大key时,进行RDB快照(bgsave命令)会触发fork()系统调用,创建一个子进程来处理快照任务。这个过程中,父进程的页表被复制给子进程,如果大key很多,页表会很大,复制过程可能会耗时较长,导致主线程阻塞。此外,如果父进程在子进程创建后修改了大key,会发生写时复制(copy-on-write),进一步增加阻塞的可能性

http://www.mrgr.cn/news/30113.html

相关文章:

  • 一篇文章教你搞定缓存三兄弟(缓存雪崩、缓存击穿、缓存穿透)
  • 快手IP归属地怎么设置别的地方
  • 汇兴智造两年业绩未达标:大客户还兼任股东,资产负债率远高同行
  • Linux基础3-基础工具4(git),冯诺依曼计算机体系结构
  • 软件总体测试计划方案、验收测试、集成测试、测试报告、测试大纲等测试资料合集(Word原件)
  • 你还在为写好Prompt而头疼吗,带你走进DSPy-Program LLMs之初体验
  • 基于JavaSwing实现的酒店管理系统
  • Android插件化(四)基础之文件存储
  • Java线程---锁机制
  • 【记录一下】jenkins的安装与部署教程
  • 从北大张泽民院士团队的研究成果中寻找医学AI未来的发展方向|个人观点·24-09-19
  • 【日记】书荒了(337 字)
  • 耐压110V茂睿芯MK9019可以向下兼容MK9016
  • 电脑怎么设置开机密码?3个方法迅速搞定!
  • 大华主动注册协议接入SVMSPro平台
  • 【数据结构】排序算法---计数排序
  • python多进程程序设计 之三
  • 最优化理论与自动驾驶(十一):基于iLQR的自动驾驶轨迹跟踪算法(c++和python版本)
  • 如何将MySQL卸载干净(win11)
  • C++学习, 异常处理