未雨绸缪——持久化
Redis数据全部在内存中,如果宕机,数据将全部丢失。需要通过持久化机制
持久化机制有两种
- 快照
- AOF日志
快照试一次全量备份,AOF日志是连续的增量备份。快照是内存数据的二进制序列化形式,在存储上非常紧凑,而AOF日志是连续的增量备份
AOF日志在长期运行过程中变得无比庞大,需要定期进行AOF重写,给日志瘦身
快照原理
Redis是单线程程序,在服务线上请求的同时,Redis还需要进行内存快照,内存快照要求Redis必须进行文件IO操作。
Redis使用操作系统的多进程COW机制来实现快照持久化
fork(多进程)
Redis在持久化时会调用glibc的函数fork产生一个子进程,快照持久化完全交给子进程来处理,父进程继续处理客户端请求。子进程刚刚产生时和父进程共享内存里面的代码段和数据段。
子进程做数据持久化,不会修改现有的内存数据结构,只是对数据结构进行遍历读取,然后序列化写到磁盘中。但是父进程不一样,它必须持续服务客户端请求,然后对内存数据结构进行不间断的修改。
使用操作系统的COW机制来进行数据段页面的分离,当父进程对其中的页面数据进行修改时,会将被共享的页面复制一份出来分离。修改操作进行,共享的页面被分离雨多。
子进程因为数据没有变化,它能看到内存里的数据在进程产生的一瞬间就凝固了,这就是Redis的持久化叫快照的原因。接下来子进程可以安心遍历。
AOF原理
AOF日志存储的是Redis服务器的顺序指令序列,AOF只记录对内存进行修改的指令记录。
Redis会在收到客户端修改指令后,进行参数校验、逻辑处理,就理科将该指令文本存储到AOF日志中(先执行指令再写日志)
Redis在长期运行的过程中,AOF日志会越来越常,重放整个AOF日志会非常耗时,所以需要对AOF日志瘦身。
AOF重写
Redis提供了bgrewriteaof指令用于对AOF日志进行瘦身,其原理是开辟一个子进程对内存就行遍历,转换成一系列的Redis操作指令,序列化到一个新的AOF日志文件中。序列化完毕后再讲操作期间发生的增量AOF日志追加到这个新的AOF日志文件中,追加完毕后就立即替代旧的AOF日志文件,瘦身工作就完成了
fsync
AOF日志是以文件的形式存在的,当程序对AOF日志文件进行写操作时,实际上是将内容写到内核为文件描述符分配的一个内存缓冲中,然后内核会异步将脏数据刷回到磁盘中。
AOF日志内容可能还没来得及完全刷到磁盘中,这个时候就会出现日志丢失。
Linux的glibc提供fsync函数可以将指定文件的内容强制从内核缓存刷到磁盘。所以生产环境的服务器,Redis通常是每隔1s左右执行一次fsync操作,这个1s是数据安全和性能之间的一个折中
运维
快照是通过开启进程的方式进行的,是比较耗资源的
- 遍历整个内存,大块写磁盘会加重系统负载
- AOF的fsync是一个耗时的IO操作,会降低Redis性能,同时也会增加系统IO负担
所以Redis的主节点不会进行持久化操作,从节点进行持久化,在网络分区的情况下,增加一个从节点来降低网络分区的概率,只要一个从节点数据同步正常,数据就不会丢失。做好实时监控工作,保证网络顺畅或能快速修复
Redis 4.0混合持久化
重启Redis时,很少使用rdb来恢复内存状态,因为会丢失大量的数据,使用AOF日志重放,但速度很慢。
4.0增加了混合持久化,AOF不再是全量的日志,而是自持久化开始到持久化结束的这段时间发生的增量AOF日志,这部分日志很小。
重启的时候,先加载rdb内容,再重放增量AOF日志,重启效率大幅提升