本文学习redis7两大持久化技术之一:AOF(Append Only File)日志追加方式持久化备份与还原,重写以及AOF方式的优缺点
首先我们先简单了解下Redis7中AOF相关配置
// 开启AOF方式持久化,默认no
appendonly yes
// AOF持久化名称
appendfilename "appendonly.aof"
// AOF持久化文件存储目录
appenddirname "appendonlydir"
// fsync数据到磁盘策略:默认每秒everysec
appendfsync everysec
// AOF重写时不进行fsync操作,防止redis长时间阻塞
no-appendfsync-on-rewrite no
// AOF重写最小大小为64M,当AOF文件大小扩展一倍时触发重写:如128M, 192M
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
// 当AOF结尾异常,Redis加载时截取正确部分,恢复时不报错,仅仅日志提示
aof-load-truncated yes
// append-only基础文件采用RDB格式
aof-use-rdb-preamble yes
// AOF记录命令执行时间戳,默认no
aof-timestamp-enabled no
修改配置文件为appendonly yes
,并启动redis
可以看到redis7中,在appendonlydir目录下生成了
继续执行以前的测试文件
@SpringBootTest
public class RedisTest {
@Autowired
private RedissonClient redissonClient;
@Test
public void testRdb() throws InterruptedException {
RMap<String, String> rMap = redissonClient.getMap("rdb");
for (int i = 0; i < 10020; i++) {
rMap.put(i + "", i + "");
}
Thread.sleep(60000);
for (int i = 0; i < 80; i++) {
rMap.put(i + "ok", i + "ok");
}
}
}
操作后我们尝试修改appendonlydir目录名,发现只读不允许修改,我们复制一份重命名为appendonlydirbak模拟备份文件,然后执行
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> shutdown
然后我们删除appendonlydir目录,重命名appendonlydirbak为appendonlydir,然后启动redis, 执行hkeys rdb
如图所示,key数量为10100未丢失
我们同时配置了RDB与AOF,但redis会已AOF为准进行恢复
我们关闭redis服务器,执行命令破坏incr.aof文件
/data # echo 'HELLO WORLD' >> /data/appendonlydir/appendonly.aof.1.incr.aof
当我们重启redis发现无法正常启动,我们使用redis-check-aof
工具检查错误
/data # redis-check-aof /data/appendonlydir/appendonly.aof.1.incr.aof
Start checking Old-Style AOF
AOF /data/appendonlydir/appendonly.aof.1.incr.aof format error
AOF analyzed: filename=/data/appendonlydir/appendonly.aof.1.incr.aof, size=492735, ok_up_to=492723, ok_up_to_line=90906, diff=12
AOF /data/appendonlydir/appendonly.aof.1.incr.aof is not valid. Use the --fix option to try fixing it.
/data # redis-check-aof --fix /data/appendonlydir/appendonly.aof.1.incr.aof
Start checking Old-Style AOF
AOF /data/appendonlydir/appendonly.aof.1.incr.aof format error
AOF analyzed: filename=/data/appendonlydir/appendonly.aof.1.incr.aof, size=492735, ok_up_to=492723, ok_up_to_line=90906, diff=12
This will shrink the AOF /data/appendonlydir/appendonly.aof.1.incr.aof from 492735 bytes, with 12 bytes, to 492723 bytes
y // 输入y才弹出来Continue,然后继续输入y
Continue? [y/N]: Successfully truncated AOF /data/appendonlydir/appendonly.aof.1.incr.aof
修复aof文件后,可以观察到appendonly.aof.1.incr.aof中HELLO WORLD被移除,并可以正常重新启动redis
我们采用伪代码来表示持久化实现的三大步骤:命令追加至aof_buf缓冲区、aof_buf缓冲写入aof文件、fsync文件同步[说白点类似将word中写入的值点击保存至磁盘]
def evenLoop():
while True:
// 处理文件事件,接受命令请求以及发送命令回复
// 处理写请求追加到aof_buf缓冲区
processFileEvents()
// 处理时间事件
processTimeEvents()
// 根据持久化策略,也就是appendfsync的配置选择是否将aof_buf缓冲写入并保存到aof文件
flushAppendOnlyFile()
redis进程就是一个事件循环(loop),循环中的文件事件负责处理客户端请求并响应,当AOF配置appendonly打开时,文件事件处理完写命令后,会将写命令已redis协议格式追加到aof_buf缓冲区末尾【如上图所示】;对于时间事件,则运行定时函数;
对于flushAppendOnlyFile()函数,也就是文件写入与同步步骤是由appendfsync
配置决定
当redis写命令越来越多,aof会越来越大,达到重写配置条件,或者手工执行bgrewriteaof
时会触发重写机制已减少aof大小
// AOF重写时不进行fsync操作,防止redis长时间阻塞
no-appendfsync-on-rewrite no
// AOF重写最小大小为64M,当AOF文件大小扩展一倍时触发重写:如128M, 192M
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
我们先记录下.incr.aof文件当前的行数为90805,再次执行上述java批量写入命令,我们发现目前行数增加至181810行,体积变为900K,现在我们执行BGREWRITEAOF重写后,我们发现incr.aof为空了,且base.rdb文件大小由1K增加156K
127.0.0.1:6379> BGREWRITEAOF
Background append only file rewriting started
当redis版本>=7时,流程如下:
当然在低于7版本是通过AOF重写缓冲区实现的,在此不在讨论
优点:
缺点:
欢迎关注公众号 算法小生 获取更多精彩内容