redis学习笔记-持久化

前言

redis持久化有两种方式:RDB和AOF。分别对应着全量复制和增量复制。深刻理解各自的实现方式及适用场景对redis的使用和运维十分重要。下面就分别介绍。

RDB持久化

RDB持久化即将当前Redis实例中的数据快照全部保存的磁盘的过程。可手动触发,也可根据配置自动触发。

手动触发

手动触发有两个命令可以选择: savebgsave。两者区别在于save是阻塞的,复制完成前会阻塞客户端命令执行,目前已经废弃。bgsave是非阻塞的。执行过程中redis进程会fork出一个子进程负责复制任务,而主进程依然响应客户端请求命令。对应bgsave命令,阻塞只存在于fork过程中。大大减小了阻塞的时间。

如图,上次rdb同步时间在17:20

执行命令bgsave后, 返回 Background saving started ,

查看rdb文件更新时间,已变为当前时间。

自动触发

若使用自动触发,需配置save参数。格式 save m n。查看redis配置文件可看到相关配置。

 save 900 1save 300 10save 60 10000复制代码

配置 save m n 含义为当数据在m秒内发生n次修改,自动执行bgsave命令进行RDB持久化。如save 900 1 表示在900秒(15分钟内)数据有至少1次修改,则触发RDB。多个配置情况下,只要符合任一条件即可。

具体在实现上,redis服务器会记录自上次RDB备份后,有多少次修改。每100ms检查一次,看是否有符合条件的save配置,有则再次执行DRB.

另外,当在客户端执行关闭服务器命令shutdown,若redis没有开启AOF,则自动执行bgsave进行备份。

RDB流程

由于save的持久化命令会发送阻塞,所以目前基本是用bgsave命令触发的RDB,关于bgsave的流程如下图所示。

简要流程如下

  1. redis进程(即图中主进程)收到bgsave命令后,调用fork命令创建子进程。期间主进程是阻塞的(图中1,2)。
  2. 主进程创建子进程完成后,返回Background saving started,不再阻塞,照常响应客户端命令。(图中3)
  3. 子进程开启RDB复制任务,根据主进程内存快照进行备份。(图4)
  4. 子进程完成后通知主进程,RDB任务完成。(图5)

简要来说是父进程fork出了一个子进程用于持久化任务,父进程仍响应客户端请求,耗时的RDB让子进程来做。这样的确可以大大减少阻塞时间,可有一个问题是,主进程还在接受请求,子进程怎样进行复制?难道子进程再复制一份主进程的内存用于复制,这样内存岂不是要翻倍?肯定不能这样。要是子进程共享父进程的内存,那怎样保证边接受请求边复制呢?

事实上,fork操作使用写时复制(copy-on-write)技术实现。创建的子进程共享父进程地址空间,当只有需要写入时才会复制地址空间。也就是说,redis的子进程使用共享的内存快照完成RDB备份,而主进程当收到写请求后,会将涉及到的内存页复制出一份副本,在此副本进行修改。当子进程RDB完成后,通知主进程更换副本,RDB就此完成。

RDB参数设置及注意点

  1. RDB文件路径由dir设置,文件名由dbfilename指定。RDB文件为二进制文件,可开启压缩处理,压缩后文件体积可大大缩小。使用rdbcompression参数指定,默认为yes
  2. RDB文件表示某时刻的redis内存快照,文件也相对较小,适用于备份,全量复制等场景。不适合实时持久化。

以下是redis配置文件有关rdb的默认配置

## 是否开启rdb文件压缩
rdbcompression yes## rdb文件效验
rdbchecksum yes## rdb文件名
dbfilename redis-dump-127.0.0.1-6379.rdb## 备份文件储存目录
dir /usr/local/var/db/redis/复制代码

AOF持久化

AOF主要用于解决redis实时持久化的问题。方式为实时将redis所有写命令记录下来,用于以后恢复及备份。

开启AOF

aof默认是关闭的,使用appendonly yes开启。用appendfilename设置aof文件名。同rdb一样,dir表示aof储存目录。

在配置文件设好后重启redis,即开启了aof功能。可使用info persistence可查看redis持久化的参数,如下

aof_enabled:1

表示已开启aof功能。

AOF流程

AOF写入日志的直接就是文本格式。如set hello world这个命令,在appendonly.aof文件中储存的就是

*3
$3
SET
$5
hello
$5
world
复制代码

这就是Redis客户端与服务器通信的的序列化协议(RESP),每行用\r\n分割,*n表示参数个数,$n表示字节数,十分简单明了。AOF直接使用协议格式可让redis直接识别。无需特殊处理,避免二次处理的开销,也方便修改。

AOF的流程如下

  1. 每当遇到写命令时,执行完命令后,会将此命令再写入一个由AOF维护的缓存区(aof_buf)。
  2. AOF缓冲区根据指定策略将数据刷到硬盘保存落地。

用流程图表示就是

为什么不直接将命令写入磁盘很容易理解,这里需关注的是以什么策略从缓冲区写到磁盘。redis提供了3种策略。

策略 说明
always 每次命令写入缓冲区后都同步刷新到硬盘(使用fsync命令刷新磁盘),此方式最安全,但也是最慢的,因为每次写数据都要同步硬盘
everysec 每次写命令调用系统命令write操作,write只会将数据写入系统缓冲区,然后由专门的线程每秒同步刷盘
no 每次写命令调用系统命令write操作写入系统缓冲区,具体刷盘时间由操作系统决定,性能是最高的,但数据安全性不能保证

通常,我们选择everysec作为刷盘策略,也是redis默认配置,可以兼顾性能和数据安全。

AOF追加阻塞

一般我们使用everysec的同步刷盘策略。此时会有一个专门的线程每秒执行一次刷盘操作。为保证数据安全性,redis主进程会比对上次刷盘时间与当前时间的差值,如果大于2秒,则阻塞以等待刷盘完成。

也就是说,如果硬盘性能很差,fsync执行太慢,会造成redis阻塞。以保证硬盘的数据不被真实内存数据落的太远(最大2秒的数据差)。

AOF重写机制

刚才提到,AOF直接使用redis的序列化协议进行备份,一段时间后,aof文件会很大。为解决此问题,可配置aof重写机制对原aof文件进行瘦身。

AOF重写的实质即把redis进程的内存数据转为写命令重新生成一份aof文件,以替代原aof文件。

重写后比原aof体积小的原因有以下几点

  1. 过期数据不再写入
  2. 命令可合并(hset k1 f1 v1,hset k1 f2 v2可合并hmset k1 f1 v1 f2 v2
  3. 重写直接使用内存数据生成,一些无效命令就不会再写入了。(如set hello a, set hello b等)

触发方式

AOF可有手动触发和自动触发。

手动触发使用bgrewriteaof命令触发。

自动触发有关参数及含义如下

## aof重写时此时aof文件与上次aof文件大小百分比
auto-aof-rewrite-percentage 100## aof重写时文件最小大小,默认64M
auto-aof-rewrite-min-size 64mb复制代码

如按默认配置,则发生重写的条件为aof文件大于64M且此时aof文件比上次重写时大100%,即是上次的2倍。

重写流程

  1. redis主进程收到aof重写命令(bgwriteaof),fork出子进程用于执行aof重写流程(图中1,2)。
  2. 主进程继续接收客户端请求,将请求写入aof_buf缓冲区。保证原有aof流程正常工作(图中3.1.1和3.1.2)。
  3. 同时,主进程还会将写命令写入aof_rewrite_aof(aof重写缓冲区),用于补偿aof重写期间丢失的命令(图中3.2)。
  4. 子进程与此同时进行aof重写过程(图中3.3)
  5. 子进程完成aof重写后信号通知主进程(图中4)
  6. 主进程收到子进程完成信号后,将aof_rewrite_aof的命令写入新aof文件(图中5)
  7. 新aof文件原子替换旧aof文件,aof重写流程结束(图中6)。

aof重写虽然比较复杂,但对比图,也能很容易明白其中流程。这这里有个疑问是为什么主进程在子进程重写时为什么要维护两个缓冲区?只维护一个不行吗?毕竟原有aof文件等到新aof文件生成后也是要替换的。

仔细想想就可知,有必要维护两个缓冲区。主要是需要维护原有aof逻辑不变,以防aof重写失败导致数据丢失。另一点两个缓冲区目的也不同,不宜混淆。

注意:

为防止资源过于竞争,同一时刻只能进行一个AOF重写任务,当进行重写时发现有RDB任务时,也会等RDB完成后进行。

RDB与AOF

加载顺序

在重启时,redis会首先判断是否开启aof,若开启aof且aof文件存在,则加载aof文件进行数据恢复以启动。否则判断rdb文件存在并加载rdb以启动。

性能开销

在进行RDB备份或是AOF重写时,都需要fork出子进程运行任务。此期间会大量消耗CPU,通常子进程对单核CPU的利用率达到90%,因此在有RDB或需AOF重写任务的redis,不要做绑定单核CPU操作,这会导致父子进程对CPU产生竞争。

RDB与AOF比较

  1. RDB是全量复制的持久化方式,一次性生成内存快照,产生二进制文件。文件读取速度快,生成较慢。适用于数据冷备。
  2. AOF通过追加生成持久化文件,体积较大,用于数据实时备份。
  3. redis阻塞的场景在fork子进程和AOF的追加阻塞阶段。

参考文章

  1. Redis开发与运维
  2. Redis设计与实现
  3. Linux进程管理——fork()和写时复制

redis学习笔记-持久化相关推荐

  1. Redis学习笔记(五)——持久化及redis.conf配置文件叙述

    对于日常使用来说,学习完SpringBoot集成Redis就够我们工作中使用了,但是既然学习了,我们就学习一些Redis的配置及概念,使我们可以更深层次的理解Redis,以及增强我们的面试成功概率,接 ...

  2. Redis学习笔记1-理论篇

    目录 1,Redis 数据类型的底层结构 1.1,Redis 中的数据类型 1.2,全局哈希表 1.3,数据类型的底层结构 1.4,哈希冲突 1.5,rehash 操作 2,Redis 的 IO 模型 ...

  3. Redis学习笔记(实战篇)(自用)

    Redis学习笔记(实战篇)(自用) 本文根据黑马程序员的课程资料与百度搜索的资料共同整理所得,仅用于学习使用,如有侵权,请联系删除 文章目录 Redis学习笔记(实战篇)(自用) 1.基于Sessi ...

  4. Redis学习笔记(B站狂神说)(自己总结方便复习)

    Redis学习笔记B站狂神说 redis: 非关系型数据库 一.NoSQL概述 1.为什么要用Nosql 1.单机Mysql的年代 思考一下,这种情况下:整个网站的瓶颈是什么? 1.数据量如果太大,一 ...

  5. Redis(学习笔记)

    Redis学习笔记 1.NoSQL数据库 1.1解决的问题 1.1.1解决CPU及内存压力 1.1.2解决IO压力 1.2NoSQL数据库概述 1.2.1什么是NoSQL数据库 1.2.2适用与不适用 ...

  6. Redis学习笔记①基础篇_Redis快速入门

    若文章内容或图片失效,请留言反馈.部分素材来自网络,若不小心影响到您的利益,请联系博主删除. 资料链接:https://pan.baidu.com/s/1189u6u4icQYHg_9_7ovWmA( ...

  7. Redis学习笔记(一) 数据类型事务异常Jredis

    Redis学习笔记(一) NoSql概述 Nosql四大分类 Redis入门 简介 Windows安装 基础使用 问题 Redis4.0之前为什么是单线程 单线程为什么这么快 Redis4.0后的多线 ...

  8. Redis学习笔记---Redis的主从复制

    Redis学习笔记-Redis的主从复制 1.Redis的高可用性 高可用性(High Availability)通常来描述一个系统经过专门的设计,从而减少停工时间,而保持其服务的高度可用性. Rei ...

  9. Redis学习笔记②实战篇_黑马点评项目

    若文章内容或图片失效,请留言反馈.部分素材来自网络,若不小心影响到您的利益,请联系博主删除. 资料链接:https://pan.baidu.com/s/1189u6u4icQYHg_9_7ovWmA( ...

最新文章

  1. Oracle单实例下oracle数据库从文件系统迁移到ASM上
  2. 探索 OSGi 框架的组件运行机制
  3. java void eat_java匿名内部类
  4. 学习方法之05六步法则,考上清华北大的路径
  5. 程序员跳槽全攻略pdf
  6. .NEt中的继承、聚合和组合
  7. 一条数据的HBase之旅,简明HBase入门教程3:适用场景
  8. java类和对象的基础(笔记)
  9. DES, TripleDES and BlowFish in Silverlight
  10. 微软十月补丁星期二值得关注的0day及其它
  11. PHP和MySQL Web开发从新手到高手,第9天-总结
  12. 各地特色美食与点菜的艺术
  13. 虚拟机克隆后修改网络部分
  14. 英雄联盟LOL静态HTML网页制作模板DⅣ+CSS学生网页作品代码游戏题材大学生网页设计作业下载
  15. 【复杂网络】最清晰最准确理解什么是“结构洞(Structural Hole)”?
  16. 松柏先生: 做品牌自己挣钱不算什么, 能让1000名山区绣娘都挣钱才牛!
  17. 【数据压缩】压缩率-图像熵-保真度
  18. oracle 常见报错
  19. 数据库 1NF、2NF、3NF、BCNF
  20. python车辆定位调度管理系统,基于django+twisted

热门文章

  1. strcpy函数的使用
  2. springboot:SpringBoot项目启动成功,但无法访问且提示404
  3. jvm四:常量的本质含义以及助记符基本认识
  4. 如何拆分PDF,PDF拆分页面的方法
  5. 题目:返回一个整数数组中最大子数组的和03
  6. pycharm远程开发项目
  7. 0201-开始使用Spring Cloud实战微服务准备工作
  8. JVM调优系列:(五)JVM常用调试参数和工具
  9. 解决crond引发大量sendmail、postdrop进程问题
  10. 使用Transact-SQL进行数据导入导出方法详解