18.Redis 主从复制

zhanglei 2022年08月07日 348次浏览

18.Redis 主从复制

针对于 Redis 2.8或以上版本

复制的方式

在 Redis 中,用户可以通过执行 slaveof 命令或者设置 slaveof 选项,让一个服务器去复制( replicate ) 另一个服务器,我们称呼被复制的服务器为主服务器( master ),而对主服务器进行复制的服务器则被称为从服务器 ( slave )

假设现在有两个 Redis 服务器,地址分别为 127.0.0.1:6379 和 127.0.0.1:12345,如果我们向服务器 127.0.0.1:12345 发送以下命令

127.0.0.1:12345> slaveof 127.0.0.1 6379
OK

那么服务器 127.0.0.1:12345 将成为127.0.0.1:6379 的从服务器,而服务器127.0.0.1:6379则会成为127.0.0.1:12345的主服务器。

进行复制中的主从服务器双方的数据库将保存相同的数据,概念上将这种现象称作“ 数据库状态一致 ”,或者简称“ 一致 ”。

比如说,我们在主服务器上执行以下命令:

127.0.0.1:6379> set msg "hello world"
OK

那么我们应该既可以在主服务器上获取 msg 键的值:

127.0.0.1:6379> get msg
"hello world"

又可以在从服务器上获取 msg 的值:

127.0.0.1:12345> get msg
"hello world"

另一方面,如果我们在主服务器上删除了键 msg:

127.0.0.1:6379> del msg
(integer) 1

那么不仅在主服务器上的 msg 键会被删除:

127.0.0.1:6379> exists msg
(integer) 0

从服务器上的 msg 键也应该会被删除:

127.0.0.1:12345> exists msg
(integer) 0

复制的实现过程

通过向从服务器发送 slaveof 命令,可以让一个从服务器去复制主服务器:

slaveof <master_ip> <master_port>

下面展示复制功能的详细实现步骤。

步骤1:设置主服务器的地址和端口

从服务器将客户端给定的主服务器IP地址127.0.0.1以及端口6379保存到服务器状态的 masterhost 属性和 masterport 属性里面:

struct redisServer{
    // ...
    // 主服务器的地址
    char *masterhost;
    // 主服务器的端口
    int masterport;
    // ...
}

slaveof 是一个异步命令,在完成 masterhost 属性和 masterport 属性的设置工作之后,从服务器向发送 slaveof 命令的客户端返回OK,表示复制命令已经被接收,实际的复制工作将在OK返回之后才真正开始执行。

步骤2:建立套接字连接

当从服务器客户端执行完 slaveof 命令之后,从服务器会创建一个连向主服务器的套接字。

image-20220807145915098

如果从服务器创建的套接字能够连接( connect )到主服务器,那么从服务器将为这个套接字关联一个专门用于处理复制工作的文件事件处理器,这个处理器将负责执行后续的复制工作,比如说接收 RDB 文件,以及接收主服务器传播来的写命令,等等。

而主服务器在接受( accept )从服务器的套接字连接之后,将为该套接字创建响应的客户端状态,并将从服务器看作连接到主服务器的一个客户端来对待,这时从服务器将同时具有服务器( server )和客户端( client )两个身份:从服务器可以向主服务器发送命令请求,而主服务器则会向从服务器返回命令回复。

image-20220807150416586

步骤3:发送 PING 命令

当从服务器成为主服务器的客户端之后,做的第一件事情就是向主服务器发送一个 PING 命令。

image-20220807151950186

发送 ping 命令有两个作用:第一,虽然主从服务器成功建立起了套接字连接,但双方并未使用该套接字进行过任何通信,通过发送 ping 命令可以检查套接字的读写状态是否正常;第二,因为复制工作接下来的几个步骤都必须在主服务器正常处理命令请求的状态下才能进行,通过发送 ping 命令可以检查主服务器能否正常处理命令请求。

步骤4:身份验证

从服务器在接收到主服务器返回的 “PONG” 回复之后,下一步要做的就是决定是否进行身份验证。

如果主从服务器都没有设置密码,即主服务器没有设置requirepass 选项,以及从服务器也没有设置 masterauth选项,那么不需要进行身份验证。

若设置从服务器的密码 masterauth为10086,则从服务器向主服务器发送 auth 10086 命令:

image-20220807155701194

因此如果要进行身份验证,那么只有当主从服务器设置的密码相同时,才通过验证。

步骤5:发送端口信息

在进行身份验证之后,从服务器将执行命令 replconf listening-port <port_number>,向主服务器发送从服务器的监听端口号,主服务器接收到这个命令后,会将端口号记录在slave_listening_port属性里。

步骤6:同步

从服务器向主服务器发送 psync 命令,执行同步操作。执行同步操作之前,仅仅是从服务器是主服务器的客户端;执行同步命令之后,主从服务器互为客户端。主服务器成为从服务器的客户端之后,才能通过发送写命令来改变从服务器的数据库状态,这也是主服务器对从服务器进行命令传播操作的基础。

image-20220807161355011

步骤7:命令传播

当完成了同步之后,主从服务器就会进入命令传播阶段,这时主服务器只要一直将自己执行的写命令发送给从服务器,而从服务器只要一直接收并执行主服务器发来的写命令,就可以保证主从服务器一直保持一致了!