持久化

通用持久化方案:

不要只使用某一持久化机制

要充分利用两种持久化机制的优点并避免它们的缺点

RDB

将某个时间点的所有数据都存放到硬盘上, 是对 redis 中的数据执行周期性的持久化

一个 RDB 文件主要是由三个部分组成:

bgsave命令:使用的fork系统调用创建一个子进程来持久化数据, 由于fork出来的子进程是写时复制,只有被父进程修改的内存页才会被赋值出来,没修改的内存页则会被父子进程共享,所以这达到了一个性能的平衡

stateDiagram-v2  bgsave --> 父进程  父进程 --> 有其他子进程正在执行就直接返回  父进程 --> fork  fork --> 响应其他命令  fork --> 子进程  子进程 --> 生成RDB文件  生成RDB文件 --> 父进程: 信号通知父进程

可以在redis-cli执行config set dir{newDir}和config setdbfilename{newFileName} 来改变持久化文件位置

after 60 sec if at least 10000 keys changed save 60 10000

默认开启,保存在dump.rdb

save 900 1           #在900秒(15分钟)之后,如果至少有1个key发生变化,Redis就会自动触发BGSAVE命令创建快照。save 300 10          #在300秒(5分钟)之后,如果至少有10个key发生变化,Redis就会自动触发BGSAVE命令创建快照。save 60 10000        #在60秒(1分钟)之后,如果至少有10000个key发生变化,Redis就会自动触发BGSAVE命令创建快照。

优缺点

AOF

stateDiagram-v2  命令写入 --> AOF缓冲: append  AOF缓冲 --> AOF文件: sync  AOF文件 --> AOF文件: rewrite  重启 --> AOF文件: load

为什么使用AOF缓冲:Redis使用单线程响应命令,如果每次写AOF文件命令都直接追加到硬盘,那么性能完全取决于当前硬盘负载

appendonly yes 开启aofappendfsync always    每一次操作都进行持久化 (每次写操作都执行fsync 性能极差)appendfsync everysec  每隔一秒进行一次持久化 (折中的方案)appendfsync no        让操作系统来决定何时同步 (让操作系统决定何时写到磁盘 数据不安全)

Redis 4.0 开始支持 RDB 和 AOF 的混合持久化(默认关闭,可以通过配置项 aof-use-rdb-preamble 开启)。

如果把混合持久化打开,AOF 重写的时候就直接把 RDB 的内容写到 AOF 文件开头。这样做的好处是可以结合 RDB 和 AOF 的优点

优缺点

AOF重写

随着AOF文件越来越大,需要定期对AOF文件进行重写,达到压缩的目的

执行 BGREWRITEAOF 命令时,Redis 服务器会维护一个 AOF 重写缓冲区,该缓冲区会在子进程创建新AOF文件期间,记录服务器执行的所有写命令。

AOF 重写操作,实际就是遍历所有数据库,把每个键值对以插入操作的形式写入日志文件,即一个 key 只写入一次

当子进程完成创建新AOF文件的工作之后,服务器会将重写缓冲区中的所有内容追加到新AOF文件的末尾,使得新旧两个AOF文件所保存的数据库状态一致

重启恢复流程

graph TB  redis启动 --> A{开启AOF?}  A --> |yes| B{存在AOF}  B --> |yes| 加载AOF  A --> |no| C{存在RDB}  B --> |no| C  C --> |yes| 加载RDB  C --> |no| 启动成功  加载RDB --> D{加载成功}  加载AOF --> D{加载成功}  D --> 启动成功

如果aof文件损坏 可以尝试使用redis-check-aof --fix进行修复

该命令在对 AOF 文件进行修复时,一旦检测到有不完整或是不正确的操作命令时,它就只保留了从 AOF 文件开头到出现不完整,或是不正确的操作命令位置之间的内容,而不完整或是不正确的操作命令,以及其后续的内容就被直接删除了

问题定位与优化

fork的问题:

持久化时各类资源的消耗:

AOFfsync策略:

graph TB  主线程 --> AOF缓冲区  AOF缓冲区 --> A{对比上次fsync时间}  A --> |大于2s| 阻塞  A --> |小于2s| 通过  AOF缓冲区 --> 同步线程  同步线程 --> 同步磁盘

使用everysec这种同步策略 当一个命令写入缓冲区后发现上次同步到磁盘的时间大于2秒 就会阻塞住 直至同步磁盘完成

这意味着使用这种策略至多会丢失2秒的数据