「进击Redis」二十二、超详细解析 Redis 持久化之 RDB

34 篇文章 5 订阅
20 篇文章 0 订阅

前言

从上篇 RedisTemplate 可没你想的那么简单 完结后,整个 Redis 的客户端相关的就弄完了,主要是JedisLettuceRedisTemplate 三篇。有不熟悉的好哥哥可以去我的文章那里翻翻,说不定就会有不一样的收获。今天的这篇的话是关于 Redis 持久化相关的第一篇,后续应该会有几篇关于持久化的,好哥哥们好好看,主要是要动手操作起来。当然如果只是为了应付面试的话可以大概的看看,但是还是建议这一块相关的东西系统的看看。看完记得点赞加关注哟。

概述

Redis 系列第一篇 初识 Redis 中就有提到说 Redis 是一个基于内存的非关系性数据库。那所谓内存数据库,就是将数据库中的内容保存在内存中,这与传统的MySQLOracle等关系型数据库直接将内容保存到硬盘中相比,内存数据库的读写效率比传统数据库要快的多(内存的读写效率远远大于硬盘的读写效率)。但是保存在内存中也随之带来了一个缺点,一旦断电或者宕机,那么内存数据库中的数据将会全部丢失。
为了解决这个缺点,Redis 提供了将内存数据持久化到硬盘,以及用持久化文件来恢复数据库数据的功能。Redis 支持两种形式的持久化,一种是RDB快照(snapshotting),另外一种是AOF(append-only-file)。

RDB

rdb
RDB持久化是把当前进程数据生成快照保存到硬盘的过程。能够在指定时间间隔内对数据进行快照存储,默认情况下,Redis 将数据快照保存在dump.rdb这个二进制的文件中。触发RDB持久化过程分为手动触发和自动触发。

触发机制

上面有提到触发分为手动触发和自动触发。手动触发又分成了两种方式,第一种使用save,第二种使用bgsave

手动触发-save

save
save会阻塞当前 Redis 服务器,直到RDB过程完成为止,对于内存比较大的实例会造成长时间阻塞,线上环境不建议使用。命令如下:

127.0.0.1:6379> save
OK
手动触发-bgsave

上面提到了就是save是一个阻塞操作。假设在生产环境中使用这个命令,如果数据量够大,那么会使 Redis 服务器阻塞的时间非常长,导致 Redis 服务的不可用。bgsave 就是用来解决这个问题的,bgsave 执行时,Redis 进程会执行fork操作创建子进程,RDB 持久化过程由子进程负责,完成后自动结束。阻塞只发生在 fork 阶段,一般时间很短。

127.0.0.1:6379> bgsave
Background saving started

整个过程如下:
在这里插入图片描述

save-bgsave 对比
命令savebgsave
类型同步异步
是否阻塞只有在 fork 是阻塞的
优点没有额外的内存消耗不会阻塞服务器
缺点阻塞服务器需要 fork 创建子进程,额外消耗内存
自动触发

自动RDB
除了执行命令手动触发之外,Redis 内部还存在自动触发RDB的持久化机制。触发的逻辑是 Redis 在 N 秒内有 M 个键被改动,好哥哥们可以通过修改配置文件来实现对RDB的自动触发。默认配置如下:

## 表示 900 秒内如果至少有 1 个 key 的值变化,则触发
save 900 1
## 表示300 秒内如果至少有 10 个 key 的值变化,则触发
save 300 10
## 表示60 秒内如果至少有 10000 个 key 的值变化,则触发
save 60 10000

其他 RDB 相关配置:

## bgsave写入错误是否停止写入
stop-writes-on-bgsave-error yes
## 是否对rdb文件使用压缩格式
rdbcompression yes
## 是否对rdb文件校验
rdbchecksum yes
## rdb持久化名称
dbfilename dump.rdb
## rdb持久化存放目录
dir ./
自动触发原理

Redis 服务器维护了一个状态结构,其中包括save条件的数组(saveparams)计数器(dirty)上次保存时间(lastsave)。前面我们在 redis.conf配置文件中进行了关于save 的配置,解析成条件的数组后就是下面的样子:
saveparams
当服务器成功执行一次修改操作,那么计数器(dirty)就会加 1。而lastsave 属性记录上一次执行savebgsave的时间,Redis 服务器还有一个周期性操作函数 severCron ,默认每隔 100 毫秒就会执行一次,该函数会遍历并检查 saveparams 数组中的所有保存条件,只要有一个条件被满足,那么就会执行 bgsave 命令。 执行完成之后,计数器(dirty)更新为 0 ,lastsave也更新为执行命令的完成时间。

数据恢复

假设哪天有哪位好哥哥执行了FLUSHALL 命令(千万别再生产上使用这个命令哦),把所有数据都清了,这时不要慌将备份文件dump.rdb (前提是你的快照生成的时机在FLUSHALL之前) 移动到 Redis 安装目录并启动服务即可,Redis 就会自动加载文件数据至内存了。Redis 服务器在载入 RDB 文件期间,会一直处于阻塞状态,直到载入工作完成为止。获取 Redis 的安装目录可以使用下面的命令。

config get dir

RDB文件解析

看这个文件我已经快瞎了,所以我在解释前面都加了行号(够贴心了吧,这还不点赞加关注吗)。

➜  go-redis-parser od -A x -t x1c -v ./teststub/dumpV9.rdb
000000  52  45  44  49  53  30  30  30  39  fa  09  72  65  64  69  73
         R   E   D   I   S   0   0   0   9 372  \t   r   e   d   i   s
000010  2d  76  65  72  05  35  2e  30  2e  35  fa  0a  72  65  64  69
         -   v   e   r 005   5   .   0   .   5 372  \n   r   e   d   i
000020  73  2d  62  69  74  73  c0  40  fa  05  63  74  69  6d  65  c2
         s   -   b   i   t   s 300   @ 372 005   c   t   i   m   e 302
000030  71  8a  8d  5d  fa  08  75  73  65  64  2d  6d  65  6d  c2  30
         q 212 215   ] 372  \b   u   s   e   d   -   m   e   m 302   0
000040  e0  0f  00  fa  0c  61  6f  66  2d  70  72  65  61  6d  62  6c
       340 017  \0 372  \f   a   o   f   -   p   r   e   a   m   b   l
000050  65  c0  00  fe  00  fb  06  00  f9  00  00  01  73  01  61  f9
         e 300  \0 376  \0 373 006  \0 371  \0  \0 001   s 001   a 371
000060  03  0e  02  6c  69  01  11  11  00  00  00  0d  00  00  00  02
       003 016 002   l   i 001 021 021  \0  \0  \0  \r  \0  \0  \0 002
000070  00  00  01  61  03  01  62  ff  f9  00  02  03  73  65  74  02
        \0  \0 001   a 003 001   b 377 371  \0 002 003   s   e   t 002
000080  01  62  01  61  f9  00  0f  06  73  74  72  65  61  6d  01  10
       001   b 001   a 371  \0 017 006   s   t   r   e   a   m 001 020
000090  00  00  01  6d  70  b5  4a  7e  00  00  00  00  00  00  00  00
        \0  \0 001   m   p 265   J   ~  \0  \0  \0  \0  \0  \0  \0  \0
0000a0  40  52  52  00  00  00  18  00  03  01  00  01  02  01  84  6e
         @   R   R  \0  \0  \0 030  \0 003 001  \0 001 002 001 204   n
0000b0  61  6d  65  05  83  61  67  65  04  00  01  02  01  00  01  00
         a   m   e 005 203   a   g   e 004  \0 001 002 001  \0 001  \0
0000c0  01  87  4c  61  6d  62  65  72  74  08  1d  01  05  01  02  01
       001 207   L   a   m   b   e   r   t  \b 035 001 005 001 002 001
0000d0  f2  33  8c  00  04  00  01  84  4a  61  63  6b  05  1a  01  05
       362   3 214  \0 004  \0 001 204   J   a   c   k 005 032 001 005
0000e0  01  02  01  f2  9c  ad  00  04  00  01  83  54  6f  6d  04  1e
       001 002 001 362 234 255  \0 004  \0 001 203   T   o   m 004 036
0000f0  01  05  01  ff  03  81  00  00  01  6d  70  b5  f8  1a  00  01
       001 005 001 377 003 201  \0  \0 001   m   p 265 370 032  \0 001
000100  05  67  72  6f  75  70  00  00  00  00  f9  00  0c  04  7a  73
       005   g   r   o   u   p  \0  \0  \0  \0 371  \0  \f 004   z   s
000110  65  74  15  15  00  00  00  12  00  00  00  04  00  00  01  61
         e   t 025 025  \0  \0  \0 022  \0  \0  \0 004  \0  \0 001   a
000120  03  f2  02  01  62  03  f3  ff  f9  03  0d  01  68  11  11  00
       003 362 002 001   b 003 363 377 371 003  \r 001   h 021 021  \0
000130  00  00  0d  00  00  00  02  00  00  01  61  03  01  61  ff  ff
        \0  \0  \r  \0  \0  \0 002  \0  \0 001   a 003 001   a 377 377
000140  0e  e0  f7  31  2f  37  16  df
       016 340 367   1   /   7 026 337
000148

这是一个 version 9RDB 文件,主要表达内容如下:

魔数(Magic Number)

在第 000000前 9 个字节是一个魔数,5 个字节 REDIS 和 4 个字节的版本号 0009。

辅助字段(Aux Fields)

通用字符串字段,用于向 RDB 添加状态,Version 7 加入的,向后兼容。AUX 字段由键和值两个字符串组成。主要有以下字段:

  1. redis-ver:版本号
  2. redis-bits:OS Arch
  3. ctime:RDB 文件创建时间
  4. used-mem:使用内存大小
  5. repl-stream-db:在 server.master 客户端中选择的数据库
  6. repl-id:当前实例 replication ID
  7. repl-offset:当前实例复制的偏移量
数据库索引

000050fe(0xfe)fb(0xfb)是 10 进制的 254 和 251,在 RDB 中国分别对应SELECT_DBRESIZE_DB。 每一个 SELECTDB后都会紧跟着RESIZEDB,后者表示的是当前数据库hashtable键大小的提示,每次切换数据库时提前读到,避免不必要的rehash

数据库键值对

这里的话就列举基础数据类型

String

00005000(0x00)是 10 进制的 0,表示String类型的对象,01 指key是一个字节长度:svalue 也是一个字节长度:a

List

0000600e(0x0e)是 10 进制的 14,表示List类型的对象。 2 个字节长度的keyli,接下来分别是一个长度的itemsab

Set

000070002,表示 Set 类型对象,3 个长度 set,两个membersab

ZSet

0001000c 是 10 进制的 12,以ziplist结构存储的Sortedset 类型,4 个长度的key:zset,接下来的 4 表示:4 个元素,zset会将memberscore一起保存,所以,就是 2 组members;分别是:{memeber:"a",score:1}{member:"b",score:2}

Hash

0001200d(13)RDB_TYPE_HASH_ZIPLIST,表示是ziplist存储的hash类型数据,1 个长度的 key:hkey后面的 2,存着 hash结构的 fieldvalue;在 fieldvalue 前面的 1,分别是指各自的长度,都是 a

文件 EOF

000130ff(255) EOF,在所有数据写完结束后,会以一个EOF 结尾。

CheckSum

Version 5 开始,如果在配置文件中开启rdbchecksum yes(上面解释过这个配置),会在RDB文件的结尾处,用 8 个字节记录,通过CRC64算法计算的整个文件内容的校验和。

注意点

  1. RDB文件保存在dir配置指定的目录下,文件名通过dbfilename配置指定。可以通过执行config set dir{newDir}config setdbfilename{newFileName}运行期动态执行,当下次运行时RDB文件会保存到新目录。
  2. 当遇到坏盘或磁盘写满等情况时,可以通过config set dir{newDir}在线修改文件路径到可用的磁盘路径,之后执行bgsave进行磁盘切换,同样适用于AOF持久化文件。
  3. Redis 默认采用 LZF 算法对生成的RDB文件做压缩处理,压缩后的文件远远小于内存大小,默认开启,可以通过参数config set rdbcompression{yes|no}动态修改。
  4. 虽然压缩RDB会消耗CPU,但是能大幅降低文件的大小,方便保存到硬盘或通过网络发送给从节点,因此线上建议开启。

优点

  1. RDB文件是单一紧凑的二进制文件,比较适合做冷备,全量复制的场景。可以将一个时间内产生的RDB文件复制到本地或者存储到云端,这样可以产生多个不同时间段内的数据备份,从而达到容灾恢复。
  2. RDB对 Redis 对外提供的读写服务,影响非常小,可以让 Redis 保持高性能,因为 Redis 主进程只需要fork一个子进程,让子进程执行磁盘IO操作来进行RDB持久化即可。
  3. 相对于AOF(下篇会弄它)持久化机制来说,直接基于 RDB 数据文件来重启和恢复 Redis 进程,更加快速,因为RDB存储的就是数据,而AOF存储的是操作命令。

缺点

  1. 在 Redis 故障时,RDB 持久化丢失的数据可能会比AOF多。因为RDB是按照时间保存的快照,所以如果在这个时间段内没有执行RDB操作,那这段时间的数据就丢失了。
  2. 耗时、耗性能,RDB 持久化通常都要fork一个子进程来执行。当数据量较大时,fork的过程是比较耗时的。
  3. RDB无法实现实时或者秒级持久化。

本期就到这啦,有不对的地方欢迎好哥哥们评论区留言,另外求关注、求点赞

上一篇: RedisTemplate 可没你想的那么简单

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值