AOF
如果先记日志在落盘,会记录错误的命令。
但是如果执行完就down机,数据有丢失的风险。避免阻塞当前的命令,但是可能阻塞下一个命令
三种写回策略
AOF(主线程写回) appendfsync的三种策略
- Always,每次写命令执行完,立马写会磁盘(基本不丢数据,影响性能)
- Everysec,每秒写回,先将日志写入AOF文件缓冲区,每隔一秒写入磁盘(可能会缺失一秒的数据)
- No 将写操作执行完,将日志放入缓冲区,由操作系统决定何时写入(性能比较好,丢失数据可能性极大)
AOF文件变大,追加效率低,恢复慢——》AOF重写机制(保存键值对最新的数据,不需要保存旧命令)
读取所有键值对,对每个键值对用一条命令记录写入。
- 手动触发 bgrewriteaof
- auto-aof-rewrite-min-size: 表示运行AOF重写时文件的最小大小,默认为64MB
auto-aof-rewrite-percentage:当前AOF文件比上一次重写后AOF文件的增量大小,和上一次重写后AOF文件大小的比值。
同时满足这两个条件会触发重写
- 由后台线程 bgrewriteaof 来完成。
- 一个拷贝:主线程fork(会阻塞主线程)出bgrewriteaof 子进程,写时复制(copy on write)避免一次数据量太大长时间阻塞,拷贝完成后,父子进程指向相同地址空间(拷贝页表,不拷贝物理内存,这样就可以访问父进程数据),子进程可以进行重写。这时如果父进程有数据写入,如果Key和原来的一致,父进程会申请新的内存空间,父子进程内存数据慢慢分离。内存以页进行分配(4K),big key的话空间比较大,可能会阻塞。操作系统需要关闭大页机制(Huge page(2M))。
- 两处日志(最新操作仍然会写入AOF日志和重写日志),AOF重写不复用AOF本身的日志(容易发生竞争,如果重写失败原来的文件也被污染)
RDB
- 相比AOF恢复的比较快,执行的是全量备份
- 生成RDB的两个命令:save(主线程执行,会阻塞)和bgsave(子线程写入RDB文件,默认)
- bgsave的时候,通过写时复制技术(copy-on-write)可以执行写操作(bgsave由主线程fork生成,可以共享主线程数据)
频繁执行全量快照会导致:1.磁盘压力大,前面还没执行完 后面又开始做了,2. fork过程会导致阻塞主线程
Redis 4.0 中提出了一个混合使用 AOF 日志和内存快照的方法,两次快照之间使用AOF。
- 数据不能丢失时,内存快照和 AOF 的混合使用是一个很好的选择;
- 如果允许分钟级别的数据丢失,可以只使用 RDB;
- 如果只用 AOF,优先使用 everysec 的配置选项,因为它在可靠性和性能之间取了一个平衡。