前言
由于redis所有数据一般都在内存中,如果不进行配置持久化,redis一旦发生重启操作,数据全部丢失掉,所以就需要开启redis持久化机制,将数据保存到硬盘中,当redis重启后,底层会读取磁盘文件来进行恢复数据,合理使用持久化机制是成为架构师或运维重要的一步,接下来就来为各位小伙伴介绍redis持久化机制的几种方式
RDB持久化机制
Rdb持久化就是把当前进程数据生成快照保存到磁盘的过程,且默认情况下生成快照保存在名称为dump.rdb的二进制文件中
RDB的持久化配置
#持久化策略save 900 1save 300 10save 60 10000
# 如果持久化出错,是否停止主进程写入stop-writes-on-bgsave-error yes
# 导入时是否检查 rdbcompression yes
# 是否压缩rdbchecksum yes
# rdb文件名dbfilename dump.rdb
# 保存rdb文件目录位置dir ./
配置很简单,这里说一下持久化机制策略具体什么意思
可能会有小伙伴会有疑问,为什么需要这么多配置?
因为redis每个时段的读写请求肯定不是均衡的,为了平衡性和数据安全,当然我们也可以根据业务,定制自定义规则什么时候情况下触发备份。
stop-writes-on-bgsave-error
这个配置也是相当重要的一项,默认是开启状态,这是当redis进行持久化的过程中如果发生错误,主进程就停止新的写入操作,也是为了保证数据的一致性吧。
简单理解:redis正在创建快照,而创建快照大概需要10s左右,然后主进程这期间还是会继续进行接受写入操作,如果我的异步线程创建快照发生了错误,那么redis主线程就会自动停止主进程的写入操作。
如果想要禁用掉rdb配置,也是非常soeasy的,直接将持久化策略全部注释掉即可
RDB工作原理
触发RDB持久化机制分为两种,第一种:手动触发,第二种:自动触发
RDB重写机制,手动触发
如果有特殊情况,我们也可以手动执行命令生快rbd快照,我们进入客户端执行save或bgsave命令,就可以生成dump.rdb文件,每次执行命令都会将所有redis快照到一个新的ddb文件里,并覆盖掉原来的rdb快照文件。
127.0.0.1:6379> saveOK127.0.0.1:6379> bgsaveBackground saving started
RDB重写机制,自动触发
bgsave操作流程
1. 执行bgsave命令,Redis父进程判断当前是否存在正在执行的子进程,如RDB/AOF子进程,如果存在bgsave命令直接返回。
2. 父进程执行fork操作创建子进程,fork操作过程中父进程被阻塞。
3. 父进程fork完成后,bgsave命令返回“* Background saving started by pid xxx”信息,并不再阻塞父进程,可以继续响应其他命令。
4. 父进程创建RDB文件,根据父进程内存生成临时快照文件,完成后对原有文件进行原子替换。根据lastsave命令可以获取最近一次生成RDB的时间,对应info Persistence中的rdb_last_save_time。
5. 进程发送信号给父进程表示完胜,父进程更新统计信息。
save与bgsave对比
命令 | save | bgsave |
---|---|---|
IO类型 | 同步 | 异步 |
是否阻塞redis其它命令 | 是 | 否(在生成子进程执行调用fork函数时会有短暂阻塞) |
复杂度 | O(n) | O(n) |
优点 | 不会消耗额外内存 | 不阻塞客户端命令 |
缺点 | 阻塞客户端命令 | 需要fork子进程,消耗内存 |
RDB优点
RDB缺点
AOF持久化机制
快照功能并不是非常耐久(durable):如果 Redis 因为某些原因而造成故障停机, 那么服务器将丢失最近写入、且仍未保存到快照中的那些数据。从 1.1 版本开始, Redis 增加了一种完全耐久的持久化方式:AOF 持久化,将修改的每一条指令记录进文件appendonly.aof中(先写入os cache,每隔一段时间fsync到磁盘)
AOF的持久化配置
#是否开启aof,默认未开启appendonly no
#aof文件名称appendfilename "appendonly.aof"
#aof持久化数据同步方式appendfsync everysec
#aof重写期间是否同步no-appendfsync-on-rewrite no
#aof重写触发配置auto-aof-rewrite-percentage 100auto-aof-rewrite-min-size 64mb
#加载aof时如果出错如何处理aof-load-truncated yes
#aof文件重写策略aof-rewrite-incremental-fsync yes
老套路,分析一下重点配置
appendfsync everysec 同步数据方式分为三种
当然,一般情况下都会采用appendfsync everysec配置,这样同步数据速度会很快,也保证了数据安全性,就算丢失数据最多就1秒的数据
no-appendfsync-on-rewrite
当aof在重写阶段,会进行磁盘同步,磁盘同步的是根据同步方式来进行的,如果同步方式设置为everysec的话,则就是每秒磁盘同步一次。
auto-aof-rewrite-min-size
当aof磁盘文件大小达到设定的阈值,就会进行一次aof重写操作,防止文件过大
auto-aof-rewrite-percentage
当aof文件自上一次重写后文件大小增长了100%则再次触发重写(如果百分比设置为0,则不会发生重写)
aof-load-truncated
启动aof之后,redis会默认使用aof文件加载数据,如果发现aof文件损坏,如何设定的值为yes,则会忽略掉改行错误,尽可能加载更多的数据,如果为no,则会直接报错退出,需要注意的是,该参数是适用于redis启动阶段。
aof-rewrite-incremental-fsync
每次批量写入磁盘的数据量由aof-rewrite-incremental-fsync参数控制,默认为32M,避免单次刷盘数据过多造成硬盘阻塞。
AOF工作原理
AOF存储格式
aof文件是以一种resp协议格式数据进行存储的,比如:新增一条命令为“set sunny 666” aof文件记录如下格式
*3$3set$5sunny$3666
星号后面的数字代表命令有多少个参数,$号后面的数字代表这个参数有几个字符
如上分析:
*3:代表命令由三个部分组成
$3:代表命令的长度,如上set命令长度就是为3
$5:代表key的长度,如上sunny的长度就是为5
$3:代表value的长度,如上666的长度就是为3
注意,如果执行带过期时间的set命令,aof文件里记录的是并不是执行的原始命令,而是记录key过期的时间戳
比如执行“set lm 123 ex 1000”,对应aof文件里记录如下
*3$3set$2lm$3123*3$9PEXPIREAT$2lm$131608730911027
AOF重写机制,手动触发
AOF文件里可能有太多没用指令,所以AOF会定期根据内存的最新数据生成aof文件
例如,执行了如下几条命令:
127.0.0.1:6379> incr readcount(integer) 1127.0.0.1:6379> incr readcount(integer) 2127.0.0.1:6379> incr readcount(integer) 3127.0.0.1:6379> incr readcount(integer) 4127.0.0.1:6379>
重写前后的区别
重写前*2$4incr$9readcount*2$4incr$9readcount*2$4incr$9readcount*2$4incr$9readcount
重写后,是否发现很精简了*3$3SET$9readcount$14
AOF重写机制,自动触发
与auto-aof-rewrite-percentage,auto-aof-rewrite-min-size两个参数有关。
bgrewriteaof 操作流程
1. 执行AOF重写请求。
如果当前进程正在执行bgsave操作,重写命令会等待bgsave执行完后再执行。
2. 父进程执行fork创建子进程。
3. fork操作完成后,主进程会继续响应其它命令。所有修改命令依然会写入到aof_buf中,并根据appendfsync策略持久化到AOF文件中。
4. 因fork操作运用的是写时复制技术,所以子进程只能共享fork操作时的内存数据,对于fork操作后,生成的数据,主进程会单独开辟一块aof_rewrite_buf保存。
5. 子进程根据内存快照,按照命令合并规则写入到新的AOF文件中。每次批量写入磁盘的数据量由aof-rewrite-incremental-fsync参数控制,默认为32M,避免单次刷盘数据过多造成硬盘阻塞。
6. 新AOF文件写入完成后,子进程发送信号给父进程,父进程更新统计信息。
7. 父进程将aof_rewrite_buf(AOF重写缓冲区)的数据写入到新的AOF文件中。
8. 使用新AOF文件替换老文件,完成AOF重写。
实际上,当Redis节点执行完一个命令后,它会同时将这个写命令发送到AOF缓冲区和AOF重写缓冲区。
RDB 和 AOF ,我应该用哪一个?
命令 | RDB | AOF |
---|---|---|
启动优先级 | 低 | 高 |
体积 | 小 | 大 |
恢复速度 | 快 | 慢 |
数据安全性 | 容易丢数据 | 根据策略决定 |
注意:如果开启的RBD 和 AOF,两个持久化机制都是执行,重启后,默认会执行AOF恢复数据,因为数据安全性,所以AOF会优先RDB
AOF的优点
AOF的缺点
混合持久化机制
重启 Redis 时,我们很少使用 RDB来恢复内存状态,因为会丢失大量数据。我们通常使用 AOF 日志重放,但是重放 AOF 日志性能相对 RDB来说要慢很多,这样在 Redis 实例很大的情况下,启动需要花费很长的时间。Redis 4.0 为了解决这个问题,带来了一个新的持久化选项——混合持久化。
通过如下配置可以开启混合持久化(必须先开启aof):
#开启混合模式,默认开启状态aof-use-rdb-preamble yes
如果开启了混合持久化,AOF在重写时,不再是单纯将内存数据转换为RESP命令写入AOF文件,而是将重写这一刻之前的内存做RDB快照处理,并且将RDB快照内容和增量的AOF修改内存数据的命令存在一起,都写入新的AOF文件,新的文件一开始不叫appendonly.aof,等到重写完新的AOF文件才会进行改名,覆盖原有的AOF文件,完成新旧两个AOF文件的替换。
于是在 Redis 重启的时候,可以先加载 RDB 的内容,然后再重放增量 AOF 日志就可以完全替代之前的 AOF 全量文件重放,因此重启效率大幅得到提升。(简单理解:混合模式,当AOF在重写的时候,是以RDB文件内容格式(二进制的形式) 存入到AOF文件中,因为RBD文件恢复速度快,AOF恢复速度慢,这样混合模式就可以大大的提高AOF恢复速度了 注意:如果不是AOF重写的话,新增的内容 还是会以原来的AOF格式追加存储数据 在AOF文件中 ,且默认开始的RBD文件持久化可以关掉了,只要开启了AOF和混合模式的AOF两个配置即可)
混合持久化AOF文件结构如下
Redis数据备份策略:
我是黎明大大,我知道我没有惊世的才华,也没有超于凡人的能力,但毕竟我还有一个不屈服,敢于选择向命运冲锋的灵魂,和一个就是伤痕累累也要义无反顾走下去的心。