我们知道关系型数据库比如MySQL支持全备、差备、增备。为了保证Redis故障重启后仍然可用我们的Redis支持全备(RDB快照备份)和增备(AOF日志连续增量备份),下面我们就来解读Redis持久化的原理。

RDB基础知识

RDB文件存在是以一个压缩后的二进制文件,这个RDB文件一般是保存在Redis安装目录下,通过启动Redis服务器执行rdbLoad函数加载RDB文件,执行rdbSave函数保存RDB文件。

RDB保存

rdbSave函数负责将内存中的数据库数据以RDB格式保存到磁盘中,如果RDB文件已存在,那么新的RDB文件将替换已有的RDB文件,SAVE和BGSAVE两个命令都会调用rdbSave函数。
SAVE直接调用rdbSave,阻塞Redis主进程,直到保存完成为止。在主进程阻塞期间,服务器不能处理客户端的任何请求。
BGSAVE则开启一个子进程,子进程负责调用rdbSave,Redis服务器在BGSAVE执行期间仍然可以继续处理客户端的请求,并在保存完成之后向主进程发送信号,通知保存已完成。

注意:执行保存命令时Redis不会再次执行save、bgsave、bgrewriteaof等命令,因为如果执行这些命令会存在资源抢占使备份出现意想不到的bug。

自动隔离保存

此时我们的小伙伴意识到,我们不能每次都执行命令手动保存或者执行定时器执行命令,这样会导致可用性降低,那么Redis提供自动保存的配置

####100秒内对Redis进行10次以上的修改save 100 10####一小时内对Redis进行至少1000次的修改save 3600 1000###只要满足上面任何一个要求则执行bgsave命令

那么Redis源代码中保存这个配置的是在redisServer中的一个saveparam的结构,代码如下:

struct saveparam {    teme_t seconds;    //秒    int changes;       //修改数}

RDB快照原理

save我们这里就不分析了,因为它直接阻塞主线程把Redis数据直接写入磁盘文件,所以我们这对bgsave进行讲解,前面说了bgsave是开启一个子进程进行文件的操作,那么此时的Redis主进程还在响应客户端的命令,那么我们的Redis如何保证数据完整性和性能呢?

Redis在持久化的时候会fork产生一个子进程,持久化过程完全交给子进程,而父进程则响应客户端的命令,子进程创建时不会立即保存文件因为这会与父进程产生资源抢占,它的指针指向父进程的内存空间与父进程共享内存,这样为了更加节约资源。

此时父进程是会读写内存中的数据,子进程只是读取资源并不会写,此时Redis使用操作系统的多进程COW(Copy On Write)机制进行数据段页面的分离,每页数据不会超过4K,我们把这个数据称之为冷数据,父进程进行修改的时候我们只需要把共享的页数据复制出来对其进行修改,而不在原数据上进行修改,冷数据没有任何的变化。子进程现在可以安心的对冷数据进行持久化,此时我们持久化的内容就像是被拍了照一样固定下来,这就是快照的整个过程。

这里值得注意的是随着时间的推移,父进程修改的页也会越来越多,理论上这个复制出来的内存能达到之前数据内存,所以我们在设计缓存的时候尽可能的少改数据。

AOF日志原理

Redis还有一个持久化操作那就是AOF(Append Only File),AOF是将客户端的修改指令保存下来追加到服务器状态的aof_buf缓冲区尾部,最后保存到AOF日志文件。举个例子。

首先,前面我们讲过Redis的通讯协议RESP,我们这里把客户端的指令转换成这种协议

>set name mango####保存到aof_buf缓冲区*3\r\n$3\r\nset\r\n$4\r\name\r\n$5\r\mango\r\n

然后我们将协议文本追加到aof_buf末尾

最后我们把这些指令信息保存至AOF日志文件中

AOF保存模式

每当服务器常规任务函数被执行、或者事件处理器被执行时,aof.c/flushAppendOnlyFile函数都会被调用,这个函数执行以下两个工作:
WRITE:根据条件,将aof_buf中的缓存写入到AOF文件。
SAVE:根据条件,调用fsync或fdatasync函数,将AOF文件保存到磁盘中。

Redis目前支持三种AOF保存模式:
1. AOF_FSYNC_NO:不保存,操作系统来决定什么时候保存保存。
2. AOF_FSYNC_EVERYSEC:每一秒钟保存一次。
3. AOF_FSYNC_ALWAYS:总是保存,每执行一个命令保存一次。

这三种模式从上到下执行速度越来越慢,安全性越来越高,如果使用no模式,那么恢复数据会恢复到上次备份,如果是everysec最多会丢失一秒,而always只会丢失一个指令。所以我们考虑使用哪种AOF模式取决于我们的业务需求综合考虑。

关于fsync

AOF日志是以文件的形式存在的,当我们的AOF从缓冲区写入AOF文件中时服务器突然宕机,此时我们的文件还没有完全写入磁盘,这时我们该如何处理呢?
fsync函数可以将指定文件的内容强制从内核缓存刷到磁盘。只要Redis进程实时调用fsync函数就可以保证AOF日志不失。但是fsync是一个磁盘IO操作,so它很慢。如果Redis执行一条指令就要fsync一次,那么可想而知Redis的性能就会拉下一大截 。
所以在生产环境的服务器中,Redis通常是每隔1s左右执行一次fsync操作,这个1s的周期是可以配置的。这是在数据安全性和性能之间做的一个折中,在保持高性能的同时,尽可能使数据少丢失。
Redis同样也提供了另外两种策略,一个是永不调用fsync让操作系统来决定何时同步碰盘,这样做很不安全,另一个是来一个指令就调用fsync一次——结果导致非常慢。这两种策略在生产环境中基本不会使用。

AOF重写

我们的AOF一直累加进行持久化,随着时间的推移备份文件会越来越大,甚至影响我们对Redis的恢复和操作,Redis也提供重写机制,下面我们来看看

>set name zhangsan>set name mango>set name lisi...>set name mango####优化后>set name mango

我们可以看到经常会对一个key进行多次修改,那么我们可以把这个key的最后一次操作保存起来这样我们就轻易的给AOF"瘦身"。当然我们还有一种方式,就是遍历整个Redis,set每个key和它的值,也跟RDB全备一样我们需要一个子进程读取当前的Redis库。

这里会出现一个问题,我们如果是遍历整个Redis需要考虑此时的客户端必定会有指令更改里面的值,此时我们怎么保证AOF重写后不丢下重写后的指令呢?

操作步骤:

  1. AOF创建一个子进程进行AOF重写,其指定内存跟主进程一致

  2. 客户端执行写命令,主线程处理指令,指令追加到AOF缓冲区,并且追加到AOF重写缓冲区

  3. AOF重写完成后替换现有的AOF文件

那么为什么会把这个指令同时追加到AOF缓冲区和AOF重写区呢?原因是如果我们在重写的时候突然服务器挂了,那么我们AOF文件中会保存这个指令。追加到AOF缓冲区是为了保证操作指令能及时同步到AOF重写区。AOF重写操作也就是之前提到过的bgrewriteaof。

Redis4.0混合持久化
Redis服务重启时,RDB会还原Redis库,那么如果Redis设置了AOF日志备份,Redis优先使用AOF恢复Redis库。为什么可以使用AOF恢复呢?原因是因为AOF是一个增量备份,按照AOF的规则我们可以恢复比较全的数据。当然RDB的恢复速度是比AOF快的,比较它是一个压缩后的二进制文件,相对于执行命令来说的确快。

Redis4.0为了解决这个问题,带来了一个新的持久化选项一一混合持久化。将RDB文件的内容和增量的AOF日志文件存在一起。这里的AOF日志不再是全量的曰志,而是自持久化开始到持久化结束的这段时间发生的增量AOF日志,通常这部分AOF日志很小。

在Redis重启的时候,可以先加载RDB,然后再重放增量AOF日志,就可以完全替代之前的AOF全量文件重放,重启效率因此得到大幅提升。

总结一下:

  1. Redis持续化操作包括RDB和AOF

  2. RDB保存的是一个压缩二进制文件,AOF保存的是操作指令文件

  3. Redis优先恢复AOF,因为它比较全,Redis4.0采用混合模式来恢复

  4. RDB执行bgsave时和AOF重写一样,开启一个子进程,他们的内存与父进程共享

  5. AOF有三种保存模式,no不主动保存依赖操作系统调度;everysec一秒执行一次;always每次执行一个指令保存一次。

  6. AOF保存模式主要是fsync函数,保证AOF日志不会丢失

一名正在抢救的coder

笔名:mangolove

CSDN地址:https://blog.csdn.net/mango_love

GitHub地址:https://github.com/mangoloveYu

Redis解读持久化RDB和AOF原理相关推荐

  1. Redis持久化 RDB和AOF 比较与选择

    Redis持久化方案 Redis是内存数据库,数据都是存储在内存中,为了避免进程退出导致数据的永久丢失,需要定期将Redis中的数据以某种形式(数据或命令)从内存保存到硬盘.当下次Redis重启时,利 ...

  2. 【Linux服务器开发系列】一场redis线上事故引发的思考丨redis持久化 rdb和aof丨redis主从复制

    一场redis线上事故引发的思考 1. 事故背景介绍 2. redis持久化 rdb和aof 3. redis主从复制 4. 解决方案详解 [Linux服务器开发系列]一场redis线上事故引发的思考 ...

  3. Redis持久化 - RDB和AOF

    一.持久化的作用 1. 什么是持久化 持久化(Persistence),即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘). 持久化Redis所有数据保持在内存中,对数据的更新将异步地保 ...

  4. 进阶的Redis之数据持久化RDB与AOF

    2019独角兽企业重金招聘Python工程师标准>>> 大家都知道,Redis之所以性能好,读写快,是因为Redis是一个内存数据库,它的操作都几乎基于内存.但是内存型数据库有一个很 ...

  5. Redis持久化 RDB和AOF

    什么叫持久化? 用一句话可以将持久化概括为:将数据(如内存中的对象)保存到可永久保存的存储设备中. 持久化的主要应用是将内存中的对象存储在数据库中,或者存储在磁盘文件中. XML 数据文件中等等. 也 ...

  6. 【腾讯阿里最全面试题】Redis持久化RDB和AOF 的区别

    跳槽必备: 嵌入式开发转互联网开发面经分享:嵌入式开发成功转战互联网行业 大厂offer的前置条件 学校学历,技术水准分析:大厂必备前置条件,项目经验 腾讯T9(原T3.1)offer,"8 ...

  7. Redis入门到精通(六),Redis的RDB及AOF原理及配置详解

    一.Redis的持久化 本章节会比较多的讲到所有关于Redis持久化的配置,平时使用场景会非常的少,对初学者可能不是很友好,如果仅仅是如何使用的话可以直接跳到RDB和AOF使用,小标题我标了红色,直接 ...

  8. Redis持久化----RDB和AOF 的区别

    关于Redis说点什么,目前都是使用Redis作为数据缓存,缓存的目标主要是那些需要经常访问的数据,或计算复杂而耗时的数据.缓存的效果就是减少了数据库读的次数,减少了复杂数据的计算次数,从而提高了服务 ...

  9. Redis持久化RDB和AOF、事务管理

    详解配置文件redis.conf 常用的配置:https://blog.csdn.net/weixin_45606067/article/details/107917743 五.Redis的持久化 1 ...

最新文章

  1. Android Studio SDK Manager 解决无法更新问题
  2. Linux下的buffer与cache
  3. WCF中安全的那些事!!!
  4. 搞清这些陷阱,NULL和三值逻辑再也不会作妖
  5. android之APP模块编译
  6. 5G浪潮推动 射频产业风起云涌
  7. 3dmax 渲染关机 脚本_3dmax从零开始【一】菜单栏
  8. 高可用eureka服务发现实例
  9. java大马后门_一款免杀php大马的解密与去后门
  10. 数学建模国赛LaTex模板讲解(Slager模板)
  11. c语言1到100奇数和与偶数和,C语言实现1到100的和奇数与偶数和
  12. linux运行360wifi,在Linux下使用“360随身WiFi 2”
  13. 如何执行IntelliJ IDEA 中的.sql文件
  14. 请问add_mutually_exclusive_group函数什么意思?
  15. 驱动篇 -- 继电器
  16. 有机化学反应里php什么意思,有机反应类型解读
  17. 前端工程化——脚手架及自动化构建
  18. 8821AU双频抓包案例
  19. 微信小游戏上线流程及游戏自审自查报告模板
  20. oracle数据库删除file,oracle数据库删除file

热门文章

  1. 计算机网络之数据链路层:4、流量控制和可靠传输机制(停止等待协议、后退N帧协议、选择重传协议)
  2. openjudge 菲波那契数列 2753
  3. JS json字符串转换
  4. Python list合并(列表合并),dict合并(字典合并)
  5. spring(四):spring与mybatis结合
  6. python实现汉诺塔程序
  7. Git HEAD detached from XXX (git HEAD 游离) 解决办法
  8. 细数那些年我用过的前端开发工具
  9. dbms_stats包更新、导出、导入、锁定统计信息
  10. 09_ServletContext介绍