Redis 中所有数据保存在内存中,对数据的更新将异步保存到磁盘上。
一、主流数据库持久化方式:
1.快照:某个时间点数据的完整备份。例如 MySQL Dump、Redis RDB
2.写日志:数据库做了任何更新都写在日志中,当需要恢复数据的时候,只需要把日志拿过来重新走一遍这些操作。例如 MySQL Binlog、Hbase HLog、Redis AOF。
二、redis持久化的两种方式:
1.RDB
将redis内存中的数据完整的生成一个快照,然后保存到硬盘中一个RDB文件(二进制)。它也是一个复制的媒介,主从复制的时候会用到RDB的持久化方式,然后做一个复制文件的传输。
1.1 触发机制:
save 同步命令,会阻塞,其他命令都会排队,等save完成后才做其他命令。
执行save会生成RDB文件,如果存在老的文件,会被替换掉。
时间复杂度 o(n)
bgsave 异步命令,不会阻塞。
执行bgsave会使用linux的fork(),函数生成一个子进程,子进程完成RDB的生成。fork()会阻塞redis其他命令。
redis中查看上一次fork使用时间的命令 info:latest_fork_usec
生成RDB文件,如果存在老的文件,会被替换掉。
时间复杂度 o(n)
命令 | save | bgsave |
IO类型 | 同步 | 异步 |
阻塞 | 是 | 仅发生在fork() |
复杂度 | o(n) | o(n) |
优点 | 不会消耗额外内存 | 不会阻塞客户端命令 |
缺点 | 阻塞客户端命令 | 需要fork,消耗内存 |
1.2 触发方式之自动触发
1.2.1 配置文件redis.conf中配置save触发RDB
配置 | seconds | changes | 触发自动RDB |
save | 900 | 1 | 900秒内改变1条数据,则触发自动RDB,用bgsave |
save | 300 | 10 | 300秒内改变10条数据,则触发自动RDB,用bgsave |
save | 60 | 10000 | 60秒内改变10000条数据,则触发自动RDB,用bgsave |
除save之外还有一些RDB相关配置属性
配置属性 | 默认配置 | 意思 | 推荐配置 |
save | 见上一个表格 | 建议关闭save | |
dbfilename | dump.rdb | 生成的RDB文件叫什么名字 | dump-${port].rdb |
dir | ./ | 生成的RDB文件、AOF文件、日志文件保存在什么路径中 | 不要使用当前目录,选择比较大的硬盘路径,可能还需要硬盘分盘 |
stop-writes-on-bgsave-error | yes | 如果bgsave发生了错误,是否停止写入 | yes |
rdbcompression | yes | RDB文件是否采用压缩格式 | yes |
rdbchecksum | yes | 是否对RDB文件进行检验 | yes |
1.2.2 触发方式之主动触发:
1.在主从复制场景下,如果从节点执行全量复制操作,则主节点会执行bgsave命令,并将rdb文件发送给从节点
2.debug reload 触发RDB
3.执行shutdown命令时,触发RDB
2.AOF
数据库做了任何更新操作都写在AOF文件中。
2.1 AOF的三种策略
always redis每条命令都会fsync到硬盘AOF文件中,这种策略,恢复数据的时候不会有数据丢失。
everysec 默认用这种。每秒把缓冲区fsync到硬盘AOF文件中,这种策略,高写入量时,会适当保护硬盘。出现故障可能会丢失一秒的数据。
no 把缓冲区fsync到硬盘AOF文件中由操作系统觉得,操作系统觉得什么时候fsync就什么时候。
比较
命令 | always | everysec | no |
优点 | 不丢失数据 | 每秒一次fsync 可能会丢一秒的数据 | 不用管 |
缺点 | IO开销较大,一般sata盘只有几百TPS | 可能会丢一秒的数据 | 不可控 |
2.2 AOF重写
AOF重写,解决AOF文件无限增大的问题,减少硬盘占用量、加上恢复速度。
原生AOF | AOF重写 |
set hello word set hello word1 set hello word2 | set hello word2 |
incr counter incr counter | set count 2 |
rpush mylist a rpush mylist b rpush mylist c | rpush mylist a b c |
2.2.1 AOF重写的两种实现方式
1.手动触发重写 bgrewriteaof 用fork()函数出一个子进程,在子进程中重写AOF文件
2.自动触发重写 AOF自动重写配置
配置名 | 含义 |
auto-aof-rewrite-min-size | AOF文件多大时才需要重写 |
auto-aof-rewrite-percentage | AOF文件增长率,下一次重写的条件 |
统计名 | 含义 |
aof_current_size | AOF当前尺寸(单位:字节) |
aof_base_size | AOF上次启动和重写的尺寸(单位:字节) |
2.2.3 AOF相关配置
配置属性 | 默认配置 | 意思 | 推荐配置 |
appendonly | no | 要使用AOF功能就要打开这个属性 | yes |
appendfilename | appendonly.aof | 生成的AOF文件叫什么名字 | appendonly-${port].aof |
appendfsync | .everysec | AOF同步的三种策略 | everysec |
dir | ./ | 生成的RDB文件、AOF文件、日志文件保存在什么路径中 | 不要使用当前目录,选择比较大的硬盘路径,可能还需要硬盘分盘 |
no-appendfsync-on-rewrite | no | AOF重写的时候不做正常的AOF append操作 | yes |
auto-aof-rewrite-percentage | 100 | AOF文件增长率,下一次重写的条件 | 100 |
auto-aof-rewrite-min-size | 64mb | AOF文件多大时才需要重写 | 64mb |
3.RDB和AOF的对比
4.RDB最佳策略
1.主节点关闭RDB
2.集中管理
3.从节点开RDB,不要太频繁。
5.AOF最佳策略
1.需要持久化就打开AOF,如果只把redis当缓存用,就没必要打开AOF了
2.AOF重写集中管理
3.建议使用everysec
三、持久化策略选择
在介绍持久化策略之前,首先要明白无论是RDB还是AOF,持久化的开启都是要付出性能方面代价的:
1.RDB持久化:1.bgsave在进行fork操作时Redis主进程会阻塞。2.子进程向硬盘写数据也会带来IO压力。
2.AOF持久化:1.向硬盘写数据的频率大大提高(everysec策略下为秒级),IO压力更大,甚至可能造成AOF追加阻塞问题。2.AOF文件的重写与RDB的bgsave类似,会有fork时的阻塞和子进程的IO压力问题。
相对来说,由于AOF向硬盘中写数据的频率更高,因此对Redis主进程性能的影响会更大。
在实际生产环境中,根据数据量、应用对数据的安全要求、预算限制等不同情况,会有各种各样的持久化策略;如完全不使用任何持久化、使用RDB或AOF的一种,或同时开启RDB和AOF持久化等。此外,持久化的选择必须与Redis的主从策略一起考虑,因为主从复制与持久化同样具有数据备份的功能,而且主机master和从机slave可以独立的选择持久化方案。
场景:
(1)如果Redis中的数据完全丢弃也没有关系(如Redis完全用作DB层数据的cache),那么无论是单机,还是主从架构,都可以不进行任何持久化。
(2)在单机环境下,如果可以接受十几分钟或更多的数据丢失,选择RDB对Redis的性能更加有利;如果只能接受秒级别的数据丢失,应该选择AOF。
(3)主从环境下,slave的存在既可以实现数据的热备,也可以进行读写分离分担Redis读请求,以及在master宕掉后继续提供服务。
在这种情况下,一种可行的做法是:
master:完全关闭持久化(包括RDB和AOF),这样可以让master的性能达到最好
slave:关闭RDB,开启AOF(如果对数据安全要求不高,开启RDB关闭AOF也可以),并定时对持久化文件进行备份(如备份到其他文件夹,并标记好备份的时间);然后关闭AOF的自动重写,然后添加定时任务,在每天Redis闲时(如凌晨12点)调用bgrewriteaof。
这里需要解释一下,为什么开启了主从复制,可以实现数据的热备份,还需要设置持久化呢?因为在一些特殊情况下,主从复制仍然不足以保证数据的安全,例如:
- master和slave进程同时停止:考虑这样一种场景,如果master和slave在同一栋大楼或同一个机房,则一次停电事故就可能导致master和slave机器同时关机,Redis进程停止;如果没有持久化,则面临的是数据的完全丢失。
- master误重启:考虑这样一种场景,master服务因为故障宕掉了,如果系统中有自动拉起机制(即检测到服务停止后重启该服务)将master自动重启,由于没有持久化文件,那么master重启后数据是空的,slave同步数据也变成了空的;如果master和slave都没有持久化,同样会面临数据的完全丢失。需要注意的是,即便是使用了哨兵(关于哨兵后面会有文章介绍)进行自动的主从切换,也有可能在哨兵轮询到master之前,便被自动拉起机制重启了。因此,应尽量避免“自动拉起机制”和“不做持久化”同时出现。
(4)异地灾备:上述讨论的几种持久化策略,针对的都是一般的系统故障,如进程异常退出、宕机、断电等,这些故障不会损坏硬盘。但是对于一些可能导致硬盘损坏的灾难情况,如火灾地震,就需要进行异地灾备。例如对于单机的情形,可以定时将RDB文件或重写后的AOF文件,通过scp拷贝到远程机器,如阿里云、AWS等;对于主从的情形,可以定时在master上执行bgsave,然后将RDB文件拷贝到远程机器,或者在slave上执行bgrewriteaof重写AOF文件后,将AOF文件拷贝到远程机器上。一般来说,由于RDB文件文件小、恢复快,因此灾难恢复常用RDB文件;异地备份的频率根据数据安全性的需要及其他条件来确定,但最好不要低于一天一次。