持久化,顾名思义,是将内存同步到磁盘的过程。

redis支持三种持久化机制

  • RDB持久化

  • AOF持久化

  • RDB与AOF混合模式

一、RDB持久化

1.1 简介

RDB是Redis中的一种持久化机制,用于将数据保存到硬盘上的二进制文件中。

redis有两种方式进行RDB持久化

  • 手动触发

  • 自动触发

1.2 rdb文件

保存

config set dir {newDir}
config set dbfilename {newFileName}

压缩

config set rdbcompression {yes|no}

校验

config set rdbchecksum {yes|no}
redis-check-dump #使用该工具检测RDB文件并获取对应的错误报告

rdb文件示意图

  • 文件头

  • 文件内容

  • 文件尾

image

1.3 save与bgsave

save: 执行时会阻塞redis(之前讲过redis是一个循环,save执行1秒,所有命令全部阻塞1秒)

bgsave:Redis会在后台通过fork异步进行快照操作,执行RDB备份的是子进程,主进程还可以继续进行命令操作。 可以通过lastsave 命令获取最后一次成功执行快照的时间

1.3.1 自动触发配置

#表示900秒内有1个键改动,就会执行rdb
save 900 1
#表示300秒内有10个键改动,就会执行rdb
save 300 10
#表示60秒内有1万个键改动,就会执行rdb
save 60 10000
#redis通过LZF算法对RDB文件进行压缩,会消耗子进程的cpu资源(多核,物理核、逻辑核有区别),如果是单核就
会影响主进程
rbcbcompression yes
#redis默认使用CRC64的算法对RDB文件进行完整性校验
rdbchecksum yes

1.3.2 bgsave持久化流程

bgsave命令的运作流程

image

1.4 rdb恢复-方式及优势

1.方式

关闭Redis

  • 先把备份的文件拷贝到工作目录下 cp dump2.rdb dump.rdb

启动Redis, 备份数据会直接加

2.优势

  • 适合大规模的数据恢复

  • 对数据完整性和一致性要求不高更适合使用

  • 节省磁盘空间

  • 恢复速度快

3.劣势

  • Fork的时候,内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑

  • 虽然Redis在fork时使用了写时拷贝技术,但是如果数据庞大时还是比较消耗性能。

  • 在备份周期在一定间隔时间做一次备份,所以如果Redis意外down掉的话,就会丢失最后一次快照后的所有修改。

4.禁用

永久禁止RDB:

save # 停止周期性触发

动态停止:

redis-cli config set save #save后给空值,表示禁用保存策略

二、AOF持久化

2.1 简介

以日志的形式将所有写操作追加到文件的末尾,使得数据在文件中呈现出与Redis内存中相同的状态。

  • 记录写操作命令;
  • AOF 会将过期时间由相对转成绝对时间;

AOF为什么直接采用文本协议格式?

  • 文本协议具有很好的兼容性

  • 文本协议具有可读性,方便直接修改和处理

aof文件的内容

  • 客户端与服务器间使用RESP进行交互

例如set hello world这条命令,在AOF缓冲区会追加如下文本(格式化显示的结果):

#参数数量为3个
*3

#set参数字节数分别是3
$3

set

#hello参数字节数分别是5
$5
hello

#world参数字节数分别是5
55
world

2.2 aof配置

aof相关配置

appendonly=yes #开启aof
appendfilename=appendonly.aof #配置aof的文件名,默认文件名是appendonly.aof。
appendfsync={everysec|always|no} #aof日志刷盘策略

动态设置

config set appendonly {yes|no}
config set appendfilename {newFileName}
config set appendfsync {everysec|always|no}

2.3 aof持久化流程

AOF的工作流程操作:

  • 命令写入 (append)

  • 文件同步(sync)

  • 文件重写(rewrite)

重启加载 (load)

image

2.3.1 aof重写

AOF文件重写是把Redis进程内的数据转化为写命令同步到新AOF文件的过程。目的是为了解决AOF文件体积过大的问题,以减少磁盘空间的占用和提高读取性能。而且更小的AOF文件可以更快地被Redis加载。

AOF重写触发方式

  • 手动触发(直接调用bgrewriteaof命令)
  • 自动触发(根据auto-aof-rewrite-min-size和auto-aof-rewrite-percentage参数确定自动触发时机)

aof重写相关配置

# aof重写期间,新进来的命令会暂存内存,等重写完了,会追加(如果出现宕机,重写启动到现在的数据会丢失)
no-appendfsync-on-rewrite=yes

aof重写条件,是原来aof的2倍,且最小文件是64mb

#当前aof文件大小超过上一次重写的aof文件的100%进行重写
auto-aof-rewrite-percentage=10

#重写AOF文件所需的最小文件大小为64mb
auto-aof-rewrite-min-size=64mb

2.3.2 aof重写流程

image

2.4 aof文件恢复

正常恢复

  • 修改默认的appendonly no,改为yes

  • 将有数据的aof文件复制一份保存到对应目录(查看目录:config get dir)

恢复:重启redis然后重新加载

异常恢复

修改默认的appendonly no,改为yes

  • 如遇到AOF文件损坏,通过/usr/local/bin/redis-check-aof--fix appendonly.aof进行恢复

  • 备份被写坏的AOF文件

  • 恢复:重启redis,然后重新加载

image

三、RDB与AOF的对比

RDB持久化

二进制数据

RDB文件紧凑体积小

网络传输快

恢复速度快

无法做到实时

AOF持久化

实时性好,支持秒级持久化

恢复速度慢

对性能影响大

rdb与aof对过期key的处理

  • 过期key对RDB和AOF没有任何影响

  • 过期key持久化到rdb之前,会检查是否过期,过期的key不进入RDB文件

  • 过期key持久化到aof

当key过期后,还没有被删除,此时进行执行aof持久化操作,该key是不会进入aof文件的,因为没有发生修改命令

当key过期后,在发生删除操作时,程序会向aof文件追加一条del命令(在将来的以aof文件恢复数据的时候该过期的键就会被删掉)

  • RDB文件恢复时,数据载入数据库之前,会对key先进行过期检查,如果过期,不导入数据库(主库情况)

aof重写时,会先判断key是否过期,已过期的key不会重写到aof文件

四、持久化问题优化

1.fork操作

对于ops几万的redis实例,fork秒级影响整体业务延时

如何改善

  • 支持fork的虚拟化技术,避免使用Xen或者物理

通过分片,降低每个redis实例的容量,控制在10gb以内,如果性能要求更高,继续降低

降低fork操作频率

2.CPU&内存优化

  • 不要和其他CPU密集型服务部署在一起,造成CPU过度竞争

  • 多实例部署,尽量保证同一时刻只有一个子进程执行重写

关闭THP

3.磁盘优化

  • 高流量使用SSD持久化

  • 分盘存储分摊IO压力(redis 10多个实例都需要AOF持久化)

AOF追加阻塞问题优化

定位:

(1)日志输出

Asynchronous AOF fsync is taking too long (disk is busy). Writing the AOF buffer without waiting for fsync to complete, this may slow down Redis

(2)info Persistence统计中, aof_delayed_fsync指标会累加

(3)磁盘io监控

优化:

  • 优化系统硬盘负载