04 AOF日志:宕机,Redis如何避免数据丢失
Redis 的持久化主要有两大机制,即 AOF(Append Only File)日志和 RDB 快照。
Redis 用于避免数据丢失的 AOF 方法
数据库的写前日志(Write Ahead Log, WAL),在实际写数据前,先把修改的数据记到日志文件中,以便故障时进行恢复。
AOF 日志正好相反,是写后日志, Redis 是先执行命令,把数据写入内存,然后才记录日志,
AOF 为什么要先执行命令再记日志:
AOF 里记录的是 Redis 收到的每一条命令,这些命令是以文本形式保存的。
- 写后日志先让系统执行命令,只有命令能执行成功,才会被记录到日志中,否则,系统就会直接向客户端报错,避免出现记录错误命令的情况。
- 在命令执行后才记录日志,所以不会阻塞当前的写操作。
AOF 两个潜在的风险:
- 如果刚执行完一个命令,还没有来得及记日志就宕机,那么这个命令和相应的数据就有丢失的风险。
- AOF 避免对当前命令的阻塞,但可能会给下一个操作带来阻塞风险。因为,AOF 日志也是在主线程中执行的,如果在把日志文件写入磁盘时,磁盘写压力大,导致写盘很慢,后续的操作也无法执行。
两个风险都是和 AOF 写回磁盘的时机相关的。如果能够控制一个写命令执行完后 AOF 日志写回磁盘的时机,风险即被解决。
三种写回策略:
AOF 配置项 appendfsync 的三个可选值
- Always,同步写回:每个写命令执行完,立马同步地将日志写回磁盘;
- Everysec,每秒写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘;
- No,操作系统控制的写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘。
性能和可靠性之间进行取舍。
AOF重写机制
AOF 文件过大会带来的性能问题,通过AOF 重写机制把日志文件变小,因为重写机制具有“多变一”功能,即旧日志文件中的多条命令,在重写后的新日志中变成了一条命令。
虽然 AOF 重写后,日志文件会缩小,但要把整个数据库的最新数据的操作日志都写回磁盘,仍然耗时。这时需要考虑重写会不会阻塞主线程?
AOF 重写会阻塞吗?
AOF 日志由主线程写回,而重写过程是由后台子进程 bgrewriteaof 来完成。
重写的过程总结为“一个拷贝,两处日志”
一个拷贝:每次执行重写时,主线程 fork 出后台的 bgrewriteaof 子进程,把主线程的内存拷贝一份给 bgrewriteaof 子进程,子进程可在不影响主线程的情况下,逐一把拷贝的数据写成操作,记入重写日志。
因为主线程未阻塞,仍然可以处理新来的操作。此时,如果有写操作,
第一处日志:正在使用的 AOF 日志,Redis 会把这个写操作写到它的缓冲区。即使宕机,这个 AOF 日志的操作仍然是齐全的,可以用于恢复。
第二处日志:新的 AOF 重写日志,这个操作也会被写到重写日志的缓冲区。重写日志也不会丢失最新的操作。等到拷贝数据的所有操作记录重写完成后,重写日志记录的这些最新操作也会写入新的 AOF 文件,以保证数据库最新状态的记录。
非阻塞:是指AOF 重写子进程的执行不阻塞主线程。
使用 AOF 进行故障恢复时,仍然需要把所有的操作记录都运行一遍,再加上 Redis 的单线程设计,命令操作只能一条一条按顺序执行,“重放”的过程就会很慢。
问:
- AOF 日志重写过程有没有其他潜在的阻塞风险呢?如果有的话,会在哪里阻塞?
- AOF 重写也有一个重写日志,为什么它不共享使用 AOF 本身的日志呢?
答:略