Redis的持久化有两种机制:快照,AOF日志。
1、快照
快照是一种全量备份机制,是内存数据的二进制序列化形式,在存储上非常紧凑。
Redis的单线程程序,为了实现持久化的同时可以响应客户端请求的目的,Redis使用了操作系统的COW(Copy On Write)机制来实现快照持久化。
1.1 Redis在持久化的过程
- 调用glibc的函数fork产生一个子进程,负责持久化的工作。子进程刚产生时和父进程共享内存里的代码段和数据段;
- 子进程遍历读取现有的内存数据结构,然后序列化到磁盘。此时,父进程依然在持续服务客户端请求,修改内存数据;
- 使用操作系统的COW机制对数据段进行分离。数据段是由很多操作系统的页面组合成的,父进程进行修改时,会被共享的页面复制一份,然后在复制页面上进行修改,这是子页面观察到的数据是没有改变的。
2、AOF日志
AOF日志是连续的增量备份,记录的是内存数据修改的顺序指令序列。
Redis收到客户端的修改指令后,先进行参数校验、逻辑处理,如果没有问题,就立即将该指令存储到AOF日志中。也就是说,先执行指令才将日志存盘。
AOF日志在长期的运行过程中会变的无比庞大,数据库重启时需要加载AOF日志进行指令重放,这个时间会非常漫长。所以需要定期进行AOF重写,优化AOF日志。
2.1 日志瘦身
Redis提供了bgrewriteaof指令用于对AOF日志进行瘦身,原理就是开辟一个子进程对内存进行遍历,转换成一系列Redis的操作指令,序列化到一个新的AOF日志文件中。操作完后再讲操作期间发生的增量AOF日志追加到这个新的AOF日志文件中,用追加完毕的AOF日志代替原有的AOF日志文件。
2.2 强制刷新
程序对AOF日志文件进行写操作时,实际上是将内容写到了内核为文件描述符分配的一个内存缓存中,然后内核会异步将数据刷回磁盘中。如果机器突然宕机,AOF日志可能还没来得及完全刷新到磁盘。
Linux的glibc提供了fsync(int fd)函数,用于将指定文件的内容强制从内核缓存刷到磁盘。Redis会定时调用fsync函数,来保证数据不丢失。调用的时间间隔是可配置的,过长会导致数据持久化不及时,过短则会导致频繁的IO操作严重降低性能。
3、持久化的实际应用
两种持久化策略的缺点:
- 快照是通过开启子进程的方式进行的,比较耗费资源,且遍历整个内存,并有大量的写磁盘操作,会加重系统负载;
- AOF的fsync是一个耗时的IO操作,会降低Redis的性能,同时也会增加系统IO负担。
所以Redis的主节点不会进行持久化操作,持久化操作主要在从节点进行;并且一般会增加一些从节点,以降低网络分区的概率,只要有一个节点同步数据正常,数据就不会轻易丢失。
4、混合持久化
由于快照的方式会丢失大量的数据,而AOF日志重放会导致启动非常慢,Redis支持使用混合持久化的方式。Redis在启动的时候,会先加载快照的内容,然后重放增量AOF,提升了重启效率。