持久化

Redis 提供不同级别的持久化方式

1、RDB 持久化方式:在指定的时间间隔,对数据进行快照存储

2、AOF 持久化方式:记录每次对服务器写的操作,当服务器重启时,会重新执行这些命令来恢复原始的数据,AOF 命令以 redis 协议追加保存每次写的操作到文件末尾,Redis 还能对 AOF 文件进行后台重写,使得AOF文件的体积不至于过大

3、如果只希望数据在服务器运行时存在,可以不使用任何持久化方式

4、可以同时开启两种持久化方式,在这种情况下,当 redis 重启时会优先载入 AOF 文件来恢复原始的数据,因为在通常情况下,AOF 文件保存的数据集要比 RDB 文件保存的数据集要完整

 

RDB

1、Redis DataBase Backup

2、在指定的时间间隔内,将内存中的数据集快照写入磁盘,即 Snapshot,它恢复时是将快照文件直接读到内存里

3、执行备份

(1)Redis 会单独创建(fork)一个子进程来进行持久化,先将数据写入到一个临时文件中,待持久化过程都结束,再用这个临时文件替换上次持久化好的文件

(2)整个过程中,主进程是不进行任何 I/O 操作,确保极高的性能

(3)如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,则 RDB 方式要比 AOF 方式更加的高效

(4)缺点:最后一次持久化后的数据可能丢失

4、Fork

(1)作用:复制一个与当前进程一样的进程,新进程的所有数据(变量、环境变量、程序计数器等) 数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程

(2)在 Linux 程序中,fork() 会产生一个和父进程完全相同的子进程,但子进程在此后多会 exec 系统调用,出于效率考虑,Linux 中引入写时复制技术

(3)一般情况父进程、子进程会共用同一段物理内存,只有进程空间的各段的内容要发生变化时,才会将父进程的内容复制一份给子进程

5、持久化流程

 

SNAPSHOTTING

1、转储数据库的文件名

dbfilename dump.rdb

2、工作目录

dir ./

(1)DB 将被写在这个目录中,文件名是用 dbfilename 配置指令指定的

(2)Append Only File 也将在这个目录下创建

(3)注意,必须在这里指定一个目录,而不是一个文件名

(4)默认为当前目录

3、将 .rdb 数据库保存到磁盘

(1)如果发生给定的秒数、给定的对 DB 的写操作数,Redis 将保存 DB

save <seconds> <changes>

(2)可以用一个空字符串参数完全禁用快照功能

save ""

(3)除非另有规定,默认情况下 Redis 会保存数据库,可以通过取消对以下三行的注释来明确设置

(4)在 3600秒(1小时)之后,至少有 1 个 key 被改变

save 3600 1

(5)在 300秒(5分钟)之后,至少有 100 个 key 被改变

save 300 100

(6)在 60 秒后,至少有 10000 个 key 被改变

save 60 10000

(7)默认 Redis 停机时,执行一次 RDB

4、默认情况下,如果启用 RDB 快照(至少有一个保存点),并且最近一次后台保存失败,Redis 将停止接受写操作

stop-writes-on-bgsave-error yes

(1)这将使用户意识到数据没有正确地持久化在磁盘上

(2)如果后台保存过程将再次开始工作,Redis 将自动允许再次写入

(3)然而,如果已经设置对 Redis 服务器和持久性的适当监控,可能会禁用这个功能,这样即使磁盘、权限等出现问题,Redis 也会继续照常工作

5、转储 .rdb 数据库时,使用 LZF 压缩字符串对象

rdbcompression yes

(1)默认情况下,启用压缩

(2)如果需要在保存过程中节省一些 CPU 资源,将其设置为 no,但如果有可压缩的 key 或 value,数据集可能会更大

6、在存储快照后,可以让 Redis 使用 CRC64 算法来进行数据校验

rdbchecksum yes

(1)从 RDB 的第 5 个版本开始,CRC64 校验码被放在文件的最后

(2)在保存和加载 RDB 文件时,会有性能上的损失(大约 10%),所以可以禁用它以获得最大的性能

(3)在禁用校验和的情况下,创建的 RDB 文件的校验和为零,这将告诉加载代码跳过检查

 

SAVE

1、执行一个同步操作,以 RDB 文件的方式,保存所有数据的快照

2、很少在生产环境直接使用 SAVE,因为它会阻塞所有的客户端的请求

(1)可以使用 BGSAVE 代替

(2)如果在 BGSAVE 命令的保存数据的子进程发生错误时,用 SAVE 命令保存最新的数据是最后的手段

3、命令成功返回 OK

 

BGSAVE 

1、后台保存 DB

2、立即返回 OK 状态码

3、Redis forks,父进程继续提供服务以供客户端调用,子进程将 DB 数据保存到磁盘然后退出

4、如果操作成功,可以通过客户端命令 LASTSAVE 来检查操作结果

 

LASTSAVE

1、执行成功时,返回 UNIX 时间戳

2、客户端执行 BGSAVE 命令时,可以通过每 N 秒发送一个 LASTSAVE 命令,来查看 BGSAVE 命令执行的结果,由 LASTSAVE 返回结果的变化可以判断执行结果

 

.rdb

1、备份

(1)通过 config get dir,查询 .rdb 文件所在目录

(2)拷贝 .rdb 文件

2、恢复

(1)关闭 Redis

(2)cp 命令,将备份文件拷贝到工作目录下

(3)启动 Redis,备份数据会直接加载

 

RDB 优点

1、适合大规模的数据恢复

2、对数据完整性、一致性要求不高更适用

3、节省磁盘空间

4、恢复速度快

 

RDB 缺点

1、Fork 时,内存中的数据被克隆一份,需要考虑大约 2 倍的膨胀性

2、虽然 Redis 在 fork 时使用写时拷贝技术,但如果数据庞大,仍消耗较多性能

3、在一定间隔时间做一次备份,所以如果 Redis 意外关闭,就会丢失最后一次快照后的所有修改

 

AOF

1、Append Only File

2、以日志的形式来记录每个写操作(增量保存)

(1)记录 Redis 执行过的所有写指令,不记录读操作

(2)只允许追加文件,但不可以改写文件

(3)Redis 启动时会读取该文件重新构建数据,即 Redis 重启时,根据日志文件的内容,将写指令从前到后执行一次,以完成数据的恢复工作

3、持久化流程

(1)客户端的请求写命令会被 append 到 AOF 缓冲区内

(2)AOF 缓冲区根据 AOF 持久化策略,将操作 sync 到磁盘的 AOF 文件中

(3)AOF 文件大小超过重写策略或手动重写时,会对 AOF 文件 rewrite,压缩 AOF 文件容量

(4)Redis 服务重启时,会重新 load AOF 文件中的写操作,达到数据恢复的目的

 

APPEND ONLY MODE

1、默认情况下,不启用 AOF

appendonly no

(1)Append Only File 提供了更好的持久性

(2)AOF、RDB 可以同时启用,如果 AOF 在启动时被启用,Redis 将加载 AOF

2、AOF 文件名

appendfilename "appendonly.aof"

3、同步频率设置

# appendfsync always
appendfsync everysec
# appendfsync no

(1)no:不主动进行同步,把同步时机交给操作系统,更快

(2)always:始终同步,每次 Redis 写入都会立刻记入日志,性能较差但数据完整性比较好

(3)everysec:每秒同步,每秒记入日志一次,如果宕机,本秒的数据可能丢失

(4)默认是 everysec,因为这通常是速度和数据安全之间的正确妥协

(5)如果不确定模式,请使用 everysec

4、当 BGSAVE 或 BGREWRITEAOF 正在进行时,它将阻止主进程调用 fsync()

no-appendfsync-on-rewrite no

(1)当 AOF fsync 策略被设置为 everysec 或 always,并且后台保存进程(后台保存或 AOF 日志后台重写)正在对磁盘执行大量 I/O,在一些 Linux 配置中,Redis 可能在 fsync() 调用中阻塞太长时间,目前还没有解决这个问题,因为即使在不同的线程中执行 fsync 也会阻塞同步 write(2) 调用

(2)当另一个子程序正在保存时,Redis 耐久性与 appendfsync none 相同,在实际操作中,这意味着在最坏的情况下,有可能损失多达 30 秒的日志(在默认 Linux 设置下)

(3)如果有延迟的问题,把它改为 yes,否则就把它设为 no,从持久性的角度看,这是最安全的选择

5、自动重写 AOF 文件

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

(1)当 AOF 日志大小增长到指定的百分比时,Redis 能够自动重写日志文件,隐式调用 BGREWRITEAOF

(2)Redis 会记住最近一次重写后 AOF 文件的大小(如果重启后没有发生重写,则使用启动时 AOF 的大小),记为 base

(3)这个基础大小与当前大小进行比较,如果当前的大小大于指定的百分比,就会触发重写

(4)另外还需要为要重写的 AOF 文件指定一个最小的尺寸,可以避免重写 AOF 文件,即使达到增加的百分比,但还是相当小

(5)指定百分比为 0,禁用自动 AOF 重写功能

(6)Redis 的 AOF 当前大小 >= base + base * 100%(默认),且当前大小 >= 64mb(默认)情况下,Redis 会对 AOF 进行重写 

 

.aof

1、备份、恢复与 RDB 一样

(1)拷贝备份文件

(2)需要恢复时,再拷贝到 Redis 工作目录下,启动系统即加载

2、正常恢复

(1)修改默认的 appendonly no,改为 yes

(2)将有数据的 .aof 文件复制一份,保存到工作目录(查看目录:config get dir)

(2)重启 Redis,然后重新加载

3、异常恢复

(1)修改默认的 appendonly no,改为 yes

(2)AOF 文件损坏,通过 /usr/local/bin/redis-check-aof --fix appendonly.aof 进行恢复

(3)备份被写坏的 AOF 文件

(4)重启 Redis,然后重新加载

4、AOF 文件损坏

(1)服务器可能在程序正在对 AOF 文件进行写入时停机,如果停机造成 AOF 文件出错(corrupt),那么 Redis 在重启时会拒绝载入这个 AOF 文件,从而确保数据的一致性不会被破坏

(2)为现有的 AOF 文件创建一个备份

(3)使用 Redis 附带的 redis-check-aof 程序,对原来的 AOF 文件进行修复

(4)redis-check-aof --fix appendonly.aof

(5)(可选)使用 diff -u 对比修复后的 AOF 文件和原始 AOF 文件的备份,查看两个文件之间的不同之处

(6)重启 Redis 服务器,等待服务器载入修复后的 AOF 文件,并进行数据恢复

 

Rewrite 压缩

1、AOF 采用文件追加方式,文件会越来越大

(1)为避免出现此种情况,新增重写机制,当 AOF 文件的大小超过所设定的阈值时,Redis 就会启动 AOF 文件的内容压缩,只保留可以恢复数据的最小指令集

(2)可以主动调用命令 bgrewriteaof

2、重写原理

(1)AOF 文件持续增长而过大时,会 fork 出一条新进程来将文件重写,也是先写临时文件最后再 rename

(2)Redis 4.0 版本后的重写,是指把 .rdb 快照,以二级制的形式附在新的 .aof 头部,作为已有的历史数据,替换掉原来的流水账操作

3、重写流程

(1)bgrewriteaof 触发重写,判断是否当前有 bgsave 或 bgrewriteaof 在运行,如果有,则等待该命令结束后再继续执行

(2)主进程 fork 出子进程执行重写操作,保证主进程不会阻塞

(3)子进程遍历 Redis 内存中数据到临时文件,客户端的写请求同时写入 aof_buf(缓冲区)、aof_rewrite_buf(重写缓冲区),保证原 AOF 文件完整,以及新 AOF 文件生成期间,新的数据修改动作不会丢失

(4)子进程写完新的 AOF 文件后,向主进程发信号,父进程更新统计信息,主进程把 aof_rewrite_buf 中的数据写入到新的 AOF 文件

(5)使用新的 AOF 文件覆盖旧的 AOF 文件,完成 AOF 重写

 

重写阻塞

1、Redis 将 AOF 重写程序放到(后台)子进程中执行

(1)子进程进行 AOF 重写期间,主进程可以继续处理命令请求

(2)子进程带有主进程的数据副本,使用子进程而不是线程,可以在避免锁的情况下,保证数据的安全性

(3)问题:因为子进程在进行 AOF 重写期间,主进程还需要继续处理命令,而新的命令可能对现有的数据进行修改,这会让当前数据库的数据和重写后的 AOF 文件中的数据不一致

(4)解决:Redis 增加一个 AOF 重写缓存,这个缓存在 fork 出子进程之后开始启用,Redis 主进程在接到新的写命令之后,除了会将这个写命令的协议内容,追加到现有的 AOF 文件之外,还会追加到这个缓存中

2、当子进程在执行 AOF 重写时,主进程需要执行以下三个工作

(1)处理命令请求

(2)将写命令追加到现有的 AOF 文件中

(3)将写命令追加到 AOF 重写缓存中

3、可保证

(1)现有的 AOF 功能会继续执行,即使在 AOF 重写期间发生停机,也不会有任何数据丢失

(2)所有对数据库进行修改的命令都会被记录到 AOF 重写缓存中

4、当子进程完成 AOF 重写之后,它会向父进程发送一个完成信号,父进程在接到完成信号之后,会调用一个信号处理函数,并完成以下工作

(1)将 AOF 重写缓存中的内容全部写入到新 AOF 文件中

(2)对新的 AOF 文件进行改名,覆盖原有的 AOF 文件

(3)当(1)执行完毕之后, 现有 AOF 文件、新 AOF 文件、数据库三者的状态就完全一致

(4)当(2)执行完毕之后, 程序就完成新、旧两个 AOF 文件的交替

5、这个信号处理函数执行完毕之后,主进程就可以继续像往常一样接受命令请求

6、在整个 AOF 后台重写过程中,只有重写缓存写入新的 AOF 文件、改名操作会造成主进程阻塞,在其他时候,AOF 后台重写都不会对主进程造成阻塞,这将 AOF 重写对性能造成的影响降到最低

7、说明:重写时并不影响 AOF 持久化正常执行,也不影响现有的 aof 缓存区、.aof 文件

(1)简化 AOF 持久化的正常过程:新命令 -> 缓存区 -> .aof 文件

(2)在执行重写时,而又有新命令,就只是在新命令 -> 缓存区,这一过程的之间把命令复制一份到重写缓存区中

(3)事实上每次有新命令写入缓存区时,都会检查是否在重写,以判断是否需要写多一份到重写缓存区

(4)但是两个缓存区依然很难保持一致,虽然两个缓存区在新命令 -> 缓存区,这一步之后看上去是一致的,但是这是暂时的

(5)因为 aof 缓存区在写到 .aof 文件中之后,会被清空或直接指向一片新的内存空间,以便确保有足够的空间继续接受新的命令,显然,这之后两个缓存区就不再一致

(6)aof 重写缓存区会一直保持从重写开始到结束所有写命令

(7)aof 缓存区会不断重复,写入命令 -> 冲洗到 .aof 文件 -> 清除 -> 写入命令,所以只会保存一部分的命令

(8)假如只保留一个缓存区,就可能有以下麻烦

(9)没有办法很好分离两个功能,互不影响

(10)标识重写过程中新增命令变得麻烦

(11)内存利用不够充分

 

AOF 优点

1、备份机制更稳健,丢失数据概率更低

2、可读的日志文本,通过操作 AOF 文件,可以处理误操作

 

AOF 缺点

1、相比 RDB,占用更多的磁盘空间

2、恢复备份速度要慢

3、每次读写都同步,有一定的性能压力

4、存在个别 Bug,造成不能恢复

 

选择持久化

1、如果只希望数据在服务器运行时存在,可以不使用任何持久化方式,即只做缓存

2、如果对数据不敏感,可以选单独使用 RDB

3、同时开启两种持久化方式

(1)在这种情况下,当 Redis 重启时会优先载入 AOF 文件来恢复原始的数据,因为在通常情况下 AOF 文件保存的数据集,要比 RDB 文件保存的数据集要完整

(2)RDB 数据不实时,同时使用两者时,服务器重启也只会找 AOF 文件

4、建议不只使用 AOF

(1)因为 RDB 更适合用于备份数据库,AOF 不断变化不容易备份

(2)RDB 适合快速重启,而且不会有 AOF 可能潜在 bug

5、性能建议

(1)RDB 文件只用作后备用途,建议只在 Slave 上持久化 RDB 文件,只保留 save 900 1

(2)如果使用 AOF,在最恶劣情况下也只会丢失不超过两秒数据

(3)AOF 代价:持续 I/O,rewrite 过程中产生的新数据,写到新文件造成的阻塞几乎是不可避免的

(4)建议 AOF 重写的基础大小设置到 5GB 以上,超过原大小 100% 大小时重写,可以改到适当的数值

Redis 7.0 持久化:Redis persistence | Redis

posted @   半条咸鱼  阅读(231)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示