0
点赞
收藏
分享

微信扫一扫

四、Redis持久化-动力节点最新Redis7笔记

4 Redis持久化

Redis是一个内存数据库,所以其运行效率非常高。但也存在一个问题:内存中的数据是不持久的,若主机宕机或Redis关机重启,则内存中的数据全部丢失。当然,这是不允许的。Redis具有持久化功能,其会按照设置以快照或操作日志的形式将数据持久化到磁盘。 根据持久化使用技术的不同,Redis的持久化分为两种:RDB与AOF。

4.1 持久化基本原理

Redis持久化也称为钝化,是指将内存中数据库的状态描述信息保存到磁盘中。只不过是不同的持久化技术,对数据的状态描述信息是不同的,生成的持久化文件也是不同的。但它们的作用都是相同的:避免数据意外丢失。 通过手动方式,或自动定时方式,或自动条件触发方式,将内存中数据库的状态描述信息写入到指定的持久化文件中。当系统重新启动时,自动加载持久化文件,并根据文件中数据库状态描述信息将数据恢复到内存中,这个数据恢复过程也称为激活。这个钝化与激活的过程就是Redis持久化的基本原理。 不过从以上分析可知,对于Redis单机状态下,无论是手动方式,还是定时方式或条件触发方式,都存在数据丢失问题:在尚未手动/自动保存时发生了Redis宕机状况,那么从上次保存到宕机期间产生的数据就会丢失。不同的持久化方式,其数据的丢失率也是不同的。 需要注意的是,RDB是默认持久化方式,但Redis允许RDB与AOF两种持久化技术同时开启,此时系统会使用AOF方式做持久化,即AOF持久化技术的优先级要更高。同样的道理,两种技术同时开启状态下,系统启动时若两种持久化文件同时存在,则优先加载AOF持久化文件。

4.2 RDB持久化

RDB,Redis DataBase,是指将内存中某一时刻的数据快照全量写入到指定的rdb文件的持久化技术。RDB持久化默认是开启的。当Redis启动时会自动读取RDB快照文件,将数据从硬盘载入到内存,以恢复Redis关机前的数据库状态。

4.2.1 持久化的执行

RDB持久化的执行有三种方式:手动save命令、手动bgsave命令,与自动条件触发。

4.2.1.1 手动save命令

通过在redis-cli客户端中执行save命令可立即进行一次持久化保存。save命令在执行期间会阻塞redis-server进程,直至持久化过程完毕。而在redis-server进程阻塞期间,Redis不能处理任何读写请求,无法对外提供服务。

4.2.1.2 手动bgsave命令

通过在redis-cli客户端中执行bgsave命令可立即进行一次持久化保存。不同于save命令的是,正如该命令的名称一样,background save,后台运行save。bgsave命令会使服务器进程redis-server生成一个子进程,由该子进程负责完成保存过程。在子进程进行保存过程中,不会阻塞redis-server进程对客户端读写请求的处理。

4.2.1.3 自动条件触发

自动条件触发的本质仍是bgsave命令的执行。只不过是用户通过在配置文件中做相应的设置后,Redis会根据设置信息自动调用bgsave命令执行。具体配置方式,后面会详解。

4.2.1.4 查看持久化时间

通过lastsave命令可以查看最近一次执行持久化的时间,其返回的是一个Unix时间戳。

4.2.2 RDB优化配置

RDB相关的配置在redis.conf文件的SNAPSHOTTING部分。

4.2.2.1 save

该配置用于设置快照的自动保存触发条件,即save point,保存点。该触发条件是在指定时间段内发生了指定次数的写操作。除非另有规定,默认情况下持久化条件为save 3600 1 300 100 60 10000。其等价于以下三条:

  • save 3600 1 # 在3600秒(1小时)内发生1次写操作
  • save 300 100 # 在300秒(5分钟)内发生100次写操作
  • save 60 10000 # 在60秒(1分钟)内发生1万次写操作

如果不启用RDB持久化,只需设置save的参数为空串即可:save “”。

4.2.2.2 stop-write-on-bgsave-error

默认情况下,如果RDB快照已启用(至少一个保存点),且最近的bgsave命令失败,Redis将停止接受写入。这样设置是为了让用户意识到数据没有正确地保存到磁盘上,否则很可能没有人会注意到,并会发生一些灾难。当然,如果bgsave命令后来可以正常工作了,Redis将自动允许再次写入。

4.2.2.3 rdbcompression

当进行持久化时启用LZF压缩字符串对象。虽然压缩RDB文件会消耗系统资源,降低性能,但可大幅降低文件的大小,方便保存到磁盘,加速主从集群中从节点的数据同步。

4.2.2.4 rdbchecksum

从RDB5开始,RDB文件的CRC64校验和就被放置在了文件末尾。这使格式更能抵抗RDB文件的损坏,但在保存和加载RDB文件时,性能会受到影响(约10%),因此可以设置为no禁用校验和以获得最大性能。在禁用校验和的情况下创建的RDB文件的校验和为零,这将告诉加载代码跳过校验检查。默认为yes,开启了校验功能。

4.2.2.5 sanitize-dump-payload

该配置用于设置在加载RDB文件或进行持久化时是否开启对zipList、listPack等数据的全面安全检测。该检测可以降低命令处理时发生系统崩溃的可能。其可设置的值有三种选择:

  • no:不检测
  • yes:总是检测
  • clients:只有当客户端连接时检测。排除了加载RDB文件与进行持久化时的检测。

默认值本应该是clients,但其会影响Redis集群的工作,所以默认值为no,不检测。

4.2.2.6 dbfilename

指定RDB文件的默认名称,默认为dump.rdb。

4.2.2.7 rdb-del-sync-files

  主从复制时,是否删除用于同步的从机上的RDB文件。默认是no,不删除。不过需要注意,只有当从机的RDB和AOF持久化功能都未开启时才生效。

4.2.2.8 dir

指定RDB与AOF文件的生成目录。默认为Redis安装根目录。

4.2.3 RDB文件结构

RDB持久化文件dump.rdb整体上有五部分构成:

4.2.3.1 SOF

SOF是一个常量,一个字符串REDIS,仅包含这五个字符,其长度为5。用于标识RDB文件的开始,以便在加载RDB文件时可以迅速判断出文件是否是RDB文件。

4.2.3.2 rdb_version

这是一个整数,长度为4字节,表示RDB文件的版本号。

4.2.3.3 EOF

EOF是一个常量,占1个字节,用于标识RDB数据的结束,校验和的开始。

4.2.3.4 check_sum

校验和check_sum用于判断RDB文件中的内容是否出现数据异常。其采用的是CRC校验算法。 CRC校验算法: 在持久化时,先将SOF、rdb_version及内存数据库中的数据快照这三者的二进制数据拼接起来,形成一个二进制数(假设称为数a),然后再使用这个a除以校验和check_sum,此时可获取到一个余数b,然后再将这个b拼接到a的后面,形成databases。 在加载时,需要先使用check_sum对RDB文件进行数据损坏验证。验证过程:只需将RDB文件中除EOF与check_sum外的数据除以check_sum。只要除得的余数不是0,就说明文件发生损坏。当然,如果余数是0,也不能肯定文件没有损坏。 这种验证算法,是数据损坏校验,而不是数据没有损坏的校验。

4.2.3.5 databases

databases部分是RDB文件中最重要的数据部分,其可以包含任意多个非空数据库。而每个database又是由三部分构成:

  • SODB:是一个常量,占1个字节,用于标识一个数据库的开始。
  • db_number:数据库编号。
  • key_value_pairs:当前数据库中的键值对数据。

每个key_value_pairs又由很多个用于描述键值对的数据构成。

  • VALUE_TYPE:是一个常量,占1个字节,用于标识该键值对中value的类型。
  • EXPIRETIME_UNIT:是一个常量,占1个字节,用于标识过期时间的单位是秒还是毫秒。
  • time:当前key-value的过期时间。

4.2.4 RDB持久化过程

对于Redis默认的RDB持久化,在进行bgsave持久化时,redis-server进程会 fork出一个bgsave子进程,由该子进程以异步方式负责完成持久化。而在持久化过程中,redis-server进程不会阻塞,其会继续接收并处理用户的读写请求。 bgsave子进程的详细工作原理如下: 由于子进程可以继承父进程的所有资源,且父进程不能拒绝子进程的继承权。所以,bgsave子进程有权读取到redis-server进程写入到内存中的用户数据,使得将内存数据持久化到dump.rdb成为可能。 bgsave子进程在持久化时首先会将内存中的全量数据copy到磁盘中的一个RDB临时文件,copy结束后,再将该文件rename为dump.rdb,替换掉原来的同名文件。 不过,在进行持久化过程中,如果redis-server进程接收到了用户写请求,则系统会将内存中发生数据修改的物理块copy出一个副本。等内存中的全量数据copy结束后,会再将副本中的数据copy到RDB临时文件。这个副本的生成是由于Linux系统的写时复制技术(Copy-On-Write)实现的。

| 写时复制技术是Linux系统的一种进程管理技术。 原本在Unix系统中,当一个主进程通过fork()系统调用创建子进程后,内核进程会复制主进程的整个内存空间中的数据,然后分配给子进程。这种方式存在的问题有以下几点:

  • 这个过程非常耗时
  • 这个过程降低了系统性能
  • 如果主进程修改了其内存数据,子进程副本中的数据是没有修改的。即出现了数据冗余,而冗余数据最大的问题是数据一致性无法保证。
现代的Linux则采用了更为有效的方式:写时复制。子进程会继承父进程的所有资源,其中就包括主进程的内存空间。即子进程与父进程共享内存。只要内存被共享,那么该内存就是只读的(写保护的)。而写时复制则是在任何一方需要写入数据到共享内存时都会出现异常,此时内核进程就会将需要写入的数据copy出一个副本写入到另外一块非共享内存区域。

4.3 AOF持久化

AOF,Append Only File,是指Redis将每一次的写操作都以日志的形式记录到一个AOF文件中的持久化技术。当需要恢复内存数据时,将这些写操作重新执行一次,便会恢复到之前的内存数据状态。

4.3.1 AOF基础配置

4.3.1.1 AOF的开启

默认情况下AOF持久化是没有开启的,通过修改配置文件中的appendonly属性为yes可以开启。

4.3.1.2 文件名配置

Redis 7在这里发生了重大变化。原来只有一个appendonly.aof文件,现在具有了三类多个文件:

  • 基本文件:可以是RDF格式也可以是AOF格式。其存放的内容是由RDB转为AOF当时内存的快照数据。该文件可以有多个。
  • 增量文件:以操作日志形式记录转为AOF后的写入操作。该文件可以有多个。
  • 清单文件:用于维护AOF文件的创建顺序,保障激活时的应用顺序。该文件只有一个。

4.3.1.3 混合式持久化开启

对于基本文件可以是RDF格式也可以是AOF格式。通过aof-use-rdb-preamble属性可以选择。其默认值为yes,即默认AOF持久化的基本文件为rdb格式文件,也就是默认采用混合式持久化。

4.3.1.4 AOF文件目录配置

为了方便管理,可以专门为AOF持久化文件指定存放目录。目录名由appenddirname属性指定,存放在redis.conf配置文件的dir属性指定的目录,默认为Redis安装目录。

4.3.2 AOF文件格式

AOF文件包含三类文件:基本文件、增量文件与清单文件。其中基本文件一般为rdb格式,在前面已经研究过了。下面就来看一下增量文件与清单文件的内容格式。

4.3.2.1 Redis协议

增量文件扩展名为.aof,采用AOF格式。AOF格式其实就是Redis通讯协议格式,AOF持久化文件的本质就是基于Redis通讯协议的文本,将命令以纯文本的方式写入到文件中。 Redis协议规定,Redis文本是以行来划分,每行以\r\n行结束。每一行都有一个消息头,以表示消息类型。消息头由六种不同的符号表示,其意义如下:

  • (+) 表示一个正确的状态信息
  • (-)  表示一个错误信息
  • (*) 表示消息体总共有多少行,不包括当前行
  • ($) 表示下一行消息数据的长度,不包括换行符长度\r\n
  • (空) 表示一个消息数据
  • (:) 表示返回一个数值

4.3.2.2 查看AOF文件

打开appendonly.aof.1.incr.aof文件,可以看到如下格式内容。 以上内容中框起来的是三条命令。一条数据库切换命令SELECT 0,两条set命令。它们的意义如下:

*2       -- 表示当前命令包含2个参数
$6       -- 表示第1个参数包含6个字符
SELECT   -- 第1个参数
$1       -- 表示第2个参数包含1个字符
0        -- 第2个参数
*3       --表示当前命令包含3个参数
$3       -- 表示第1个参数包含3个字符
set       -- 第1个参数
$3       -- 表示第2个参数包含3个字符
k11       -- 第2个参数
$3       -- 表示第3个参数包含2个字符
v11       -- 第3个参数
*3

4.3.2.3 清单文件

打开清单文件appendonly.aof.manifest,查看其内容如下: 该文件首先会按照seq序号列举出所有基本文件,基本文件type类型为b,然后再按照seq序号再列举出所有增量文件,增量文件type类型为i。 对于Redis启动时的数据恢复,也会按照该文件由上到下依次加载它们中的数据。

4.3.3 Rewrite机制

随着使用时间的推移,AOF文件会越来越大。为了防止AOF文件由于太大而占用大量的磁盘空间,降低性能,Redis引入了Rewrite机制来对AOF文件进行压缩。

4.3.3.1 何为rewrite

所谓Rewrite其实就是对AOF文件进行重写整理。当Rewrite开启后,主进程redis-server创建出一个子进程bgrewriteaof,由该子进程完成rewrite过程。其首先对现有aof文件进行rewrite计算,将计算结果写入到一个临时文件,写入完毕后,再rename该临时文件为原aof文件名,覆盖原有文件。

4.3.3.2 rewrite计算

rewrite计算也称为rewrite策略。rewrite计算遵循以下策略:

  • 读操作命令不写入文件
  • 无效命令不写入文件
  • 过期数据不写入文件
  • 多条命令合并写入文件

4.3.3.3 手动开启rewrite

Rewrite过程的执行有两种方式。一种是通过bgrewriteaof命令手动开启,一种是通过设置条件自动开启。 以下是手动开启方式: 该命令会使主进程redis-server创建出一个子进程bgrewriteaof,由该子进程完成rewrite过程。而在rewrite期间,redis-server仍是可以对外提供读写服务的。

4.3.3.4 自动开启rewrite

手动方式需要人办干预,所以一般采用自动方式。由于Rewrite过程是一个计算过程,需要消耗大量系统资源,会降低系统性能。所以,Rewrite过程并不是随时随地任意开启的,而是通过设置一些条件,当满足条件后才会启动,以降低对性能的影响。 下面是配置文件中对于Rewrite自动启动条件的设置。

  • auto-aof-rewrite-percentage:开启rewrite的增大比例,默认100%。指定为0,表示禁用自动rewrite。
  • auto-aof-rewrite-min-size:开启rewrite的AOF文件最小值,默认64M。该值的设置主要是为了防止小AOF文件被rewrite,从而导致性能下降。

自动重写AOF文件。当AOF日志文件大小增长到指定的百分比时,Redis主进程redis-server会fork出一个子进程bgrewriteaof来完成rewrite过程。 其工作原理如下:Redis会记住最新rewrite后的AOF文件大小作为基本大小,如果从主机启动后就没有发生过重写,则基本大小就使用启动时AOF的大小。 如果当前AOF文件大于基本大小的配置文件中指定的百分比阈值,且当前AOF文件大于配置文件中指定的最小阈值,则会触发rewrite。

4.3.4 AOF优化配置

4.3.4.1 appendfsync

当客户端提交写操作命令后,该命令就会写入到aof_buf中,而aof_buf中的数据持久化到磁盘AOF文件的过程称为数据同步。 何时将aof_buf中的数据同步到AOF文件?采用不同的数据同步策略,同时的时机是不同的,有三种策略:

  • always:写操作命令写入aof_buf后会立即调用fsync()系统函数,将其追加到AOF文件。该策略效率较低,但相对比较安全,不会丢失太多数据。最多就是刚刚执行过的写操作在尚未同步时出现宕机或重启,将这一操作丢失。
  • no:写操作命令写入aof_buf后什么也不做,不会调用fsync()函数。而将aof_buf中的数据同步磁盘的操作由操作系统负责。Linux系统默认同步周期为30秒。效率较高。
  • everysec:默认策略。写操作命令写入aof_buf后并不直接调用fsync(),而是每秒调用一次fsync()系统函数来完成同步。该策略兼顾到了性能与安全,是一种折中方案。

4.3.4.2 no-appendfsync-on-rewrite

该属性用于指定,当AOF fsync策略设置为always或everysec,当主进程创建了子进程正在执行bgsave或bgrewriteaof时,主进程是否不调用fsync()来做数据同步。设置为no,双重否定即肯定,主进程会调用fsync()做同步。而yes则不会调用fsync()做数据同步。 如果调用fsync(),在需要同步的数据量非常大时,会阻塞主进程对外提供服务,即会存在延迟问题。如果不调用fsync(),则AOF fsync策略相当于设置为了no,可能会存在30秒数据丢失的风险。

4.3.4.3 aof-rewrite-incremental-fsync

当bgrewriteaof在执行过程也是先将rewrite计算的结果写入到了aof_rewrite_buf缓存中,然后当缓存中数据达到一定量后就会调用fsync()进行刷盘操作,即数据同步,将数据写入到临时文件。该属性用于控制fsync()每次刷盘的数据量最大不超过4MB。这样可以避免由于单次刷盘量过大而引发长时间阻塞。

4.3.4.4 aof-load-truncated

在进行AOF持久化过程中可能会出现系统突然宕机的情况,此时写入到AOF文件中的最后一条数据可能会不完整。当主机启动后,Redis在AOF文件不完整的情况下是否可以启动,取决于属性aof-load-truncated的设置。其值为:

  • yes:AOF文件最后不完整的数据直接从AOF文件中截断删除,不影响Redis的启动。
  • no:AOF文件最后不完整的数据不可以被截断删除,Redis无法启动。

4.3.4.5 aof-timestamp-enabeld

该属性设置为yes则会开启在AOF文件中增加时间戳的显示功能,可方便按照时间对数据进行恢复。但该方式可能会与AOF解析器不兼容,所以默认值为no,不开启。

4.3.5 AOF持久化过程

AOF详细的持久化过程如下:

  1. Redis接收到的写操作命令并不是直接追加到磁盘的AOF文件的,而是将每一条写命令按照redis通讯协议格式暂时添加到AOF缓冲区aof_buf。
  2. 根据设置的数据同步策略,当同步条件满足时,再将缓冲区中的数据一次性写入磁盘的AOF文件,以减少磁盘IO次数,提高性能。
  3. 当磁盘的AOF文件大小达到了rewrite条件时,redis-server主进程会fork出一个子进程bgrewriteaof,由该子进程完成rewrite过程。
  4. 子进程bgrewriteaof首先对该磁盘AOF文件进行rewrite计算,将计算结果写入到一个临时文件,全部写入完毕后,再rename该临时文件为磁盘文件的原名称,覆盖原文件。
  5. 如果在rewrite过程中又有写操作命令追加,那么这些数据会暂时写入aof_rewrite_buf缓冲区。等将全部rewrite计算结果写入临时文件后,会先将aof_rewrite_buf缓冲区中的数据写入临时文件,然后再rename为磁盘文件的原名称,覆盖原文件。

4.4 RDB与AOF对比

4.4.1 RDB优势与不足

4.4.1.1 RDB优势

  • RDB文件较小
  • 数据恢复较快

4.4.1.2 RDB不足

  • 数据安全性较差
  • 写时复制会降低性能
  • RDB文件可读性较差

4.4.2 AOF优势与不足

4.4.2.1 AOF优势

  • 数据安全性高
  • AOF文件可读性强

4.4.2.2 AOF不足

  • AOF文件较大
  • 写操作会影响性能
  • 数据恢复较慢

4.5 持久化技术选型

  • 官方推荐使用RDB与AOF混合式持久化。
  • 若对数据安全性要求不高,则推荐使用纯RDB持久化方式。
  • 不推荐使用纯AOF持久化方式。
  • 若Redis仅用于缓存,则无需使用任何持久化技术。
举报

相关推荐

windows10安装Redis7笔记

0 条评论