AOF 持久化是怎么实现的?
AOF 日志
Append Only File持久化功能,只记录写操作命令,不记录读操作
默认不开启,需要修改 redis.conf 配置文件
AOF 日志文件其实就是普通的文本,我们可以通过 cat 命令查看里面的内容,不过里面的内容如果不知道一定的规则的话,可能会看不懂。
Redis 是先执行写操作命令后,才将该命令记录到 AOF 日志里的,这么做其实有两个好处。
- 1、避免额外检查开销:不会记录错误命令(错误的话redis执行失败,不会记录)
- 2、不会阻塞当前写操作:执行成功后才会记录 两个风险:
- 1、执行写操作命令和记录日志是两个过程,中间发生宕机,数据有丢失风险。
- 2、对写一个命令可能有阻塞风险。(都是主进程执行)
写回策略 Redis 执行完写操作命令后,会将命令追加到 server.aof_buf 缓冲区,之后通过 write() 写入内核缓冲区,提供了三种写会磁盘的策略
- Always,每次写操作后将日志数据落盘;
- 数据最可靠,性能最差
- Everysec,每隔一秒落盘;
- 比较均衡,最多丢掉一秒的数据
- No,由操作系统控制写回的时机。
- 数据可靠性不确定,性能相对最好
重写机制 随着写操作越来越多,文件会不断变大,后续如果通过该文件恢复数据,会很慢。 当文件大小超过阈值,会执行重写压缩 AOF 文件 重新会读取当前库中所有数据,以写入的模式记录到新的 AOF 文件,全部记录完替换旧的 AOF 文件(同一个数据多次修改只记录一次,删除的数据不用记录),记录完替换是为了避免新的 AOF 重写失败,污染数据。 Redis使用子进程进行重写,避免阻塞主进程,同时避免多线程共享内容带来的竞争,父子进程会用写时复制避免,但是复制还是主进程操作,大key容易出现阻塞问题。在重写过程中,会增加一个 AOF 重写缓冲区 记录重写过程中的新的写命令,过程中写操作主进程需要
- 执行客户端发来的命令;
- 将执行后的写命令追加到「AOF 缓冲区」;
- 将执行后的写命令追加到「AOF 重写缓冲区」; 重写结束后会将 AOF 重写缓冲区 数据追加到新的 AOF 文件中,然后改名并使用新的 AOF 文件(会阻塞主进程正常执行,在这个过程中也就不会出现新的写操作了) Redis启动时会对 AOF 文件进行校验和检查,如果文件损坏,会拒绝启动,并提供错误信息。
RDS 快照
- save 由主进程写入,会阻塞主线程
- bgsave 由子进程创建(默认),这个期间主线程修改了数据,无法写入到正在写入的 RDS 快照中
- Redis自动加载,无手动加载命令
- 是全量快照,可以配置每隔一段时间质性
- 因为是二进制数据(AOF是操作命令),所以恢复更快
- 但是因为每次写入全量,所以创建很慢
- 如果快照创建后立刻宕机,会丢失创建快照后写入的说有数据
- 因此提出混合持久化
- 当开启了混合持久化时,在 AOF 重写日志时,
fork出来的重写子进程会先将与主线程共享的内存数据以 RDB 方式写入到 AOF 文件,然后主线程处理的操作命令会被记录在重写缓冲区里,重写缓冲区里的增量命令会以 AOF 方式写入到 AOF 文件,写入完成后通知主进程将新的含有 RDB 格式和 AOF 格式的 AOF 文件替换旧的的 AOF 文件。
- 当开启了混合持久化时,在 AOF 重写日志时,
也就是说,使用了混合持久化,AOF 文件的前半部分是 RDB 格式的全量数据,后半部分是 AOF 格式的增量数据。
这样的好处在于,重启 Redis 加载数据的时候,由于前半部分是 RDB 内容,这样加载的时候速度会很快。
加载完 RDB 的内容后,才会加载后半部分的 AOF 内容,这里的内容是 Redis 后台子进程重写 AOF 期间,主线程处理的操作命令,可以使得数据更少的丢失。
并没有显式的边界标识来直接区分RDB和AOF的边界。但是,由于RDB和AOF的格式和内容本质上是不同的(RDB是二进制格式,AOF是文本格式),因此在解析混合持久化文件时,Redis能够根据文件格式和内容的不同来自动区分RDB和AOF部分。
大 Key 问题
- 单线程写入或者删除大 Key 会比较慢,会阻塞(删除可以使用unlink异步删除避免阻塞)
- 获取大 Key 造成高网络负载
- AOF 日志写入很多大 Key,文件大小会很大,会频繁触发重写
- 如果配置了 Always 写回策略,写操作容易阻塞很久
- AOF 和 RDB 生成过程中,父进程修改了共享数据,会触发写时复制,大 Key 容易阻塞父进程
如果 Redis 只是缓存,可以关闭 AOF 经常监控大 Key,将大 Key 进行拆分
