复制
完整重同步部分重同步部分重同步的实现
复制偏移量复制积压缓冲区服务器运行IDPSYNC过程的实现
建立连接和同步判断(完整/部分)复制数据复制(建立连接 + 身份验证 + PSYNC + 数据同步)
建立连接后的心跳检测
每秒发送命令三个作用(检测网络状态,min-slaves配置,检测命令丢失)(1)复制偏移量
复制的双方——主服务器和从服务器分别维护一个复制偏移量
eg.主从服务器现在的复制偏移量都是10086,如果主服务器向从服务器A,B,C传播33字节,而A断线了,则情况如下
(2)复制积压缓冲区
是由主服务器维护的一个固定长度,先进先出的队列,默认1MB。
主服务器在复制时不仅会把命令发送给所有从服务器,也会写入复制挤压缓冲区。如下所示
当从服务器断线重连时,会通过PSYNC命令将自己的offset发送给主服务器。
主服务器判断offset后面缺失的内容是否在积压缓冲区中:
如果在:则回复+CONTINUE,表示采用部分重同步来恢复。并将缺失的数据发送给从服务器如果不在:则进行完整重同步缓冲区大小默认1MB,可以根据conf中repl-backlog-size来修改大小
(3)服务器运行ID
每个服务器,无论主从,都有自己的运行ID:40个随机16进制字符,在服务器启动时自动生成
当从服务器初次复制时,主服务器会发送自己的ID,从服务器会保存。当从服务器断线重连时,向主服务器发送之前记录的ID 如果相同,说明是断线重连前的那个主服务器,可以尝试进行partial resync如果不相同,说明主服务器已经换了,必须fully resync从服务器发送PSYNC命令,请求复制
如果从服务器以前没有复制过任何主服务器,则向主服务器发送 PSYNC ? -1 的命令,表示请求完整重同步如果之前已经复制过某主服务器,则向主服务器发送 PSYNC <runid> <offset> ;runid是上次复制的主服务器ID;offset是从服务器当前的复制偏移量主服务器回复有三种情况:
+FULLRESYNC <runid> <offset> : 执行 fully sync,offset是主服务器的复制偏移量+CONTINUE:执行 partial sync,从服务器等待主服务器发送缺失的数据-ERR:主服务器版本低于2.8,识别不了PSYNC命令,需要从服务器发送SYNC命令例子:
(1)从服务器的客户端——>从服务器: slaveof 127.0.0.1 6379
(2)从服务器——>主服务器:PSYNC ? -1
(3)主服务器——>从服务器:FULLRESYNC 53b9b28df8042fdc5ab5e3fcbbbabff1d5dce2b3 10086
(4)完整重同步成功,主从服务器保持一致,offset一直增加
(4)offset同步到20000字节时,从服务器断开重连
(5)从服务器——>主服务器:PSYNC 53b9b28df8042fdc5ab5e3fcbbbabff1d5dce2b3 20000
(6)主服务器——>从服务器: + CONTINUE (发现缺失的数据仍在缓冲区中,可继续复制)
(1)从服务器设置地址和端口
当从客户端发送salve指令时,从服务器会存储对于IP地址和端口号到redisServer中去。
当设置属性完成后,从服务器返回给客户端OK指令。而实际的复制工作将在之后才执行
struct redisServer{ //主服务器地址 char *masterhost; //主服务器端口 int masterport; }(2)从服务器建立socket连接
从服务器根据IP和端口号,向主服务器建立连接。
连接建立后,从服务器将为这个socket关联一个handler
这时,从服务器可以被当作 主服务器的客户端。
(3)从服务器发送发送PING命令
从服务器成了主服务器的客户端之后,第一件事是发送PING命令,主服务器会有三种回复
返回了一个回复超时——>网络状态不好,从服务器断开并重新连接返回一个ERROR——>主服务器可能在忙,从服务器断开并重新连接返回PONG——>成功,可以继续下一步(4)身份验证
从服务器收到PONG之后,进行身份验证,主要根据conf中的配置。
如果设置了masterauth,则从服务器会自动发送 AUTH password指令给主服务器进行验证
eg.如果主服务器设置了密码为10086, 则从服务器会发送 AUTH 10086 //conf配置文件 slaveof <masterip> <masterport> //设置当本机为 slave 服务时,设置 master 服务的 IP 地址及端口,在 Redis 启动时,它会自动从 master 进行数据同步 masterauth <master-password> //作为slave时,需要给master提供的密码 requirepass foobared //本服务器自身的密码,客户端在连接 Redis 时需要通过 AUTH <password> 命令提供密码,默认关闭连接成功的情况:
主服务器没有设置requirepass,从服务器也没有提供masterauth主服务器设置了requirepass,从服务器也提供了masterauth。两者相同其他情况都连接不成功
(5)发送端口信息
身份验证成功后,从服务器发送 REPLCONF listening-port <port-number>命令,向主服务器发送从服务器的监听端口号,主服务器记录在对应redisClient中
typedef struct redisClient{ //从服务器的监听端口号 int salve_listening_port }该属性的唯一作用是:主服务器查看所有slave时:执行 INFO replication命令,打印所有从服务器的端口号
(6)同步
这一步中,主服务器和从服务器都是各自的客户端。执行PSYNC命令
(7)命令传播
完成同步之后,主服务器只要将自己执行的写命令同步给从服务器,就可以一直保持一致。
