编者: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服务器在启动时都会将状态记录到该结构体的属性中,而相对应的在建立复制时,从服务器会将信息记录到以上属性中。
复制分为两个部分,分别是: 同步、命令传播
跟踪同步阶段的连接阶段:
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
这就是从服务器日志信息的源码流程
对于sentinel的日志信息,也就并不难解释了,sentinel 启动后会每隔10秒,向被监控主机发送info命令,获取主服务器的信息,就会在consle打印从机信息,之后sentinel 就会向主从机发送info命令,而因为防火墙的原因,sentinel无法收到从机的响应,就会将它主观下线。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/30109892/viewspace-2088400/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/30109892/viewspace-2088400/