深入理解redis复制连接机制

编者:Matlon

测试环境: 一主一从 + sentinel

问题描述: 

主从建立复制后,开启sentinel,发现consle 的打印信息如下:

[8850] 20 Apr 18:24:24.924 # Sentinel runid is 16ade6a85d000cda7ac61831c3c1e01c35312c3b
[8850] 20 Apr 18:26:06.192 * +slave slave 192.168.164.232:6286 192.168.164.232 6286 @ ts 192.168.164.231 6286
[8850] 20 Apr 18:26:11.256 # +sdown slave 192.168.164.232:6286 192.168.164.232 6286 @ ts 192.168.164.231 6286 

sentinel 发现slave后,就主观下线redis 从机,而在主从中都有相关的复制信息,比较诡异

在231的日志中,发现如下错误

[92876] 20 Apr 02:39:26.424 * Connecting to MASTER 192.168.164.231:6286
[92876] 20 Apr 02:39:26.425 * MASTER <-> SLAVE sync started
[92876] 20 Apr 02:39:26.426 # Error condition on socket for SYNC: Connection refused

发现连接有问题,查看一番,发现是防火墙没关

[root@redis02 redis]# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source     destination        
ACCEPT     all  --  anywhere      anywhere   state RELATED,ESTABLISHED
ACCEPT     icmp --  anywhere   anywhere           
ACCEPT     all  --  anywhere      anywhere           
ACCEPT     tcp  --  anywhere     anywhere    state NEW tcp dpt:ssh
REJECT     all  --  anywhere      anywhere     reject-with icmp-host-prohibited
Chain FORWARD (policy ACCEPT)
target     prot opt source     destination        
REJECT     all  --  anywhere    anywhere     reject-with icmp-host-prohibited
Chain OUTPUT (policy ACCEPT)
target     prot opt source    destination  

那问题来了,既然有防火墙,为什么主从上有复制信息?

        我们看一下防火墙的规则,对于所有接受都禁止,所有输出没有限制,也就是说从服务器可以向主服务器发送各种命令或请求,但接受不到主服务器的响应,那么主从到底是如何连接的呢?

通过对照源码,我们从头梳理一下:

 如下是redis 服务器关于复制的部分属性结构,在server.c中 

    struct  redisServer{

          //. . . . . . . . . . . . . .

          /*Replication (slave)*/

          char *masterauth;           /* 主从认证 */

          char *masterhost;          /* 主服务器IP */

          int masterport;             /* 主服务器端口 */

          client *master;             /* Client that is master for this slave */

          int repl_timeout;        /* 复制超时 */

          int repl_state;          /* 从服务器的复制状态 */

         // . . . . . . . . . . . . . . . . 

    }

每个redis服务器在启动时都会将状态记录到该结构体的属性中,而相对应的在建立复制时,从服务器会将信息记录到以上属性中。

0?wx_fmt=png

      复制分为两个部分,分别是: 同步、命令传播 

跟踪同步阶段的连接阶段:

   1、用户通过客户端向从服务器发送slaveof命令,返回OK,此时,调用slaveofCommand函数判断语法格式,同时执行第2步

     127.0.0.1:6286> slaveof 192.168.164.231 6286

      OK

   2、从服务器将客户端给定的主服务器IP地址和端口保存到记录服务器状态的masterhost和masterport属性中,此时,调用replicationSetMaster函数修改属性值,同时修改repl状态,

    # Replication

     role:slave
     master_host:192.168.164.231
     master_port:6286

   3、从服务器根据保存的IP地址和端口,创建连向主服务器的套接字连接(即fd),如果成功,为套接字关联一个文件事件处理器

   4、主服务器在接受从服务器的套接字连接之后,将为该套接字创建相应的客户端状态,
          master_link_status:up
          127.0.0.1:6286> info replication
          # Replication
          role:master
          connected_slaves:1
          slave0:ip=192.168.164.232,port=6286,state=online,offset=5751,lag=0

  5、在连接的同时,创建的时间事件处理器,serverCron会隔一段时间执行一次,调用replicationCron,检查自己的复制状态,日志同文章前面的错误日志类似

        void replicationCron(void){

             if (server.repl_state == REPL_STATE_CONNECT) {
                 serverLog(LL_NOTICE,"Connecting to MASTER %s:%d",
                 server.masterhost, server.masterport);
             if (connectWithMaster() == C_OK) {                    #建立套接字,并将更改repl_state的值为connecting
                serverLog(LL_NOTICE,"MASTER <-> SLAVE sync started");
              }
         }

   5、之后主从服务器就会调用syncWithMaster函数,进行socket校验,如果二者不能互通,
         在日志中报错:Error condition on socket for SYNC: Connection refused

void syncWithMaster(void){

      . . . . .  . . 

     if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &sockerr, &errlen) == -1)

        sockerr = errno;
     if (sockerr) {
        serverLog(LL_WARNING,"Error condition on socket for SYNC: %s",
            strerror(sockerr));
        goto error;                           # 跳到错误处理,将repl_state置为connect,关闭socket 
    }

    . . . . . . . . . . . .

}

命令传播阶段:

     主从服务器默认会每秒一次的频率,向各自发送命令,主服务器如果没有收到响应,就会更改lag的值(>=1),

     slave0:ip=192.168.164.232,port=6286,state=online,offset=5751,lag=1 

 
0?wx_fmt=png

 这就是从服务器日志信息的源码流程

        对于sentinel的日志信息,也就并不难解释了,sentinel 启动后会每隔10秒,向被监控主机发送info命令,获取主服务器的信息,就会在consle打印从机信息,之后sentinel 就会向主从机发送info命令,而因为防火墙的原因,sentinel无法收到从机的响应,就会将它主观下线。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/30109892/viewspace-2088400/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/30109892/viewspace-2088400/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值