• Redis持久化与一致性解决方案「面试必问」


    1. MySQL与Redis一致性解决同步问题 

    怎样去验证我们的Redis缓存是否一定生效了呢?

    • 很简单:如果缓存生效,那么我们每次查询数据是不是先从Redis里面查,那么好,我们先去查第一次,接着去改MySQL里面的数据值,此时再去查第二次,此时如果发现第二次查询到的数据值与与我们改过的MySQL里面的数据值不一致,也就是两次查询返回的结果相同,此时就证明Redis缓存生效了。

    MySQL与Redis数据不同步的问题如何解决?

    方式1:直接清理Redis缓存,重新查询数据库让它重新去同步即可~!(这样做治标不治本)

    方式2:我们的MySQL和Redis实现数据同步不可能是强一致性在分布式系统当中不可能有强一致性),我们只有通过一些最终一致性的解决方案,就是短暂数据延迟、不一致是允许的,但是最终数据一定要保持一致直接使用MQ异步订阅MySQL的bin log日志文件(insert/delete/update),然后增量的同步到Redis中(实现增量同步) => 最终一致性的方案。

    方式3:使用Alibaba的canal开源框架它的底层就是采用MQ订阅bin log,可以简单的把canal理解为就是一个用来同步增量数据的一个工具。

    2. Redis持久化机制 

    Redis有两种持久化方案:

    • RDB快照持久化

    • AOF日志持久化  

    • 混合持久化方式Redis 4.0 新增的方式,集成了 AOF 和 RBD 的优点;

    Redis因为出现某种原因的情况下发生宕机之后,数据是不会丢失的,原理就是Redis当中的持久化机制~!

    持久化就是把内存中的数据持久化到本地磁盘,防止服务器宕机所导致的内存数据丢失。

    EHCAHE属于一级缓存,是JVM内置缓存!

    大部分的缓存框架都会有基本功能:淘汰策略、持久化机制(唯独Memcached很奇葩,Memcached就是一个单纯的缓存框架,它里面就没有持久化机制)...

    多级缓存使用到了一个装饰设计模式:相当于我不影响我之前缓存本身的代码,但是我可以对我的缓存去做增强,因此多级缓存就是采用装饰模式去实现的~!

    多级缓存可以采用装饰模式去重构~!

    Redis当中的持久化机制:Redis当中提供了持久化机制,它会把内存当中的数据备份在磁盘当中!磁盘当中的文件当你出现断电、宕机之后,在你重启Redis时,它会把磁盘当中的文件再加载到内存当中,从而保证你的数据可以不丢失!

    持久化机制可以保证即使Redis进程在写入数据时崩溃,数据也不会丢失~!

    Redis提供了两种持久化机制:RDB(默认)和 AOF机制。 

    Redis的持久化机制有两种方案:RDB(默认)和AOF!

    Redis默认采用RDB方式来实现数据的持久化!

    全量同步与增量同步实现的区别:

    全量同步和增量同步都是分布式系统中常用的数据同步的方法。

    全量同步

    • 全量同步(Full Synchronization)定时同步,就是每天定时(避开高峰期)或者是采用一种周期的实现将数据拷贝到另外一个地方,比如900s以内,如果对我们的Redis做了10次写的操作,那么就将所有数据持久化的写入到硬盘当中,或者是从源节点将所有数据都发送传输到目标节点,以确保目标节点和源节点上的数据完全一致
    • 全量同步通常用于备份、重构或初始化整个分布式系统的场景
    • 在进行全量同步时,会将整个数据库当中的数据复制到目标位置,无论是否已经存在相同的数据记录,所以由于全量同步需要传输所有的数据,因此如果在数据量比较大的情况下,会耗时较长,占用大量的网络带宽和系统资源虽然全量同步频率不是很大,但是可能会造成数据的丢失。

    增量同步

    • 增量同步(Incremental Synchronization)采用对行为进行记录的操作来实现数据的同步也就是源节点和目标节点之间只传输发生变化的数据,从而来确保目标节点和源节点之间的数据保持同步。
    • 由于增量同步是基于之前的同步状态和标记,只将变更部分,也就是只有变化的数据才会被记录传输到目标位置,已经存在的数据记录不会被重复复制,因此增量同步的开销相对较小,但是增量同步的过程比较频繁,频率会非常高,频率如果非常高,对我们的Redis整个服务器同步的压力也是比较大的,但是能够保证数据不丢失。

    全量同步与增量同步的比较:

    • 增量同步会比全量同步更加消耗服务器的内存,但是能够更加的保证数据的同步。

    在Redis中,主从复制就是一个典型的增量同步的场景,Redis的主节点可以持久化数据到磁盘,并通过将数据变化的命令的发送给从节点来实现增量同步,从节点接受到命令之后,按照发送顺序依次执行以保证数据的一致性。

    持久化机制 - RDB持久化 - 全量同步 - 持久化内存数据到磁盘

    • RDB全称Redis Database Backup file(Redis数据备份文件),也被叫做Redis数据快照,是Redis默认的持久化方式。
    • RDB采用定时持久化机制,所以RDB采用全量同步的持久化方案,按照一定的时间将内存中的数据以快照的形式保存到硬盘中,对应产生的数据文件为dump.rdb,但是服务器因为某种原因宕机后可能数据会丢失。
    • 简单来说就是把/将Redis内存当中的所有数据以二进制、快照的形式都记录/保存到磁盘当中,当Redis实例发生故障重启后,此时会从磁盘读取快照文件并加载到内存当中,从而来恢复数据。
    • Disk:磁盘   DB  loaded  from  disk
    • RDB备份文件:dump.rdb => 是Redis的二进制快照文件,保存的都是二进制格式的数据
    • 快照文件称为RDB文件,保存了最后一次生成快照时Redis当中的所有数据,默认是保存在当前运行目录!
    • Redis已经帮助我们默认开启了RDB存储~!

    RDB持久化的执行时机

    RDB持久化在四种情况下会执行:被动操作(一二三) + 主动操作(四)

    • 一和二都是手动触发快照操作,让Redis去做一个备份! 
    1. 手动调用执行save命令, 可以立即执行一次RDB:DB saved on disk:保存在磁盘上,save指令是由Redis的主进程来执行RDB备份操作,由于Redis的工作线程是单线程,如果执行save指令则会阻塞其他所有命令的执行,因此不建议使用!SAVE命令执行快照的过程会阻塞所有客户端的请求,应避免在生产环境使用此命令,只有在数据迁移时可能用到,Redis为了规避这个问题,又给我们提供了另外一个指令:bgsave,bgsave命令可以在后台异步进行快照操作,快照的同时服务器还可以继续响应客户端的请求,因此需要手动执行快照时推荐使用basave命令!

    2.  bgsave是主流的触发RDB持久化的方式,手动调用执行bgsave命令,异步执行RDB:bg指的是background,后台运行,bgsave指令会开启独立的fork子进程来执行RDB备份操作,从而避免主进程受到影响,让主进程继续处理命令,主进程可以持续处理用户请求,不受影响。

    1. Redis停机(关闭Redis服务器)时会执行一次save命令,执行RDB备份操作,实现RDB持久化:Saving the final RDB snapshot before exiting. 在退出之前保存最后的RDB快照。但是注意:如果突然断电则不执行RDB备份操作,主动关闭Redis服务器才会执行,比如默认情况下执行shutdown命令时,如果没有开启AOF持久化功能则自动执行BGSAVE  =>  被动触发~!

    4. 触发RDB条件时:在Redis内部有触发RDB的机制,可以在redis.conf文件中找到,格式如下:

    • RDB:把内存当中的数据直接dump备份到RDB文件当中~! 

    通过配置文件中的save参数来定义快照的周期 - Redis服务器dump-备份快照的频率: 

    • Save     
    1. # 900秒内,如果至少有1个key被修改,则执行bgsave命令来指定RDB备份操作 如果注释掉save "",则表示禁用RDB
    2. save 900 1 如果900s(15分钟)内有一个Key发生变化被修改,就触发一次RDB
    3. save 300 10 如果300s(5分钟)内有十个Key发生变化,就触发一次RDB
    4. save 60 10000 如果60s(1分钟)内有一万个Key发生变化(代表60s内至少执行10000次修改责编触发RDB),就触发一次RDB

    RDB的其它配置也可以在redis.conf文件中设置:

    1. # 是否对RDB备份文件做压缩处理,降低RDB文件的体积
    2. # 建议不开启,压缩也会消耗cpu,影响Redis的性能,磁盘的话不值钱
    3. rdbcompression yes
    4. # RDB文件名称
    5. dbfilename dump.rdb
    6. # RDB文件保存的路径目录 ./表示当前目录
    7. dir ./

    RDB原理

    • 在Linux系统当中,所有的进程都没有办法直接操作物理内存,而是由操作系统给每个进程分配一个虚拟内存,主进程只能操作虚拟内存,而后操作系统会维护一个虚拟内存与物理内存之间的映射关系表,这个表就称之为页表,所以,主进程操作虚拟内存,而虚拟内存基于页面的映射关系到我们的物理内存真正的这个存储位置,这样就能实现对物理内存数据的读写了。
    • bgsave开始时会fork主进程得到子进程(主/父进程执行fork操作会去创建一个子进程,注意:这个fork的过程对主进程来说是阻塞的)子进程共享主进程的内存数据(注意:它不是把主进程的内存数据做拷贝,而是把主进程的页表做拷贝,这样,主进程跟子进程就有了相同的影映射关系,当子进程在操作自己的虚拟内存时,因为映射关系跟主进程一样,所以最终一定能映射到相同的物理内存区域,这样就实现了子进程与主进程内存空间的共享了,这样,就无需拷贝内存中的数据,直接实现内存共享,这样阻塞的时间就尽可能的缩短了),完成fork后子进程开始读取内存数据并写入到磁盘当中的RDB文件里面去,当然这是一个新的RDB文件,写完之后会替换旧的RDB文件  =>  这个过程确实是异步执行的。

    子进程在写RDB的过程当中,主进程也可以同时接收用户的请求,来去修改内存中的数据,如果这个时候主进程同时在修改数据,而子进程同时在读,读写之间会有冲突,甚至有可能会出现一些脏数据,所以为了避免这个问题的发生,我们的fork底层会采用Copy-On-Write技术,fork会把共享内存标记成read-only只读模式,任何一个进程都只能来读数据,而不能写:

    • 当主进程执行读操作时,访问共享内存;
    • 当主进程执行写操作时,则会拷贝一份数据,执行写操作,这样就避免了脏写问题的发生 

    RDB方式bgsave的基本流程?

    • fork主进程得到一个子进程,共享主进程的内存空间
    • 子进程读取内存数据并写入新的RDB文件
    • 用新的RDB文件替换旧的RDB文件 

    RDB的优缺点

    优点:

    • 只有一个文件dump.rdb,方便持久化;
    • 性能最大化,fork子进程来进行持久化写操作,让主进程继续处理命令
    • 相当于数据集大时,比AOF的启动效率更高

    缺点:

    • 如果发生断电,则RDB会存在丢失数据的风险:因为RDB是间隔一段时间进行持久化,假设上一次触发了RDB,但下一次还没来得及触发突然发生断电了,两次RDB之间写入数据就会有数据丢失的风险;
    • RDB它是将内存当中的数据以及快照直接保存在磁盘当中, 写RDB文件比较耗时,耗费性能~!前提是你的内存当中存储的数据量比较大!

    容灾性是指系统在面对硬件故障、软件错误或其他不可预测的异常情况时,仍能保持部分或全部功能可用的能力。 

    RDB全量同步用的比较少,一般都会用AOF增量同步~! 

    持久化机制 - AOF持久化 - 增量同步 - 持久化修改数据的命令

    AOF是基于数据日志操作实现的持久化,所以AOF采用增量同步的持久化方案(推荐使用)~!

    AOF的主要作用是解决了数据持久化的实时性,AOF是Redis持久化的主流方式。 

    • AOF全称为Append-Only File(追加文件)。
    • AOF备份文件:appendonly.aof  
    • AOF持久化是将Redis服务器处理的每一个写命令/写操作(set命令 => 只记录影响数据变化的指令 => 增删改的)都会追加记录在AOF文件的末尾,以文本格式记录了Redis服务器收到的每个写操作的命令,可以看做是命令日志文件。 
    • 当Redis需要恢复数据时,只需重新执行AOF文件中的写命令即可。
    • AOF持久化可以提供更高的数据安全性,因为在每次写操作后都会追加到AOF文件中,避免了数据丢失的风险。

    AOF默认是关闭的,需要修改redis.windows.conf配置文件来开启AOF:

    1. # 是否开启AOF持久化功能,默认是no,是关闭的,如果需要开启AOF持久化,则需要将no改为yes
    2. appendonly yes
    3. # AOF文件的名称
    4. appendfilename "appendonly.aof"

    默认情况下系统每30s会执行一次同步操作,为了防止缓冲区数据丢失,可以在Redis写入AOF文件后主动要求系统将缓冲区数据同步到硬盘上,可以通过appendfsync参数设置同步的时机。

    AOF的命令记录的频率也可以通过redis.windows.conf文件来配:AOF的三种同步策略  

    1. # 表示每执行一次写命令,就立即记录到AOF文件(写一次,保存一次),能够实时的保证数据的安全性,保证数据不丢失,但是效率非常低
    2. appendfsync always
    3. # sec是second-秒的简写,写命令执行完先放入AOF缓冲区,然后表示每隔1秒将缓冲区数据写到AOF文件,是默认方案,该方案是AOF的缺省策略。
    4. appendfsync everysec
    5. # 写命令执行完先放入AOF缓冲区,由操作系统决定何时将缓冲区内容写回磁盘
    6. appendfsync no
    AOF的三种同步策略对比:  

    • 建议使用everysec,既能够保证数据的同步,效率也还可以,但是它也有缺点:最多丢失1秒内的数据,但是效率非常高~!

    AOF的优缺点:

    优点:

    1. 数据安全,AOF持久化可以配置appendfsync属性,可以配置AOF每秒执行一次fsync操作,如果Redis进程挂掉,最多丢失1s的数据。 
    2. 通过append模式写文件,即使中途服务器宕机,可以通过redis-check-aof工具解决数据一致性问题。
    3. AOF以append-only的模式写入,所以没有磁盘寻址的开销,写入性能非常高。

    缺点:

    1. 对于同一份文件,AOF文件比RDB数据快照文件要大,且恢复速度慢
    2. 数据集大的时候,比RDB启动效率低
    • AOF增量备份时,文件太大了怎么办?  =>  AOF文件重写! 

    AOF文件重写

    • 因为是记录命令,AOF文件会比RDB文件大的多而且AOF会记录对同一个Key的多次写操作,但是只有最后一次写操作才有意义。 
    • 因此Redis给我们提供了一条命令,通过执行bgrewriteaof命令 => 对AOF日志进行重写,可以让AOF文件执行重写功能,AOF文件重写是Redis中一种优化AOF持久化机制的操作,它重新创建一个更小的AOF文件来替代原有的AOF文件,从而达到减轻磁盘空间占用和提高读取性能的目的,通过消除 / 删除已过期或已删除的数据的命令 => 只会记录该Key的最后一次修改,用最少的命令达到相同效果,从而在一定程度上去降低AOF日志文件的体积。

    • AOF文件重写的过程并不是简单的对原有的AOF文件进行压缩或者整理,而是通过读取内存中的数据来重建一个新的AOF文件,它会遍历Redis当前内存中的数据并将其以命令的形式写入到新的AOF文件中,整个过程不受原有AOF文件的影响,因此可以消除原AOF文件中已过期或已删除的数据。
    AOF文件重写的触发方式有两种:
    1. 手动触发:通过发送bgwriteaof命令给Redis服务器,从而来手动触发AOF文件重写。
    2. 自动触发:通过设置redis.conf配置文件中的auto-aof-write-percentage和auto-write-min-size参数来配置自动触发AOF文件重写的条件。Redis也会在触发阈值时自动去重写AOF文件,当AOF文件的大小比上次文件增长超过指定的百分比 ,或者AOF文件的体积大小超过指定的最小体积时,Redis会自动触发AOF文件重写。
    1. # AOF文件比上次文件 增长超过多少百分比则触发重写
    2. auto-aof-rewrite-percentage 100
    3. # AOF文件体积最小多大以上才触发重写
    4. auto-aof-rewrite-min-size 64mb

    需要注意的是:AOF文件重写是一个耗时且消耗CPU资源的操作,可能会对Redis服务器产生负载,因此在生成环境中需要谨慎使用。

    RDB和AOF对比

    维度RDBAOF
    持久化方式定时对整个内存做快照记录每一次执行的写命令
    数据完整性不完整,两次备份之间会丢失相对完整,取决于刷盘策略
    文件大小会有压缩,文件体积小记录命令,文件体积很大
    宕机恢复速度很快
    数据恢复优先级低,因为数据完整性不如aof高,因为数据完整性更高
    系统资源占用高,大量cpu和内存消耗低,主要是磁盘io资源,但aof重写时会占用大量cpu和内存资源
    使用场景可以容忍数分钟的数据丢失,追求更快的启动速度对数据安全性要求较高常见
    • aof文件要比rdb文件要大很多! 
    • Redis加载RDB恢复数据远远快于AOF的方式。
    1. RDB属于全量同步(定时同步),优点:同步效率非常高   缺点:RDB方式数据无法做到实时持久化,数据可能会丢失,因为BGSAVE每次运行都要执行fork操作创建子进程,属于重量级操作,频繁执行成本比较高。
    2. AOF属于增量同步(有点偏向实时),优点:同步效率比较低,最多只会丢失1秒钟数据

    平衡点:你既想要效率高,又想要数据不丢失,肯定使用AOF的everysec同步策略~! 

    RDB和AOF各有自己的优缺点,通常来说,可以选择同时启用RDB和AOF持久化,这样在Redis重启时可以使用RDB文件加载数据,通过重放AOF文件中的命令来实现数据的完整性和一致性~!

    如果AOF与RDB都开启的情况下,优先使用AOF,因为AOF同步更加偏向数据不丢失~!

  • 相关阅读:
    Ubuntu20.04 中已经安装 Pytorch 但 Import 报错 - 解决记录
    macOS Sonoma 正式版系统已发布,macos14值得更新吗
    第七章 查找 九、B+树
    react中使用Modal.confirm数据不更新的问题解决
    Redis 发布和订阅
    #ubuntu# #git# repository git config --global --add safe.directory
    【3D视觉】PointNet解析
    光储并网直流微电网simulink仿真模型,光伏采用mppt实现最大功率输出研究
    传智健康_第6章 移动端开发-体检预约
    android系统耗时关键字
  • 原文地址:https://blog.csdn.net/weixin_53622554/article/details/134231854