- 命令传播
步骤1:设置主服务器的地址和端口
当客户端向从服务器发送一下命令时:
slaveof 127.0.0.1 6379
首先要做的就是将客户端给定的主服务器IP地址以及端口号保存到服务器状态的masterhost属性和masterport属性里面
Stcuct redisServer{
//…
前面的一些信息
//主服务器地址
char *masterhost;
//主服务器端口号
int masterport;
//…
};
SLAVEOF命令也是一个异步命令,会启用另一个进程去执行,在完成保存主服务器IP地址和端口号的工作后,从服务器将发送OK回复给客户端
这一步只是代表复制指令被接收,下面才会真正去执行复制工作
步骤二:建立套接字连接
得到了主服务器IP地址和端口号,下面的一步肯定是要进行主从服务器之间连接
从服务器会自己新建一个套接字,然后使用这个套接字连接到服务器,如果连接成功,收到连接成功回复的从服务器套接字会自动去绑定专门用于处理复制工作的文件事件处理器,这个处理器将会负责执行后续的复制工作,比如去接收RDB文件、接收后面主服务器通过传播发送的写命令
而主服务器在接受从服务器套接字连接之后,会为该套接字创建相应的一个客户端状态,将从服务器视作一个客户端去对待,那么此时从服务器就可以向主服务器发送命令请求,而主服务器可以接受从服务器发送的命令请求进行返回命令回复(不熟悉套接字连接可以回看前面系列的套接字连接)
步骤3:发送Ping命令
完成连接之后,从服务器就成为了主服务器的一个客户端,从服务器第一件事就是去发送Ping命令,一般客户端向服务器发送Ping命令,服务器会返回Pong的信息
发送ping命令主要有两个作用
-
虽然主从服务器建立了套接字连接,但主从服务器并没有使用套接字进行过任何通信,难以确定状态是否正常,使用ping命令可以知道连接状态是否正常
-
同时,Ping命令可以确定主服务器可以正常执行命令,因为复制工作接下来的几个步骤都必须在主服务器可以正常执行命令的情况下进行
从服务器在发送Ping命令之后将遇到下列三种情况之一
-
第一种是网络状态不佳,主服务器接收到了Ping已经回复了pong,但从服务器不可以在规定时限内读取出命令回复的内容,这样就表示主从服务器之间的网络连接状态不佳,不可以继续执行复制工作的后续步骤,当出现这种情况时,从服务器会断开连接,然后重新创建连接主服务器的套接字。
-
第二种是主服务出错,主服务器会向从服务器返回一个错误,表示主服务器暂时没办法处理从服务器的命令请求,不能够执行复制工作的后续步骤,当出现这种情况时,从服务器也是会断开连接,然后重新创建连接主服务器的套接字。
-
第三种是正常情况,从服务器读取到了Pong回复,表示主从服务器之间连接状态正常并且主服务器可以正常相应从服务器的请求,然后会继续执行下面的复制工作
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210430222141240.png?x-oss-process=image/watermark,type_ZmFu
【一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
Z3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0dEVVRfVHJpbQ==,size_16,color_FFFFFF,t_70#pic_center)
步骤4:身份验证
现在从服务器可以接收主服务器返回的PONG,证明连接一切正常,下一步就是要进行身份验证了
-
如果从服务器的配置文件设置了masterauth选项,就会进行身份验证
-
如果从服务器的配置文件没有设置masterauth选项,就不会进行身份验证
其实这个身份验证就是从服务器向主服务器发送了一条AUTH命令。
那么对于主服务器这边就会出现4种情况
-
如果主服务器设置了密码验证,即requirepass选项,而且从服务器也设置了masterauth选项,那么就会执行AUTH命令,如果验证通过,复制工作可以继续进行,与此相反,如果验证不通过,主服务器将返回一个invalid passwor的错误
-
如果主服务器设置了密码验证,但从服务器没有设置了masterauth选项,主服务器会返回一个NOAUTH错误
-
如果主服务器没有设置密码验证,但从服务器设置了masterauth选项,主服务器也将返回一个no password is set 的错误
-
如果主服务器没有设置密码验证,从服务器也没有设置masterauth选项,继续执行命令,继续下面的复制工作
步骤5:发送端口信息
在进行身份验证后,从服务器将执行下列的命令
REPLCONF listening-port
其实就是从服务器将自己的监听端口号发送给主服务器,主服务器在接收到这个命令之后,就会将该监听端口号保存在主服务器上的客户端状态,对应的属性为slave_listening_port属性中
typedef struct redisClient(
//。。。
//从服务器的监听端口号
int slave_listening_port;
//…
)redisClient;
这个属性目前并没有什么作用,目前唯一的作用就是主服务器接收客户端的info repliication命令时得到的回复中会显示,下图中对应的port属性就是了(可能是主服务器那边需要记录自己的从服务器的信息)
步骤6:同步
来到了这里,从服务器在主服务器中的客户端信息已经完整,并且主从服务器之间连接没有问题,就可以进行同步操作了。
这里要注意的是,在同步步骤之前,前面的所有步骤,从服务器都是主服务器的客户端,但来到了这一步,从服务器不仅是主服务器的客户端,同时,主服务器也是从服务器的客户端,这是因为后面的缓冲区里面的写命令是由主服务器发送给从服务器的,此时只要主服务器为从服务器的客户端,那么直接发送写命令给从服务器去执行即可。
-
如果Psync命令执行的是部分重同步操作,主服务器需要成为从服务器的客户端,才可以发送缓冲池的写命令
-
如果Psync命令执行的是完全重同步操作,主服务也需要成为从服务器的客户端,才可以发送缓冲池的写命令
-
总的来说,来到同步这一步,主服务器也会变成从服务器的客户端
上一文章已经说过部分重同步和完整重同步的实现,这里就不再赘述