redis源码学习常态化版权声明

原创
小哥 3年前 (2022-10-28) 阅读数 154 #PHP
文章标签 PHP

作为web作为发展部的一员,相信每个人在面试经历中都会遇到这样的问题:redis它是如何持续下去的?

不要急着给出答案,先停下来想一想,然后再看下面的介绍。我希望你读完这篇文章后能回答这个问题。

为什么需要坚持不懈?

由于Redis它是一种内存数据库,即服务器运行时,系统为其分配一部分内存存储数据。一旦服务器挂起或突然停机,数据库中的数据就会丢失。为了在服务器突然关闭的情况下保存数据,必须将数据从内存持久保存到磁盘。

对于持续存在的程序,将数据从程序写入计算机磁盘的过程如下:

1客户端向数据库发送写指令(此时数据在客户端的内存中)

2,数据库收到写入的指令和数据(此时数据在服务器的内存中)

3数据库发起系统调用,将数据写入磁盘(此时数据在内核的内存中)

4操作系统将数据传输到磁盘控制器(此时数据在磁盘高速缓存中)

5磁盘控制器执行实际将数据写入物理介质(例如磁盘)的操作

如果只考虑数据库级别,数据在第三阶段后将是安全的。此时,系统调用已经启动。即使数据库进程崩溃,系统调用也会继续,数据可以成功写入磁盘。
在此步骤之后,在第一个步骤中4步骤内核会将数据从内核缓存保存到磁盘缓存,但出于系统效率的考虑,此操作在默认情况下可能不会执行得太频繁30s一次,这意味着如果此步骤失败或服务器在执行时突然关闭,则可能会出现30s数据丢失了,这个更常见的灾难性问题也需要考虑。

POSIX API还提供了一个系统调用来强制内核将缓存数据写入磁盘,这是更常见的。fsync系统调用。

int fsync(int fd);

fsync该函数仅用于文件描述符。fd指定的文件工作,并等待写入磁盘操作结束后才返回。每次呼叫fsync则初始化写入操作,并将缓冲区数据写入磁盘。fsync()当写入操作完成时,该函数会阻止该进程。如果其他线程正在写入相同的文件,它还会阻止其他线程,直到写入操作完成。

持久化

持久性是一种在持久状态和瞬时状态之间转换程序数据的机制。对于程序来说,程序中的数据在内存中。如果不及时同步写入磁盘,一旦断电或程序突然崩溃,数据就会丢失。只有及时将数据同步到磁盘上,才能永久保存数据,不会造成停机镜像数据的有效性。持久性是将数据从程序同步到磁盘的过程。

转存失败 重新上传 取消

Redis的持久化

redis有RDB和AOF坚持下去有两种方法。RDB是快照文件、redis通过执行SAVE/BGSAVE命令执行数据备份时,将redis保存当前数据 *.rdb 在该文件中,该文件保存所有数据集。AOF是服务器通过读取配置,在指定的时间内追加。redis写下命令。 *.aof 文件,是一种增量的持久化方式。

RDB

RDB文件通过SAVE或BGSAVE命令执行。
SAVE命令将阻止Redis服务流程RDB直到创建了该文件。
BGSAVE命令通过fork子流程,还有子流程要创建。RDB文件、父进程和子进程共享数据段,父进程继续提供读写服务,子进程实现备份功能。BGSAVE仅当需要修改共享数据段时才复制该阶段,即。COW(Copy On Write)。SAVE创建RDB只要满足其中一个条件,就可以通过设置多个保存条件在后台执行文件。SAVE操作。

SAVE和BGSAVE该命令的实现代码如下:

void saveCommand(client *c) {
    // BGSAVE它在执行时不能执行。SAVE
    if (server.rdb_child_pid != -1) {
        addReplyError(c,"Background save already in progress");
        return;
    }
    rdbSaveInfo rsi, *rsiptr;
    rsiptr = rdbPopulateSaveInfo(&rsi);
    // 调用rdbSave功能执行备份(阻止当前客户端)
    if (rdbSave(server.rdb_filename,rsiptr) == C_OK) {
        addReply(c,shared.ok);
    } else {
        addReply(c,shared.err);
    }
}

/*
* BGSAVE 命令实现 [可选参数"schedule"]
*/
void bgsaveCommand(client *c) {
    int schedule = 0;

    /* 当AOF在执行时,SCHEDULE参数修改BGSAVE的效果
    * BGSAVE将在以后执行,而不是报告错误
    * 可以理解为:BGSAVE在议程上
    */
    if (c->argc > 1) {
        // 参数只能是"schedule"
        if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"schedule")) {
            schedule = 1;
        } else {
            addReply(c,shared.syntaxerr);
            return;
        }
    }

    // BGSAVE正在执行,不执行操作
    if (server.rdb_child_pid != -1) {
        addReplyError(c,"Background save already in progress");
    } else if (server.aof_child_pid != -1) {
        // aof正在执行,如果schedule==1,BGSAVE在议程上
        if (schedule) {
            server.rdb_bgsave_scheduled = 1;
            addReplyStatus(c,"Background saving scheduled");
        } else {
            addReplyError(c,
            "An AOF log rewriting in progress: cant BGSAVE right now. "
            "Use BGSAVE SCHEDULE in order to schedule a BGSAVE whenever "
            "possible.");
        }
    } else if (rdbSaveBackground(server.rdb_filename,NULL) == C_OK) {// 否则调用rdbSaveBackground执行备份操作
        addReplyStatus(c,"Background saving started");
    } else {
        addReply(c,shared.err);
    }
}

有了RDB文件完成后,如果关闭服务器或需要添加新的服务器,则可以在重启后加载数据库服务器。RDB该文件还原以前备份的数据。
但是bgsave耗时长,实时性不够强,关机时会造成大量数据丢失。

AOF(Append Only File)

RDB该文件保存数据库的密钥值对数据,AOF保存的是数据库执行的WRITE命令。

AOF实施过程分为三个步骤:

append->write->fsync

appendAPPEND命令AOF缓冲区,write将缓冲器的内容写入程序缓冲器,fsync将程序缓冲区的内容写入文件。
当AOF当持久性功能打开时,服务器会为执行的每个命令将命令附加到协议格式。redisServer结构体的aof_buf缓冲区,这里不描述具体的协议。

AOF持久期有一个配置选项:appendfsync。该选项有三个值:
always:所有内容均已写入并同步。aof文件
everysec:将aof_buf将缓冲区的内容写入AOF文件,如果距离上次同步的距离AOF文件的
no:将aof_buf缓冲区中的所有内容都是写入的。AOF文件,但不在AOF文件被同步,操作系统决定何时同步,这通常是默认设置。30s。

AOF持久化模式每个写入命令都被附加。AOF文件,当服务器继续运行时,AOF文件会变得越来越大,为了避免AOF生成的文件太大,服务器将是正确的。AOF文件将被重写,并且操作将是相同的。key合并相同的命令,从而减小文件的大小。

例如,要保存员工的姓名、性别和其他信息:

> hset employee_12345 name "hoohack"
> hset employee_12345 good_at "php"
> hset employee_12345 gender "male"

只需输入该散列键的状态,AOF该文件需要保存三个命令。如果有其他操作,如删除或更新值,则命令会更多,文件也会更大。通过重写,可以适当减小文件大小。

AOF重写的实现原理是先在服务器端数据库,然后遍历数据库,找出每个数据库中的所有键对象,得到键值对的键和值,再根据键的类型重写键值对。例如,上面的示例可以组合成以下命令:

> hset employee_12345 name "hoohack" good_at "php" gender "male"。

AOF重写执行大量的写操作,Redis它是单线程的,因此如果服务器直接调用重写,则服务器无法处理其他命令,因此Redis服务器有一个新的单一进程要执行。AOF重写。

Redis执行重写的过程:

在子进程中执行AOF重写时,服务器从客户端接收命令,执行来自客户端的命令,然后将执行的写命令附加到AOF缓冲区,并将执行的写命令追加到AOF重写缓冲区。
当子进程完成重写时,它将向服务器发送一个完整的信号,服务器将AOF将追加覆盖缓冲区中的所有内容AOF文件,然后自动重写现有的AOF文件。

RDB和AOF的优缺点

RDB持久化方法只有从服务器读取数据,才能将备份中的文件加载到程序中。AOF该方法必须创建一个要执行的伪客户端。

RDB文件小,保存了某个时间点之前的数据,适合灾备和主备同步。

RDB备份需要很长时间。如果数据量很大,在停机的情况下可能会丢失一些数据。此外,RDB只有在通过配置满足特定条件时才会执行此操作。如果在这段时间内发生停机,这部分数据也将丢失。

AOF这样,在相同数据集的情况下,文件大小将高于RDB这条路很大。

AOF持久化方法也因配置不同而有所不同。默认配置为每秒同步。最快的模式是同步每个命令。最糟糕的方法是等待系统执行fsync将缓冲区同步到磁盘文件,大多数操作系统都是30s。通常配置为每秒同步一次,因此最多会有1s数据丢失的风险。

哪种同步方式更好?

RDB和AOF多好的组合啊。启动定时任务,每小时备份服务器的当前数据状态,以日期和小时命名,并启动定时任务以删除无效的备份文件(例如,48几个小时前)。AOF配置为1s就一次。如此一来,损失最大的将是。1s数据,而如果。redis一旦发生雪崩,可以在不停止服务的情况下快速恢复到前一天的状态。

总结

Redis持久化方案不是一成不变的,需要将文中的理论与实际结果相结合来证明其可行性。

原创文章,写作有限,只有一点学问,如果文章有什么地方有误,希望能告知。

更多精彩内容,请关注个人公众号。

版权声明

所有资源都来源于爬虫采集,如有侵权请联系我们,我们将立即删除