1.sentinelHandleRedisInstance中哨兵的工作
参考上文中的2.4.2.1节,这一节给出来sentinelTimer中第二步sentinelHandleDictOfRedisInstances(sentinel.masters)-【对Sentinel监控的所有主节点进行递归式的执行周期性操作】的内容概要介绍.
1.1 sentinelReconnectInstance-重新建立连接
参考上文中的2.4.2.1.1节.
1.2 sentinelSendPeriodicCommands-发送监控命令
/* Send periodic PING, INFO, and PUBLISH to the Hello channel to
* the specified master or slave instance. */
void sentinelSendPeriodicCommands(sentinelRedisInstance *ri) {
mstime_t now = mstime();
mstime_t info_period, ping_period;
int retval;
/* Return ASAP if we have already a PING or INFO already pending, or
* in the case the instance is not properly connected. */
/* 如果ri实例连接处于关闭状态,直接返回 */
if (ri->link->disconnected) return;
/* For INFO, PING, PUBLISH that are not critical commands to send we
* also have a limit of SENTINEL_MAX_PENDING_COMMANDS. We don't
* want to use a lot of memory just because a link is not working
* properly (note that anyway there is a redundant protection about this,
* that is, the link will be disconnected and reconnected if a long
* timeout condition is detected. */
/*
对于不是发送如INFO,PING,PUBLISH等关键命令的请求,我们设置宏
SENTINEL_MAX_PENDING_COMMANDS对最大请求数进行限制,我们不想连接
对象在无法正常工作的情况下占用大量的内存(请注意,无论如何,我们
还有一个冗余的保护措施,即如果检测到长时间的超时条件,连接将被断
开连接并重新连接
#define SENTINEL_MAX_PENDING_COMMANDS 100
内存保护策略
如果待执行的命令大于100乘以连接的引用数,那么就返回
*/
if (ri->link->pending_commands >=
SENTINEL_MAX_PENDING_COMMANDS * ri->link->refcount) return;
/* If this is a slave of a master in O_DOWN condition we start sending
* it INFO every second, instead of the usual SENTINEL_INFO_PERIOD
* period. In this state we want to closely monitor slaves in case they
* are turned into masters by another Sentinel, or by the sysadmin.
*
* Similarly we monitor the INFO output more often if the slave reports
* to be disconnected from the master, so that we can have a fresh
* disconnection time figure. */
/*
如果ri是从节点,且他的主节点处于故障状态的状态或者从节点和主节点断开复制了
*/
if ((ri->flags & SRI_SLAVE) &&
((ri->master->flags & (SRI_O_DOWN|SRI_FAILOVER_IN_PROGRESS)) ||
(ri->master_link_down_time != 0)))
{
/* 设置INFO命令的周期时间为1s */
info_period = 1000;
} else {
/* 否则就是默认的10s
#define SENTINEL_INFO_PERIOD 10000
*/
info_period = SENTINEL_INFO_PERIOD;
}
/* We ping instances every time the last received pong is older than
* the configured 'down-after-milliseconds' time, but every second
* anyway if 'down-after-milliseconds' is greater than 1 second. */
/*
每次最后一次接收到的PONG的间隔时间比配置的 'down-after-milliseconds' 时间更长,
但是如果 'down-after-milliseconds'大于1秒,则每秒钟进行一次ping
*/
/* 获取down_after_period,过了down_after_period这段时间,就可以认为它下线了 */
ping_period = ri->down_after_period;
if (ping_period > SENTINEL_PING_PERIOD) ping_period = SENTINEL_PING_PERIOD;
/* Send INFO to masters and slaves, not sentinels. */
/*
如果实例不是Sentinel节点且Sentinel节点从该数据节点(主节点或从节点)
没有收到过INFO回复或者收到INFO回复超时,则发送INFO命令给主节点和从节点
*/
if ((ri->flags & SRI_SENTINEL) == 0 &&
(ri->info_refresh == 0 ||
(now - ri->info_refresh) > info_period))
{
/* 发送INFO命令给主节点和从节点,具体见下文分析 */
retval = redisAsyncCommand(ri->link->cc,
sentinelInfoReplyCallback, ri, "%s",
sentinelInstanceMapCommand(ri,"INFO"));
/* 已发送未回复的命令个数加1 */
if (retval == C_OK) ri->link->pending_commands++;
}
/* Send PING to all the three kinds of instances. */
/* 如果发送和回复PING命令超时, 调用sentinelSendPing(ri),具体见下文分析 */
if ((now - ri->link->last_pong_time) > ping_period &&
(now - ri->link->last_ping_time) > ping_period/2) {
sentinelSendPing(ri);
}
/* PUBLISH hello messages to all the three kinds of instances. */
/* 如果发送频道的定时命令超时,调用sentinelSendHello,具体见下文分析 */
if ((now - ri->last_pub_time) > SENTINEL_PUBLISH_PERIOD) {
sentinelSendHello(ri);
}
}
补充一些枚举值:
/* Note: times are in milliseconds. */
#define SENTINEL_INFO_PERIOD 10000
#define SENTINEL_PING_PERIOD 1000
#define SENTINEL_ASK_PERIOD 1000
#define SENTINEL_PUBLISH_PERIOD 2000
#define SENTINEL_DEFAULT_DOWN_AFTER 30000
#define SENTINEL_HELLO_CHANNEL "__sentinel__:hello"
#define SENTINEL_TILT_TRIGGER 2000
#define SENTINEL_TILT_PERIOD (SENTINEL_PING_PERIOD*30)
#define SENTINEL_DEFAULT_SLAVE_PRIORITY 100
#define SENTINEL_SLAVE_RECONF_TIMEOUT 10000
#define SENTINEL_DEFAULT_PARALLEL_SYNCS 1
#define SENTINEL_MIN_LINK_RECONNECT_PERIOD 15000
#define SENTINEL_DEFAULT_FAILOVER_TIMEOUT (60*3*1000)
#define SENTINEL_MAX_PENDING_COMMANDS 100
#define SENTINEL_ELECTION_TIMEOUT 10000
#define SENTINEL_MAX_DESYNC 1000
#define SENTINEL_DEFAULT_DENY_SCRIPTS_RECONFIG 1
1.2.1 INFO
1.上文中进行了如下调用:
{
...
retval = redisAsyncCommand(ri->link->cc,
sentinelInfoReplyCallback, ri, "%s",
sentinelInstanceMapCommand(ri,"INFO"));
if (retval == C_OK) ri->link->pending_commands++;
...
}
2.看看redisAsyncCommand的实现
int redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, ...) {
va_list ap;
int status;
va_start(ap,format);
status = redisvAsyncCommand(ac,fn,privdata,format,ap);
va_end(ap);
return status;
}
3. sentinelInfoReplyCallback是处理INFO命令返回信息的回调函数,sentinelInfoReplyCallback
很长,逻辑很多.
1.2.2 PING
1.2.3 PUBLISH