文章目录
- Redis 持久化
- 1 持久化基本原理
- 2 RDB(Redis DataBase) 持久化
- 2.1 持久化的执行
- 2.2 手动 save 命令
- 2.3 手动 bgsave 命令
- 2.4 自动条件触发
- 2.5 查看持久化时间
- 3 RDB 优化配置
- 3.1 save
- 3.2 stop-write-on-bgsave-error
- 3.3 rdbcompression
- 3.4 rdbchecksum
- 3.5 sanitize-dump-payload
- 3.6 dbfilename
- 3.7 rdb-del-sync-files
- 3.8 dir
- 4 RDB 文件结构
- 5 RDB 持久化过程
- 6 补充写实复制技术
Redis 持久化
- Redis 是一个内存数据库,所以其运行效率非常高。但是存在一个问题:内存中的数据是不持久的,若主机宕机或 Redis 关机重启,则内存中的数据全部丢失。Redis 具有持久化功能,其会按照设置以快照或操作日志的形式将数据持久化到磁盘。
- 根据持久化使用技术的不同,Redis 的持久化分为两种:RDB 与 AOF
1 持久化基本原理
![在这里插入图片描述](https://img-blog.csdnimg.cn/8b5f7b524e3e4fb5b5e8baa277fa98f4.png)
- Redis 持久化称为钝化,是指将内存中数据库的状态描述信息保存到磁盘中。不同的持久化技术,对数据的状态描述信息是不同的,生成的持久化文件也是不同的。但作用都是相同的:避免数据意外丢失。
- 数据恢复过程也称为激活。通过手动方式,或自动定时方式,或自动条件触发方式,将内存中数据库的状态描述信息写入到指定的持久化文件中。当系统重新启动时,自动加载持久化文件,并根据文件中数据库状态描述信息将数据恢复到内存中。
- 钝化与激活的过程就是 Redis 持久化的基本原理。
- 对于 Redis 单机状态下,无论是手动方式,还是定时方式或条件触发方式,都存在数据丢失问题:在尚未手动/自动保存时发生了 Redis 宕机状况,那么从上次保存到宕机期间产生的数据就会丢失。不同的持久化方式,其数据的丢失率也是不同
- RDB 是默认持久化方式,但 Redis 允许 RDB 与 AOF 两种持久化技术同时开启,此时系统会使用 AOF 方式做持久化,即 AOF 持久化技术的优先级要更高。同样两种技术同时开启状态下,系统启动时若两种持久化文件同时存在,则优先加载 AOF持久化文件。
2 RDB(Redis DataBase) 持久化
- RDB是指将内存中某一时刻的数据快照全量写入到指定的 rdb 文件的持久化技术。
- RDB 持久化默认是开启的,当 Redis 启动时会自动读取 RDB 快照文件,将数据从硬盘载入到内存,以恢复 Redis 关机前的数据库状态
2.1 持久化的执行
- RDB 持久化的执行有三种方式:手动 save 命令、手动 bgsave 命令,与自动条件触发
2.2 手动 save 命令
- 通过在 redis-cli 客户端中执行 save 命令可立即进行一次持久化保存。
- **save 命令在执行期间会阻塞 redis-server 进程,直至持久化过程完毕。**而在 redis-server 进程阻塞期间,Redis不能处理任何读写请求,无法对外提供服务。
2.3 手动 bgsave 命令
- background save,后台运行 save。
- bgsave 命令会使服务器进程 redis-server 生成一个子进程,由该子进程负责完成保存过程。在子进程进行保存过程中,不会阻塞 redis-server 进程对客户端读写请求的处理
- 通过在 redis-cli 客户端中执行 bgsave 命令可立即进行一次持久化保存。
2.4 自动条件触发
- 自动条件触发的本质仍是 bgsave 命令的执行。用户通过在配置文件中做相应的设置后,Redis 会根据设置信息自动调用 bgsave 命令执行。
2.5 查看持久化时间
- 通过 lastsave 命令可以查看最近一次执行持久化的时间,其返回的是一个 Unix 时间戳
3 RDB 优化配置
- RDB 相关的配置在
redis.conf
文件的SNAPSHOTTING
部分
3.1 save
# Save the DB to disk.
#保存DB到磁盘
# save <seconds> <changes> [<seconds> <changes> ...]
#
# Redis will save the DB if the given number of seconds elapsed and it
# surpassed the given number of write operations against the DB.
#如果给定的秒数过去了超过了给定的对DB的写操作数,Redis将保存数据库
#
# Snapshotting can be completely disabled with a single empty string argument
#snapshot可以用一个空字符串参数完全禁用
# as in following example:
# save ""
#
# Unless specified otherwise, by default Redis will save the DB:
# * After 3600 seconds (an hour) if at least 1 change was performed
# * After 300 seconds (5 minutes) if at least 100 changes were performed
# * After 60 seconds if at least 10000 changes were performed
#
# You can set these explicitly by uncommenting the following line.
#
# save 3600 1 300 100 60 100
#除非另有说明,默认情况下Redis会保存DB:
# * 3600秒后(一个小时),如果至少执行了一次更改
# * 在300秒(5分钟)后,如果执行了至少100次更改
# * 如果执行了至少10000次更改,则在60秒后
#你可以通过取消注释下面的行显式设置。
# save 3600 1 300 100 60 100
- 该配置用于设置快照的自动保存触发条件(save point)。该触发条件是在指定时间段内发生了指定次数的写操作。除非另有规定,默认情况下持久化条件为
save 3600 1 300 100 60 10000
# 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 " "
3.2 stop-write-on-bgsave-error
# By default Redis will stop accepting writes if RDB snapshots are enabled
# (at least one save point) and the latest background save failed.
# This will make the user aware (in a hard way) that data is not persisting
# on disk properly, otherwise chances are that no one will notice and some
# disaster will happen.
#默认情况下,如果启用RDB快照,Redis将停止接受写操作(至少一个保存点)和最新的后台保存失败。
#这将使用户意识到(以一种艰难的方式)数据没有持久化在磁盘上,否则很可能没有人会注意到灾难将会发生。
#
# If the background saving process will start working again Redis will
# automatically allow writes again.
#如果后台保存进程将重新开始工作,Redis将自动允许再次写入。
#
# However if you have setup your proper monitoring of the Redis server
# and persistence, you may want to disable this feature so that Redis will
# continue to work as usual even if there are problems with disk,
# permissions, and so forth.
#但是,如果您已经设置了适当的Redis服务器监控和持久性,你可能想要禁用这个功能,以便Redis将继续正常工作,即使磁盘有问题,permissions,等。
- 默认情况下,如果 RDB 快照已启用(至少一个保存点),且最近的 bgsave 命令失败,Redis将停止接受写入。这样设置是为了让用户意识到数据没有正确地保存到磁盘上,否则很可能没有人会注意到,并会发生一些灾难。当然,如果 bgsave 命令后来可以正常工作了,Redis将自动允许再次写入
3.3 rdbcompression
- 当进行持久化时启用 LZF 压缩字符串对象。虽然压缩 RDB 文件会消耗系统资源,降低性能,但可大幅降低文件的大小,方便保存到磁盘,加速主从集群中从节点的数据同步。
3.4 rdbchecksum
- 从 RDB5 开始,RDB 文件的 CRC64 校验和就被放置在了文件末尾。这使格式更能抵抗 RDB文件的损坏,但在保存和加载 RDB 文件时,性能会受到影响(约 10%),因此可以设置为 no禁用校验和以获得最大性能。
- 在禁用校验和的情况下创建的 RDB 文件的校验和为零,这将告诉加载代码跳过校验检查。默认为 yes,开启了校验功能。
3.5 sanitize-dump-payload
- 该配置用于设置在加载 RDB 文件或进行持久化时是否开启对 zipList、listPack 等数据的全面安全检测。该检测可以降低命令处理时发生系统崩溃的可能。其可设置的值有三种选择:
- no:不检测
- yes:总是检测
- clients:只有当客户端连接时检测。排除了加载 RDB 文件与进行持久化时的检测。
- 默认值本应该是 clients,但其会影响 Redis 集群的工作,所以默认值为 no,不检测
3.6 dbfilename
- 指定
RDB
文件的默认名称,默认为dump.rdb
3.7 rdb-del-sync-files
- 主从复制时,是否删除用于同步的从机上的 RDB 文件。默认是 no,不删除。
- 注意:只有当从机的 RDB 和 AOF 持久化功能都未开启时才生效。
3.8 dir
- 指定 RDB 与 AOF 文件的生成目录。默认为 Redis 安装根目录
4 RDB 文件结构
- RDB 持久化文件 dump.rdb 整体上有五部分构成
-
SOF:常量,一个字符串 REDIS,仅包含这五个字符,其长度为 5。用于标识 RDB文件的开始,以便在加载 RDB 文件时可以迅速判断出文件是否是 RDB 文件。
-
rdb_version:整数,长度为 4 字节,表示 RDB 文件的版本号。
-
EOF:常量,占 1 个字节,用于标识 RDB 数据的结束,校验和的开始。
-
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,也不能肯定文件没有损坏。
- 这种验证算法,是数据损坏校验,而不是数据没有损坏的校验。
- CRC 校验算法:
-
databases:可以包含任意多个非空数据库。而每个 database 又是由三部分构成:
-
SODB:是一个常量,占 1 个字节,用于标识一个数据库的开始。
-
db_number:数据库编号。
-
key_value_pairs:当前数据库中的键值对数据。
-
每个 key_value_pairs 又由很多个用于描述键值对的数据构成。
- VALUE_TYPE:是一个常量,占 1 个字节,用于标识该键值对中 value 的类型。
- EXPIRETIME_UNIT:是一个常量,占 1 个字节,用于标识过期时间的单位是秒还是毫秒。
- time:当前 key-value 的过期时间。
-
5 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)**实现的。
6 补充写实复制技术
- 写时复制技术是 Linux 系统的一种进程管理技术。
- 原本在 Unix 系统中,当一个主进程通过 fork()系统调用创建子进程后,内核进程会复制主进程的整个内存空间中的数据,然后分配给子进程。这种方式存在以下问题:
- 这个过程非常耗时
- 这个过程降低了系统性能
- 如果主进程修改了其内存数据,子进程副本中的数据是没有修改的。即出现了数据冗余,而冗余数据最大的问题是数据一致性无法保证。
- 现代的 Linux 则采用了更为有效的方式:写时复制。子进程会继承父进程的所有资源,其中就包括主进程的内存空间。即子进程与父进程共享内存。只要内存被共享,那么该内存就是只读的(写保护的)。而写时复制则是在任何一方需要写入数据到共享内存时都会出现异常,此时内核进程就会将需要写入的数据 copy 出一个副本写入到另外一块非共享内存区域。