快照,就是给当前redis在内存中的数据进行拍照片,一般有条件触发拍照,比如执行save、bigsave 或某段时间内满足了写条件都会触发,当服务器重启时,根据照片将内容恢复到内存,这就是快照。
快照流程
触发快照功能,比如执行了BGSAVE命令 判断是否有子进程在进行RDB持久化 有子进程在持久化则返回,到此结束本次持久化 无子进程持久化,则fork一个子进程 子进程开始从共享内存读取数据写入临时文件 临时文件写完之后调用rename系统函数重命名临时文件为dump.rdb, rename会删除原来的dump.rdb
子进程处理快照的同时父进程继续为客户端提供服务
写时复制
父进程原来映射的物理空间 page-1, page-2, page-3
fork子进程并执行exec,此时相当于对内存拍了照片,父子进程映射同一块内存空间,内存页引用计数加1
父进程执行写操作,写的内容假设在page-2,此时发生写时复制,page-2的数据会被拷贝到page-4,然后写page-4,同时父进程断开到page-2的映射,page-2引用计数减1
父子进程共享page-1,3,其它各自管理
假设子进程结束,对应子进程的内存会根据引用计数回收
触发快照的方式
客户端向Redis发送BGSAVE命令:开辟子进程,只有在开辟子进程时短暂拒绝客户端请求,一旦子进程启动,正常处理客户请求
redis 配置触发
save 10 1 # 10s 内发生一次写操作,触发BGSAVE
# 快照允许且一旦发生快照持久化失败时,若此选项开启
# redis将不再处理客户端写请求,一旦失败恢复,依然
# 会恢复接收写请求,若不再乎数据持久化失败丢失的问题
# 可以设置该选项为 no,从而即便持久化失败也正常提供
# 服务
stop-writes-on-bgsave-error yes
# 是否开启LZF算法压缩字符串,若开启将会有更多cpu占用率
# 设置为no,节省cpu,但持久化的文件更大,cpu和空间的一个
# 折中,根据实际业务场景选择
rdbcompression yes
# 是否开启 CRC64 校验,开启后,持久化存储时
# 会计算 CRC64, 并将校验码写入到快照文件件的
# 末尾,加载时也会再次校验持久化文件,一旦校验
# 失败,不会加载文件。开启时在持久化和加载时有
# 10% 性能损耗
rdbchecksum yes
# 持久化文件的名称,默认 dump.rdb
dbfilename dump.rdb
# 持久化文件默认路径
dir var/lib/redis
复制
客户端向Redis发送SAVE命令:SAVE命令与BGSAVE不同之处是,SAVE不开辟子进程,而是主进程直接执行持久化,此时不接收客户端请求,一般BGSAVE内存不足是用SAVE方法 redis-server 接收到SHUTDOWN命令或是TERM信号是,开启SAVE命令,进行持久化,此时会短暂阻止进程结束,直到持久化完毕 节点被设置为从,并发送同步进行数据同步时,主节点会触发
问题
快照是某一个时刻的内存全貌,一旦服务器挂了,那就丢失了上一次快照结束后到最近的数据,因此要权衡业务是否接受数据的丢失,比如业务接受最近10分钟数据的丢失,可以配置
save 600 1
复制
AOF是将写操作命令追加到一个文件,重启或恢复时,只要执行一遍文件中的命令就可以恢复数据。
AOF配置
# 是否开启 AOF
appendonly yes
# AOF 文件名称
appendfilename "appendonly.aof"
# 操作系统如何何时将缓冲区数据刷到磁盘
# no 操作系统决定何时刷新到磁盘,此时redis性能最好
# always 每条写后都刷新,最安全,性能最弱
# everysec 每秒刷新一次
# appendfsync always
appendfsync everysec
# appendfsync no
# 其它进程执行BGSAVE,BGREWRITEAOF 时是否停止
# 执行刷新命令 fsync()
no-appendfsync-on-rewrite no
# 当AOF文件的体积比上一次重写之后的体积大了至少
# 一倍且AOF文件体积大于64mb时执行 BGREWRITEAOF
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
复制
append写
always:每条写操作都刷盘,安全性高,数据丢失最少,但是性能最低,对于ssd磁盘很致命
no:操作系统自己决定,性能特别好,但是一旦服务挂掉,导致不定条数的数据丢失,可能丢失少,也可能一个缓冲区的数据全丢了
everysec:每秒刷一次盘,性能和安全的一个折中
AOF 文件重写
不停的append有一个问题,看下面的命令
lacr_r1:6379> set a 1
OK
lacr_r1:6379> set a 2
OK
lacr_r1:6379> set a 1
OK
lacr_r1:6379> set a 3
OK
复制
root@lacr_r1:/var/lib/redis# cat appendonly.aof
# 第一条命令
set # 命令
$1 # 键长度
a # 键
$1 # 值长度
1 # 值
*3
$3
----------------------------
set
$1
a
$1
2
*3
$3
------------------------------
set
$1
a
$1
1
*3
$3
------------------------------
set
$1
a
$1
3
复制
结果四条命令全部append文件中持久化文件中了,导致持久化文件越来越大,浪费磁盘空间,因此应该尽可能的压缩,此时可以向redis发送 BGREWRITEAOF 命令:
lacr_r1:6379> BGREWRITEAOF
Background append only file rewriting started
root@lacr_r1:/var/lib/redis# cat appendonly.aof
SET
$1
a
$1
3
*2
$6
复制
触发 BGREWRITEAOF 判断有无AOF的子进程,有则退出,无则继续 判断有无RDB的子进程,有则退出,无则继续 FORK子进程,将内存中的数据合并压缩刷新到临时AOF文件temp-rewriteaof-bg-进程id.aof
父进程继续接收客户端请求 子进程结束,父进程判断退出状态,若子进程正常退出,父进程将自己写入的数据刷新到temp-rewriteaof-bg-进程id.aof
父进程调用rename将临时文件重命名为appendonly.aof,并删除临时aof文件