乐趣区

Redis持久化存储详解(一)

为什么要做持久化存储?
持久化存储是将 Redis 存储在内存中的数据存储在硬盘中,实现数据的永久保存。我们都知道 Redis 是一个基于内存的 nosql 数据库,内存存储很容易造成数据的丢失,因为当服务器关机等一些异常情况都会导致存储在内存中的数据丢失。
持久化存储分类
在 Redis 中,持久化存储分为两种。一种是 aof 日志追加的方式,另外一种是 rdb 数据快照的方式。
RDB 持久化存储
什么是 RDB 持久化存储
RDB 持久化存储即是将 redis 存在内存中的数据以快照的形式保存在本地磁盘中。
.RDB 持久化存储分为自动备份和手动备份
1. 手动备份通过 save 命令和 bgsave 命令。save 是同步阻塞,而 bgsave 是非阻塞(阻塞实际发生在 fork 的子进程中)。因此,在我们实际过程中大多是使用 bgsave 命令实现备份.
redis> SAVE
OK
redis> BGSAVE
Background saving started
2. 自动备份 a. 修改配置项 save m n 即表示在 m 秒内执行了 n 次命令则进行备份.b. 当 Redis 从服务器项主服务器发送复制请求时,主服务器则会使用 bgsave 命令生成 rbd 文件,然后传输给从服务器.c. 当执行 debug reload 命令时也会使用 save 命令生成 rdb 文件.d. 当使用 shutdown 命令关掉服务时,如果没有启用 aof 方式实现持久化则会采用 bgsave 的方式做持久化. 同时 shutdown 后面可以加备份参数[nosave|save].
bgsave 持久化存储实现原理
1. 执行 bgsave 命令,Redis 父进程判断当前是否存在正在执行的子进程,如果存在则直接返回.2. 父进程 fork 一个子进程(fork 的过程中会造成阻塞的情况), 这个过程可以使用 info stats 命令查看 latest_fork_usec 选项, 查看最近一次 fork 操作小号的时间, 单位是微妙.3. 父进程 fork 完之后, 则会返回 Background saving started 信息提示, 此时 fork 阻塞解除.4.fork 出的子进程开始根据父进程内存数据生成临时的快照文件,然后替换原文件. 使用 lastsave 命令可以查看最后一次生成 rdb 的时间,对应 info 的 rdb_last_save_time 选项.5. 当备份完毕之后向父进程发送完成信息,具体可以见 info Persistence 下的 rbd_* 选项.
RDB 持久化的优势与劣势
优势:1. 文件实现的数据快照,全量备份,便于数据的传输. 比如我们需要把 A 服务器上的备份文件传输到 B 服务器上面,直接将 rdb 文件拷贝即可.2. 文件采用压缩的二进制文件,当重启服务时加载数据文件,比 aof 方式更快. 劣势:1.rbd 采用加密的二进制格式存储文件,由于 Redis 各个版本之间的兼容性问题也导致 rdb 由版本兼容问题导致无法再其他的 Redis 版本中使用.2. 时效性差,容易造成数据的不完整性. 因为 rdb 并不是实时备份,当某个时间段 Redis 服务出现异常,内存数据丢失,这段时间的数据是无法恢复的,因此易导致数据的丢失.
RDB 文件常见的处理方式
1. 当遇到磁盘写满情况,可以使用如下命令来切换存储磁盘
// dirName 则是新的存储目录名(该方式同样适用于 aof 格式)
config set dir dirName
2. 文件压缩处理,虽然对 CPU 具有消耗,但是减少体积的暂用,同时做文件传输 (主从复制) 也减少消耗.
// 修改压缩开启或关闭
config set rdbcompression yes|no
3.rbd 备份文件损坏检测. 可以使用 redis-check-rdb 工具检测 rdb 文件, 该工具默认在 /usr/local/bin/ 目录下面.
[root@syncd redis-data]# /usr/local/bin/redis-check-rdb ./6379-rdb.rdb
[offset 0] Checking RDB file ./6379-rdb.rdb
[offset 26] AUX FIELD redis-ver = ‘5.0.3’
[offset 40] AUX FIELD redis-bits = ’64’
[offset 52] AUX FIELD ctime = ‘1552061947’
[offset 67] AUX FIELD used-mem = ‘852984’
[offset 83] AUX FIELD aof-preamble = ‘0’
[offset 85] Selecting DB ID 0
[offset 105] Checksum OK
[offset 105] \o/ RDB looks OK! \o/
[info] 1 keys read
[info] 0 expires
[info] 0 already expired
AOF 持久化存储
AOF 持久化存储是什么
AOF 持久化存储便是以日志的形式将 redis 存储在 aof_buf 缓冲区中的数据写入到磁盘中。简而言之,就是记录 redis 的操作日志,将 redis 执行过的命令记录下载,当我们需要数据恢复时,redis 去重新执行一次日志文件中的命令.
如何配置持久化存储
// 将 no 改为 yes,控制 aof 开启与否
appendonly no
// 控制 aof 文件名称,存储的目录便是 dir 配置项
appendfilename “appendonly.aof”
// 三种备份策略(三者只需要开启以一个即可)
# appendfsync always // 命令写入立即写入磁盘
appendfsync everysec // 每秒实现文件的同步,写入磁盘
# appendfsync no // 随机进行文件的同步, 同步操作则交给操作系统来负责,通常时间是最长 30s
AOF 持久化存储实现原理
aof 日志追加方式实现持久化存储,需要经历如下四个过程. 命令写入 -> 文件同步 -> 文件重写 -> 文件重载 1.redis 命令写入,此时会将 redis 命令写入 aof_buf 换从区.2. 缓冲区中数据根据备份策略实现写入日志文件.3. 当 aof 的文件越来越庞大,会根据我们的配置策略来实现 aof 的重写,实现文件的压缩,减少体积.4. 当 redis 重新启动时,在去重写加载 aof 文件,达到数据恢复的目的.
命令写入
命令写入主要是将文件执行过的命令写入到日志文件中. 并且日志文件尊徐文本协议格式,下面示例代码便是 aof 日志文件中存储的内容格式.
*3\r\n$3\r\nset\r\n$5\r\nhello\r\n$5\r\nworld\r\n
aof 采用的是文本协议格式。主要是原因根据资料提示,可以能使由于如下原因.1. 文本协议的兼容性好. 前面我们提及到了 rdb 文件是进行二进制加密,可能不同版本之间会出现不兼容的情况,采用文本协议可以加避免该问题。同时文本协议也可以减少跨平台使用所带来的诸多问题.2. 可读性强. 由于 aof 是将命令写入文件中,我们可以直接查看命令内容,同时也可以修改日志文件内容.3. 开启 aof 后,所有的文件文件都包含追加操作,直接采用文本协议,减少二次开销(这一点,个人不是很理解. 因为我们的 aof 是保存的是命令,当我们再次去加载的时候,会去执行一次里面的命令,当文件大的时候应该是比较耗时的吧。如果没有做好文件重写策略,大量重复无效的命令执行,对于二进制加密的 rdb 格式,不需要再去转换,这一点确实可以减少二次开销).
文件写入
文件写入是将 aof_buf 缓冲区的命令写入到文件中. 文件写入的策略有如下三种方式

配置项
配置说明

always
命令写入到 aof_buf 缓冲区中之后立即调用系统的 <font color=’red’>fsync 操作 </font> 同步到 aof 文件中,fsync 完成后线程返回.

everysec
命令写入到 aof_buf 缓冲区后 <font color=’red’> 每隔一秒 </font> 调用系统的 <font color=’red’>write 操作 </font>,write 完成后线程返回.

no
命令写入 aof_bug 缓冲区后调用系统 write 操作,不对 aof 文件做 fsync 同步,同步硬盘操作由 <font color=’red’> 系统操作 </font> 完成,时间一般最长为 30s.

系统调用 write 和 fsync 说明:·write 操作会触发延迟写(delayed write)机制。Linux 在内核提供页缓冲区用来提高硬盘 IO 性能。write 操作在写入系统缓冲区后直接返回。同步硬盘操作依赖于系统调度机制,例如:缓冲区页空间写满或达到特定时间周期。同步文件之前,如果此时系统故障宕机,缓冲区内数据将丢失.·fsync 针对单个文件操作(比如 AOF 文件),做强制硬盘同步,fsync 将阻塞直到写入硬盘完成后返回,保证了数据持久化. 文件写入策略分析配置为 always 时,每次写入都要同步 AOF 文件,在一般的 SATA 硬盘上,Redis 只能支持大约几百 TPS 写入,显然跟 Redis 高性能特性背道而驰,不建议配置. 配置为 no。由于操作系统每次同步 AOF 文件的周期不可控,而且会加大每次同步硬盘的数据量,虽然提升了性能,但数据安全性无法保证. 配置为 everysec。是建议的同步策略,也是默认配置,做到兼顾性能和数据安全性。理论上只有在系统突然宕机的情况下丢失 1 秒的数据.
文件重载
1. 为什么要文件做文件重载操作? 由于 aof 采用的是日志追加,我们 redis 命令不断的写入,aof 文件的体积也也会不断的增加. 因此 redis 引入了 aof 重写机制达到减小 aof 文件体积.<font color=”blue”>aof 文件重写是把 redis 进程内的数据转换为写命令同步到新的 aof 文件的过程(这一点其实不是特别明白,文件重写不是针对 aof 文件文件做操作的吗?为什么这里是将 redis 进程内的数据转换为命令写入文件,这里的进程内的数据不是太明白,还有待深入研究. 个人理解的就是将旧的 aof 文件内容根据重写策略,进行优化生成新的 aof 文件。).</font>2. 文件重载有什么好处? 文件重载主要优化的地方有如下三点。使用文件重载既可以减少文件的体积,同时去掉了一些无效的操作,可以加快文件重载效率.a. 将一些在进程内无效的数据不在写入新的文件. 如过期的键.b. 去掉一些无效的命令. 如 del key1.c. 简化操作. 如 lpush list a,lpush list b. 直接可以简化为 lpush list a b.3. 文件重载由那些方式? 文件重载有自动触发机制和手动触发机制. 手动触发机制: 直接使用 bgrewriteaof 命令即可. 该命令在 fork 子进程的时候会发生阻塞. 自动触发机制:auto-aof-rewrite-min-size:aof 重写时文件最小的体积,默认的是 64M.auto-aof-rewrite-percentage: 代表当前 AOF 文件空间(aof_current_size)和上一次重写后 AOF 文件空间(aof_base_size)的比值.
自动触发时机 =aof_current_size>auto-aof-rewrite-minsize&&(aof_current_size-aof_base_size)/aof_base_size>=auto-aof-rewritepercentage
其中 aof_current_size 和 aof_base_size 可以在 info Persistence 统计信息中查看.4. 文件重载实现的原理是怎样的?1. 执行重写命令,判断是否存在子进程。如果已经有子进程在进行 aof 重写,则会提示如下信息.
ERR Background append only file rewriting already in progress
如果已经存在子进程在进行 bgsave 操作,重写命令会延迟到 bgsave 命令完成之后进行,会返回如下信息.
Background append only file rewriting scheduled
2. 父进程会 fork 一个子进程,在 fork 子进程的过程中会造成阻塞.3.fork 子进程结束阻塞解除,进行其他新的命令操作. 新的命令依旧根据文件写入策略同步数据, 保证 aof 机制正确进行 (图中 3.1).4. 子进程在进行写的过程中,由于 fork 操作运用的是写时复制技术,子进程只能共享 fork 操作时内存保留的数据,新的数据是无法操作的. 父进程在这过程中仍然在响应其他的命令,于是 Redis 会使用 aof 重写缓存区来保存这部分新的数据(图中 3.2).5. 子进程进行根据重写规则将数据写入到新的 aof 文件中,并且每次写入有大小限制, 通过 aof-rewrite-incremental-fsync 配置项来控制,默认是 32M, 这样可以见减少单次刷盘(I/ O 写) 造成硬盘阻塞.6. 子进程在完成重写之后,会向父进程发送信息,父进程更新统计信息. 可参看 info persistence 下的 aof_* 相关统计。7. 父进程会把新写入存在 aof 重写缓冲区的数据写入到 aof 文件中(图 5.2).8. 将新的 aof 文件替换掉旧的 aof 文件.<font color=’blue’> 在第 3 和 4 中,其实不是特别理解. 不理解的是为什么父进程在响应新的命令会写入旧的 aof 文件,还要 aof 重写缓存区. 个人理解的是,父进程在进行新命令写入处理的策略是,按照正常的备份策略写入旧的 aof 的同时也把新的命令写入重写缓冲区,在第 5.2 中将这部分新的数据写入到新的 aof 文件中, 这样保证数据的完整性.</font>
文件重载
文件重载就是将文件重新加入到 redis 服务中. 比如 redis 服务重启用于数据恢复.redis 的重载机制非常完善,具体流程如下.
AOF 文件常见的问题处理
1. 文件损坏我们在加载损坏的文件是可能提示如下信息.
Bad file format reading the append only file: make a backup of your AOF file,then use ./redis-check-aof –fix <filename>
此时我们可以使用 redis-check-aof –fix 命令进行修复(记得对文件做个备份). 修复后使用 diff- u 进行数据对比,找出部分丢失的数据.2. 文件加载不完整这可能是数据在备份的时候,redis 服务异常,导致备份不完整. 可以使用 redis 的 aof-load-truncated 兼容该异常
AOF 的优缺点
优点: 多种文件写入 (fsync) 策略. 数据实时保存,数据完整性强. 即使丢失某些数据,制定好策略最多也是一秒内的数据丢失. 可读性强,由于使用的是文本协议格式来存储的数据, 可有直接查看操作的命令,同时也可以手动改写命令. 缺点: 文件体积过大,加载速度比 rbd 慢. 由于 aof 记录的是 redis 操作的日志, 一些无效的,可简化的操作也会被记录下来, 造成 aof 文件过大. 但该方式可以通过文件重写策略进行优化.
选择 AOF 还是 RDB 进行数据的持久化
1. 针对不同的情况来选择,建议使用两种方式相结合.2. 针对数据安全性、完整性要求高的采用 aof 方式.3. 针对不太重要的数据可以使用 rdb 方式.4. 对于数据进行全量备份,便于数据备份的可以采用 rdb 方式. 原文转自微信公众号: 浪子编程走四方

退出移动版