前言
Redis基于内存存储数据,服务器宕机了数据就会丢失,为了解决这个问题,Redis把内存数据持久化保存下来。持久化的方式分为AOF、RDB。
AOF
aof的全称是append Only file,采用追加文件的方式进行持久化。
AOF 文件是以追加的方式,逐一记录接收到的写命令的。当一个键值对被多条写命令反复修改时,AOF 文件会记录相应的多条命令。
Redis先执行命令,把数据写入内存后再记录日志。好处是可以避免记录错误命令。
AOF线程
AOF 日志由主线程写回,重写过程是由后台线程 bgrewriteaof 来完成的,这也是为了避免阻塞主线程,导致数据库性能下降。
AOF中一条命令格式
格式分为2部分:
1.*3:表示命令由3部分组成(3可变化,非固定)
2.$3:表示后面紧接的键或者值字节长度
例如:set testk testval 命令
*3
$3
set
$5
testk
$7
testval
AOF写入策略
设想如果Redis在内存中执行了命令,但是来不及写AOF就宕机了,此时数据就会丢失,但是如果Redis只是作为数据查询缓存,数据不存在时读取数据库查询数据问题并不大。如果Redis作为数据存储,那么数据将会丢失。
如何解决写AOF数据丢失问题呢?Redis提供了3种写入策略:
1.Aways,同步写回:每个写命令执行完,立马同步地将日志写回磁盘;
2.Everysec,每秒写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘;
3.No,操作系统控制的写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘。
三种写入策略优缺点
配置项 | 写入时机 | 优点 | 缺点 |
---|---|---|---|
Aways | 同步写入 | 可靠性高,数据基本不丢失 | 每个写命令都落盘,性能影响较大 |
Everysec | 每秒写入 | 性能适中 | 宕机时丢失1秒内的数据 |
No | 操作系统控制的写入 | 性能好 | 宕机时丢失数据较多 |
这里的“性能问题”,主要在于以下三个方面:
1.文件系统本身对文件大小有限制,无法保存过大的文件,使用AOF重写机制处理;
2.如果文件太大,之后再往里面追加命令记录的话,效率也会变低;
3.如果发生宕机,AOF 中记录的命令要一个个被重新执行,用于故障恢复,如果日志文件太大,整个恢复过程就会非常缓慢,这就会影响到 Redis 的正常使用。
写入策略-Aways
“同步写回”可以做到基本不丢数据,但是它在每一个写命令后都有一个慢速的落盘操作,不可避免地会影响主线程性能;
写入策略-Everysec
“每秒写回”采用一秒写回一次的频率,避免了“同步写回”的性能开销,虽然减少了对系统性能的影响,但是如果发生宕机,上一秒内未落盘的命令操作仍然会丢失。所以,这只能算是,在避免影响主线程性能和避免数据丢失两者间取了个折中。
写入策略-NO
虽然“操作系统控制的写回”在写完缓冲区后,就可以继续执行后续的命令,但是落盘的时机已经不在 Redis 手中了,只要 AOF 记录没有写回磁盘,一旦宕机对应的数据就丢失了;
AOF配置
redis.conf
#默认关闭
appendonly no
#默认保存aof文件名称为:appendonly.aof
appendfilename "appendonly.aof"
#写入策略默认为everysec
# appendfsync always
appendfsync everysec
# appendfsync no
#执行bgrewriteaof操作时主进程是否写aof文件的操作
#no:重写时主进程写AOF文件,最安全的方法,但是都写磁盘,主进程有阻塞风险
#yes:重写时主进程不写AOF文件,有数据丢失风险
no-appendfsync-on-rewrite no
#aof文件增长比例,指当前aof文件比上次重写的增长比例大小
auto-aof-rewrite-percentage 100
#aof文件重写最小的文件大小,即最开始aof文件必须要达到这个文件时才触发
auto-aof-rewrite-min-size 64mb
#当发生AOF文件末尾截断时,加载文件还是报错退出
aof-load-truncated yes
#混合持久化
aof-use-rdb-preamble yes
混合持久化过程
混合持久化同样也是通过bgrewriteaof完成的,不同的是当开启混合持久化时,fork出的子进程先将共享的内存副本全量的以RDB方式写入aof文件,然后在将重写缓冲区的增量命令以AOF方式写入到文件,写入完成后通知主进程更新统计信息,并将新的含有RDB格式和AOF格式的AOF文件替换旧的的AOF文件。简单的说:新的AOF文件前半段是RDB格式的全量数据后半段是AOF格式的增量数据,如下图:
AOF重写机制
Redis使用AOF重写机制处理大文件,Redis根据现有情况重新创建一个AOF文件(把所有的key写入日志,整个过程也是很耗时的操作)。
在重写的时候,是根据这个键值对当前的最新状态,为它生成对应的写入命令。这样一来,一个键值对在重写日志中只用一条命令就行了,而且,在日志恢复时,只用执行这条命令,就可以直接完成这个键值对的写入了。
AOF重写触发条件
1.AOF重写可以由用户通过调用BGREWRITEAOF手动触发。
2.服务器在AOF功能开启的情况下,会维持以下三个变量:
- 记录当前AOF文件大小的变量aof_current_size。
- 记录最后一次AOF重写之后,AOF文件大小的变量aof_rewrite_base_size。
- 增长百分比变量aof_rewrite_perc。
3.每次当serverCron(服务器周期性操作函数)函数执行时,它会检查以下条件是否全部满足,如果全部满足的话,就触发自动的AOF重写操作:
- 没有BGSAVE命令(RDB持久化)/AOF持久化在执行;
- 没有BGREWRITEAOF在进行;
- 当前AOF文件大小要大于server.aof_rewrite_min_size(默认为1MB),或者在redis.conf配置了auto-aof-rewrite-min-size大小;
- 当前AOF文件大小和最后一次重写后的大小之间的比率等于或者等于指定的增长百分比(在配置文件设置了auto-aof-rewrite-percentage参数,不设置默认为100%)
AOF重写如何执行
1.主线程 fork 出后台的 bgrewriteaof 子进程。fork 会把主线程的内存拷贝一份给 bgrewriteaof 子进程,这里面就包含了数据库的最新数据。然后,bgrewriteaof 子进程就可以在不影响主线程的情况下,逐一把拷贝的数据写成操作,记入重写日志。
2.主线程不是阻塞状态,仍然可以处理新来的操作,并且把这个操作写到AOF的缓冲区。即使宕机了, AOF 日志的操作仍然是齐全的,可以用于恢复。
3.主线程处理新来的操作处理写入AOF的缓冲区外,也会被写到重写日志的缓冲区,重写日志也不会丢失最新的操作。等到拷贝数据的所有操作记录重写完成后,重写日志记录的这些最新操作也会写入新的 AOF 文件,以保证数据库最新状态的记录。此时,我们就可以用新的 AOF 文件替代旧文件了。
参考:
https://blog.csdn.net/hezhiqiang1314/article/details/69396887
https://www.jianshu.com/p/446b12e4740f