Redis的持久化

持久化

Redis的持久化机制有两种

  • 快照(快照是一次全量备份、是内存数据的二进制序列化形式,在存储上非常紧凑)
  • AOF日志(是连续增量的备份、是内存数据修改的指令记录文本)

AOF日志在长期的运行过程中会变得无比庞大,数据库重启时需要加载AOF日志进行指令重放,这个时间会无比漫长,所以需要定期进行AOF重写,给AOF日志进行瘦身

快照原理

Redis使用操作系统的多进程cow(copy on write)机制来实现快照持久化。 Redis在持久化时会调用glibc的函数fork产生一个子进程,快照持久化完全交给子进程来处理,父进程继续处理客户端请求,子进程刚刚产生时,它和父进程共享内存里面的代码段和数据段。用PHP伪代码来展示

<?php

$childPid = pcntl_fork();

if ($childPid == -1) {
    // fork error
} else if ($childPid) {
    // 父进程继续处理客户端请求
    handle_client_rquests();
} else {
    // 子进程处理快照写磁盘
    handle_snapshot_write();
}

举例说明:假如我们有一张纸条,上面写了123三个数,打快照时,我们会把这123这三个原始数据按照原有的顺序和方式记录到别的纸条上,之后如果有新数据456写到这张纸条上,假如这张纸条丢了,那我们还可以将最原始的123那张纸条留下来,大大降低了数据丢失的风险。

AOF原理

AOF日志存储的Redis服务器的顺序指令序列,AOF日志只记录对内存进行修改的指令记录。

Redis会在收到客户端修改指令后,进行参数校验、逻辑处理,如果都没有问题,就立即将该指令文本存储到AOF日志中。也就是说,先执行指令才将日志存盘。

AOF重写

Redis提供了bgrewriteaof指令用于对AOF日志进行瘦身,原理就是开辟一个子进程对内存进行遍历,转换成一系列的Redis的操作指令,序列化到一个新的AOF日志文件中,序列化完毕后再将操作期间发生的增量AOF日志追加到这个新的AOF日志文件中,追加完毕后就立即替代旧的AOF日志文件。

AOF日志是以文件的形式存在的,当程序对AOF日志文件进行写操作的时候,实际上是将内容写到内核为文件描述符分配的一个内存缓存中,然后内核会异步将脏数据刷回到磁盘。

但是服务器突然宕机,AOF日志内容还没来得及完全刷到磁盘怎么办?

Linux的glibc提供了fsync函数可以将制定文件的内容强制从内核缓存刷到磁盘。只要Redis进程实时调用该函数就可以保证不丢失AOF日志,但是fsync是磁盘IO操作,这是很慢的!!!所以在生产环境可以配置Redis每隔1秒就执行一次fsync操作,这个1秒是可以配置的

Redis混合持久化

重启Redis时,我们很少使用rdb来恢复内存状态,因为会丢失大量的数据,我们通常使用AOF来重放日志,但是重放日志相对于使用rdb来说慢的多,这样在Redis实例很大的时候启动需要花费很长的时间。

Redis4.0引入了新的持久化选项:混合持久化。 将rdb文件和AOF日志存在一起,这样AOF的让孩子就不是全量的日志,而是自持久化到持久化结束的这段时间发生的增量AOF日志,于是Redis在重启的时候,可以先加载rdb的内容,再重放AOF日志,就可以完全替代之前的AOF全量重放,重启效率就会得到大幅度提升。

为什么Redis是先执行指令,之后在记录AOF日志?

个人认为是只记录有效的指令,这样可以过滤一些没有执行成功的指令,因为Redis本身定位就是高速读写的缓存,那有可能存在aof的日志文件本身就比rdb文件大。

标签:
作者:华传财
舞台上有你,就演好角色; 舞台上没你,就静静地做观众;

已有 0 位网友参与,快来吐槽:

发表评论