vlambda博客
学习文章列表

带你走进Redis的世界 - Redis的持久化

前言

Redis的数据正常都是存储在内存内,如果宕机突然发生,数据就会全部丢失,因此需要提供一种方式保证redis的数据不会因为故障而丢失,这种机制就是redis的持久化机制。

redis的持久化机制分为:

  • 快照 snapshot模式 全量模式

    快照,是一次全量的备份,是内存数据二进制序列化形式,在存储上非常紧凑

  • AOF日志模式 增量模式

    AOF日志是连续的增量备份,长期运行过程中,会变得无比庞大,而且,如果发生宕机,需要读取所有的日志文件,进行恢复,需要大量的时间,所以需要定期对AOF重写,瘦身日志文件

快照原理

正如我们之前,聊过的,redis是一款单线程程序,该线程要同时负责多个客户端的并发读写操作和内存数据结构的逻辑读写。

在服务线上请求的同时,Redis需要进行内存快照,内存快照要求Redis必须进行文件IO操作,因为是单线程,所以文件IO操作就不能使用多路复用API。

意味着,Redis在进行完成服务线上请求的同时,还要进行文件IO操作,会严重影响服务器的性能,

同时,Redis不能阻塞客户端的请求,导致线上业务不可用,那么Redis就需要一边持久化,一边进行响应客户端请求。

针对以上问题难点,Redis采用多线程COW(Copy On write)机制来实现快照持久化。

fork(多线程)

Redis是有状态的节点,每次客户端请求服务端对数据的写操作,都会触发状态的改变。基于全量模式的持久化,通过在状态改变的瞬间,触发snapshot进行保存。

带你走进Redis的世界 - Redis的持久化

Redis的全量写入包含两种方式:SAVE BGSAVE

带你走进Redis的世界 - Redis的持久化

save可以通过客户端显式触发,也可以在redis shutdown时触发,save本身通过redis命令,单线程串行化执行保存。阻塞其他的操作。

bgsave可以通过客户端显式触发,也可以通过定时任务触发,也可以在主从模式下,由从节点触发。

对于bgsave,redis在持久化时,调用glibc函数fork产生一个子进程,快照持久化,完全交给子进程处理,父进程继续处理客户端请求。

子进程做数据持久化,不会修改现有的内存数据结构,只是对数据结构进行遍历读取,序列化,写入到磁盘中。

相比save,bgsave不会影响父进程执行处理客户端请求,但是产生子进程,增加服务器内存的开销。产生fork进程,会造成在复制父进程中,存在秒级的不可用

AOF原理

在Redis中,增量持久化称为AOF(Append-only file)方式。Redis仅对数据的变化进行存储,类似于日志文件。

带你走进Redis的世界 - Redis的持久化

AOF日志文件存储的是Redis服务器的顺序指令序列,AOF日志只记录内存改变的指令。

Redis的增量持久化,存在于每次处理完写命令之后,通过propagate函数触发。

Redis的AOF包含三种同步策略:

  1. always 每次执行完命令,直接同步触发fsync方法,强制数据落地磁盘。会降低redis的吞吐量,每次当落地成功,才响应给客户端,因此此种方式,很大程度的有很好的容错能力

  2. every second 每秒异步触发一次fsync方法。

  3. no 不显式调用fsync方法,由操作系统决定什么时候落地。

对于Redis数据的回放,即对数据的重写,全量和增量,触发时机一致。

Redis 4.0 混合持久化

重启redis时,很少使用rdb即快照方式进行恢复数据,因为会丢失大量数据,通常采用AOF才进行重放。但是AOF日积月累会很庞大,因此会花费很长时间进行重放。

Redis 4.0为解决上述问题,采用混合持久化。在重启redis时,进行先加载rdb内容,然后重放增量AOF文件,此时,重启效率会优化很多。

更多的,可以参考下官方介绍。