【Redis实现系列】主从复制步骤

主从复制步骤

设置主服务器地址和端口

当客户端向从服务器发送以下命令时:

127.0.0.1:12345> SLAVEOF 127.0.0.1 6379
OK

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

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

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

建立套接字连接
  • 第一次建立连接:slave --> master , 是 slave 向 master 发送命令的通道 ,与 master 回复的通道

在SLAVEOF命令执行之后,从服务器将根据命令所设置的IP地址和端口,创建连向主服务器的套接字连接。

如果从服务器创建的套接字能成功连接(connect)到主服务器

  • 那么从服务器将为这个套接字关联一个专门用于处理复制工作的文件事件处理器,来接收 master 的回复,这个处理器将负责执行后续的复制工作(即 master 成为 client 的客户端,给 client 发送命令),比如接收RDB文件,以及接收主服务器传播来的写命令,诸如此类。

而主服务器在接受(accept)从服务器的套接字连接之后

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

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

这个PING命令有两个作用:

  • 虽然主从服务器成功建立起了套接字连接,但双方并未使用该套接字进行过任何通信,通过发送PING命令可以检查套接字的读写状态是否正常。

  • 因为复制工作接下来的几个步骤都必须在主服务器可以正常处理命令请求的状态下才能进行,通过发送PING命令可以检查主服务器能否正常处理命令请求。

从服务器在发送PING命令之后将遇到以下三种情况的其中一种:

  • 如果主服务器向从服务器返回了一个命令回复,但从服务器却不能在规定的时限(timeout)内读取出命令回复的内容,那么表示主从服务器之间的网络连接状态不佳,不能继续执行复制工作的后续步骤。当出现这种情况时,从服务器断开并重新创建连向主服务器的套接字。

  • 如果主服务器向从服务器返回一个错误,那么表示主服务器暂时没办法处理从服务器的命令请求,不能继续执行复制工作的后续步骤。当出现这种情况时,从服务器断开并重新创建连向主服务器的套接字。比如说,如果主服务器正在处理一个超时运行的脚本,那么当从服务器向主服务器发送PING命令时,从服务器将收到主服务器返回的BUSY Redisis busy running a script.You can only call SCRIPT KILL or SHUTDOWN NOSAVE.错误。

  • 如果从服务器读取到"PONG"回复,那么表示主从服务器之间的网络连接状态正常,并且主服务器可以正常处理从服务器(客户端)发送的命令请求,在这种情况下,从服务器可以继续执行复制工作的下个步骤。

    在这里插入图片描述

对从服务器身份验证

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

  • 如果从服务器设置了masterauth选项(即 master 设置了密码),那么进行身份验证。

  • 如果从服务器没有设置masterauth选项(即 master 没有设置密码),那么不进行身份验证。

在需要进行身份验证的情况下,从服务器将向主服务器发送一条AUTH命令,命令的参数为从服务器masterauth选项的值。

  • 举个例子,如果从服务器masterauth选项的值为10086,那么从服务器将向主服务器发送命令AUTH 10086

    在这里插入图片描述

从服务器在身份验证阶段可能遇到的情况有以下几种:

  • 如果主服务器没有设置requirepass选项,并且从服务器也没有设置masterauth选项,那么主服务器将继续执行从服务器发送的命令,复制工作可以继续进行。

  • 如果从服务器通过AUTH命令发送的密码和主服务器requirepass选项所设置的密码相同,那么主服务器将继续执行从服务器发送的命令,复制工作可以继续进行。与此相反,如果主从服务器设置的密码不相同,那么主服务器将返回一个invalid password错误。

  • 如果主服务器设置了requirepass选项,但从服务器却没有设置masterauth选项,那么主服务器将返回一个NOAUTH错误。另一方面,如果主服务器没有设置requirepass选项,但从服务器却设置了masterauth选项,那么主服务器将返回一个no password is set错误。

    在这里插入图片描述

发送端口信息

在身份验证步骤之后,从服务器将执行命令REPLCONF listening-port <port-number>,向主服务器发送从服务器的监听端口号。

  • 因为 salve 连接 master 时的端口号并不是 redis 监听的端口号,而是这个连接监听的端口号。

主服务器在接收到这个命令之后,会将端口号记录在从服务器所对应的客户端状态的 slave_listening_port 属性中:

typedef struct redisClient {
    // ...
    // 从服务器的监听端口号
    int slave_listening_port;
    // ...
} redisClient;

通过在 master 的 INFO replication 命令可以查看。

同步
  • 会进行第二次建立连接:master --> slave ,是 master 向 slave 发送命令的通道,与 slave 回复的通道
  • 所以这步之后,主服务器会成为从服务器的客户端,而从服务器也会成为主服务器的客户端
    • 在 从服务器的客户端链表里,主服务对应客户端的 flags 标志着它是 master
    • 在 主服务器的客户端链表里,每个从服务器对应的客户端,其标志是 slave,并且保存着自己监听的端口、最后一次心跳时间、偏移量 等信息。

在这一步,从服务器将向主服务器发送PSYNC命令,执行同步操作,并将自己的数据库更新至主服务器数据库当前所处的状态。

在同步操作执行之前,只有从服务器是主服务器的客户端,但是在执行同步操作之后,主服务器也会成为从服务器的客户端:

  • 如果PSYNC命令执行的是完整重同步操作,那么主服务器需要成为从服务器的客户端,才能将保存在缓冲区里面的写命令发送给从服务器执行。

  • 如果PSYNC命令执行的是部分重同步操作,那么主服务器需要成为从服务器的客户端,才能向从服务器发送保存在复制积压缓冲区里面的写命令。

  • 正因为主服务器成为了从服务器的客户端,所以主服务器才可以通过发送写命令来改变从服务器的数据库状态,不仅同步操作需要用到这一点,这也是主服务器对从服务器执行命令传播操作的基础。

    在这里插入图片描述

命令传播

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

小结

  • Redis 2.8以前的复制功能不能高效地处理断线后重复制情况,但Redis 2.8新添加的部分重同步功能可以解决这个问题。

  • 部分重同步通过复制偏移量、复制积压缓冲区、服务器运行ID三个部分来实现。

  • 在复制操作刚开始的时候,从服务器会成为主服务器的客户端,并通过向主服务器发送命令请求来执行复制步骤,而在复制操作的后期,主从服务器会互相成为对方的客户端。

  • 主服务器通过向从服务器传播命令来更新从服务器的状态,保持主从服务器一致,而从服务器则通过向主服务器发送命令来进行心跳检测,以及命令丢失检测。

已标记关键词 清除标记
<p> <strong><span>Redis是一个key-value</span></strong><a href="https://baike.baidu.com/item/%E5%AD%98%E5%82%A8%E7%B3%BB%E7%BB%9F"><strong><span>存储系统</span></strong></a><strong><span><span>。和</span>Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(</span></strong><a href="https://baike.baidu.com/item/%E9%93%BE%E8%A1%A8"><strong><span>链表</span></strong></a><strong><span>)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些</span></strong><a href="https://baike.baidu.com/item/%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B"><strong><span>数据类型</span></strong></a><strong><span><span>都支持</span>push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。</span></strong> </p> <p> <strong><span>Redis的出现,很大程度补偿了</span></strong><a href="https://baike.baidu.com/item/memcached"><strong><span>memcached</span></strong></a><strong><span><span>这类</span>key/value存储的不足,在部分场合可以对关系数据库起到很好的补充作用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客户端,使用很方便。</span></strong> </p> <p> <strong><span>Redis支持主从同步。数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。这使得Redis可执行单层树复制。存盘可以有意无意的对数据进行写操作。由于完全实现了发布/订阅机制,使得从数据库在任何地方同步树时,可订阅一个频道并接收主服务器完整的消息发布记录。同步对读取操作的可扩展性和数据冗余很有帮助。</span></strong> </p> <p> <span>  </span></p><p> <strong><span> </span></strong> </p> <p> <strong><span>本课程主要讲解以下内容:</span></strong> </p> <p> <span>1. </span><strong><span>Redis的基本使用</span></strong> </p> <p> <span>2. </span><strong><span>Redis数据库的数据类型</span></strong> </p> <p> <span>3. </span><strong><span>Redis数据库数据管理</span></strong> </p> <p> <span>4. </span><strong><span>Redis主从复制</span></strong> </p> <p> <span>5. </span><strong><span>Redis数据库的持久性</span></strong> </p> <p> <span>6. </span><strong><span>Redis的高可靠性和集群</span></strong> </p> <p> <span>7. </span><strong><span>Redis的优化和性能测试</span></strong> </p> <p> <span>8. </span><strong><span>Redis服务器的维护和管理</span></strong> </p> <p> <span>9. </span><strong><span>Redis服务器的常见问题排错</span></strong> </p> <p> <strong><span> </span></strong> </p> <img src="https://img-bss.csdn.net/201908300910404009.png" alt="" />
相关推荐
©️2020 CSDN 皮肤主题: 撸撸猫 设计师:C马雯娟 返回首页