Loading

Redis持久化

本篇博客是对《Redis设计与实现》的学习和总结
日期:2020-12-15
Redis版本:3.0.6

Redis持久化的方式

RDB持久化

RDB持久化将数据库数据写入到RDB文件中,在Redis重新启动的时候会自动解析RDB文件,恢复数据库数据到内存中。

  1. RDB持久化的相关命令
save

save命令会阻塞Redi直到RDB文件写入完成,在阻塞期间Redis不能处理任何命令

bgsave

Redis执行fork创建一个子进程,由子进程来执行RBD文件的写入,而父进程可以继续处理命令。Redis内部所有涉及RDB的操作都采用 bgsave 的方式。

子进程并不会有父进程的内存复制,也就是说bgsave命令不会使Redis占用的内存翻倍。因为操作系统会对创建子进程的操作做了优化,在刚开始时,父子进程共享相同的内存,直到父进程或子进程对内存进行写入之后,对被写入的内存进行复制。执行bgsave的子进程不会写内存,所以只有在父进程写内存的时候才会复制被写入的内存。

  1. 自动执行持久化
save seconds changes 

如果在 seconds 秒内发生了 changes 次修改的话,就执行一次bgsave。用伪代码表示如下:

lastSaveTime # 上一次执行 save 或 bgsave 的时间戳
current # 现在的时间戳
currentChanges # 从lastSaveTime 到 current 期间内的修改次数

if (currentChanges >= changes && (current - lastSaveTime) > seconds) {
	# 执行 bgsave
}

这里的修改次数并不是被修改的键的个数,比如, set aaa 111算作一次修改,但是lpush list 111 222 333算作 3 次修改。

如果配置多个 save 配置项,只要满足其中任何一个,就会执行 bgsave。以下是 Redis 的默认配置:

save 900 1 # 15分钟内有至少1次修改
save 300 10 # 5分钟内有至少10次修改
save 60 10000 # 1分钟内有至少1万次修改

AOF持久化

AOF(append only file)持久化是将Redis的写命令全部追加到文件中,在重启恢复数据库的数据时,只要重新执行这些写命令就可以了。

  1. AOF持久化的步骤
    AOF持久化功能可以分为三步:
  • 命令追加:在执行完一个写命令之后,将这个命令添加到AOF缓冲区
  • 文件写入:在执行完命令之后,如果AOF缓冲区中有有内容,将其写入到AOF文件中
  • 文件同步:根据配置项appendfsync的配置决定是否进行同步

文件写入和文件同步的区别:文件写入就是调用 write函数试图将数据写入到文件中,但是操作系统为了提高效率,会先将数据保存在一个缓冲区里面,等到缓冲区被填满或者超过时限,才真正将缓冲区里的数据写入到磁盘中。文件同步就是强制操作系统将缓冲区的内容立即写入磁盘中,操作系统提供 fsyncfdatasync函数进行文件同步。

appendfsync配置项的可选值:

  • always:每一次执行写命令都会进行文件同步,同步完成后才会返回
  • everysec:每秒进行一次同步,文件写入后就会返回,有专门线程每秒进行一次同步
  • no:不强制进行同步,让操作系统决定什么时候同步
  1. AOF文件重写
    AOF文件不断追加命令会越来越庞大,比如对于一个列表键可能会保存以下命令:
rpush list 111
rpush list 222
rpush list 333
lpop list

那么最终这个列表键的内容是

1) "222"
2) "333"

对于恢复数据库数据来说,只要rpush list 222 333命令就可以达到相同的效果,而且占用更少的磁盘空间,恢复数据时也执行更少的命令。
bgrewriteaof命令就是将内存中的所有数据都写成添加命令存到AOF文件中,这样就可以让AOF文件变小。
bgrewriteaof命令执行流程如下如所示:

(1) bgrewriteaof也是由子进程去执行,父进程继续处理命令。
(2) 子进程会创建一个新的AOF文件,将数据库中的数据写成添加命令写入这个新的AOF文件。
(3) 父进程继续处理命令,仍然将修改命令添加到旧的AOF文件中,除此之外还会将重写期间内的修改命令添加到重写缓冲区中。
(4) 子进程重写完成后,父进程将重写缓冲区中的内容写入到新AOF文件中
(5) 对文件改名使用新AOF文件覆盖旧AOF文件,完成AOF重写。

在子进程执行期间,因为父进程还在执行命令,所以如果没有重写缓冲区,新的AOF文件将缺少子进程执行期间内的修改操作。而且在子进程执行期间,父进程也会将写命令写入到旧AOF文件中,如果这期间发生事故也可以用旧AOF文件恢复。

bgrewriteaof也可以通过配置项自动触发,配置项和其默认值如下:

auto-aof-rewrite-percentage 100 # 当前AOF文件大小和上一次重写后AOF文件大小的增长百分比
auto-aof-rewrite-min-size 64mb # 触发bgrewriteaof最小的AOF文件大小

触发条件伪代码如下:

aof_current_size # 当前AOF文件大小
aof_base_size # 上一次重写后AOF文件大小

if ( (aof_current_size > auto-aof-rewrite-min-size) 
	&& (aof_current_size - aof_base_size) * 100 / aof_base_size >= auto-aof-rewrite-percentage) ) {

}

RDB与AOF

  1. RDB文件更加紧凑体积要比AOF文件小,使用RDB文件恢复数据也比AOF文件要快,Redis的主从复制功能就传输的是RDB文件
  2. 如果发生事故RDB会比AOF丢失更多数据,RDB持久化根据save配置隔一段时间执行一次(不能过于频繁而影响性能),而AOF持久化每一个修改命令都会写入AOF文件,如果appendfsync配置为 everysec,最多丢失1秒的数据
  3. RDB文件一旦被创建就不会再被修改了,所以很容易对RDB文件进行复制来备份数据
  4. AOF文件中存的是Redis命令(以Redis协议的格式),所以人很容易看懂
  5. 如果RDB持久化和AOF持久化都被打开,Redis启动时会优先使用AOF文件进行数据恢复,因为AOF文件保存的数据更加完整

参考资料

  • 《Redis设计与实现》
  • 《Redis开发与运维》
  • Redis中文文档
posted @ 2020-12-17 21:56  暮雨今夕  阅读(119)  评论(0)    收藏  举报