关于redis sentinel的启动

关于redis sentinel的启动
******************************************************************************
1启动方式
可以看到在server.c中,下面这一行判断是否是sentinel模式启动
server.sentinel_mode = checkForSentinelMode(argc,argv);
******************************************************************************
这个函数具体如下
/* Returns 1 if there is --sentinel among the arguments or if
 * argv[0] contains "redis-sentinel". */
如果在参数中间存在--sentinel或者第一个启动参数是redis-sentinel,那么就返回1,即是sentinel模式
int checkForSentinelMode(int argc, char **argv) {
    int j;

    if (strstr(argv[0],"redis-sentinel") != NULL) return 1;
    for (j = 1; j < argc; j++)
        if (!strcmp(argv[j],"--sentinel")) return 1;
    return 0;
}

所以我们可以采用
redis-sentinel sentinel.conf
或者
redis-server sentinel.conf --sentinel

当然你可以采用下面这种多余的模式
redis-sentinel sentinel.conf   --sentinel
******************************************************************************
2.初始化
可以看到在server.c中,存在如下的初始化sentinel的代码
    /* We need to init sentinel right now as parsing the configuration file
     * in sentinel mode will have the effect of populating the sentinel
     * data structures with master nodes to monitor. */
现在我们需要开始初始化sentinel,用sentinel的模式解析配置文件中的参数,
这样可以用主机节点的信息填充sentinel的数据结构,从而达到监督的目的
    if (server.sentinel_mode) {
        initSentinelConfig();
        initSentinel();
    }
这两个函数的具体逻辑如下
******************************************************************************
函数initSentinelConfig
/* This function overwrites a few normal Redis config default with Sentinel
 * specific defaults. */
这个函数用sentinel特殊的默认值重写一小部分正常的redis服务的默认配置
void initSentinelConfig(void) {
    server.port = REDIS_SENTINEL_PORT;  这里是端口号  #define REDIS_SENTINEL_PORT 26379
    server.protected_mode = 0; /* Sentinel must be exposed. */  sentinel必须能被访问,要不然起不到监督的作用
}
******************************************************************************
函数initSentinel
/* Perform the Sentinel mode initialization. */ 执行sentinel模式的初始化
void initSentinel(void) {
    unsigned int j;

    /* Remove usual Redis commands from the command table, then just add
     * the SENTINEL command. */
将常用的redis命令从命令表中移除,将sentinel的命令加入到表中
    dictEmpty(server.commands,NULL); 移除原来redis命令
    for (j = 0; j < sizeof(sentinelcmds)/sizeof(sentinelcmds[0]); j++) { 循环添加sentinel命令
        int retval;
        struct redisCommand *cmd = sentinelcmds+j;

        retval = dictAdd(server.commands, sdsnew(cmd->name), cmd); 添加新命令
        serverAssert(retval == DICT_OK);

        /* Translate the command string flags description into an actual
         * set of flags. */
         将命令字符串标志描述转换为实际的标志集合
        if (populateCommandTableParseFlags(cmd,cmd->sflags) == C_ERR)
            serverPanic("Unsupported command flag");
    }

    /* Initialize various data structures. */  初始化各种不同的数据结构
    sentinel.current_epoch = 0;
    sentinel.masters = dictCreate(&instancesDictType,NULL); 
    sentinel.tilt = 0;
    sentinel.tilt_start_time = 0;
    sentinel.previous_time = mstime();
    sentinel.running_scripts = 0;
    sentinel.scripts_queue = listCreate();
    sentinel.announce_ip = NULL;
    sentinel.announce_port = 0;
    sentinel.simfailure_flags = SENTINEL_SIMFAILURE_NONE;
    sentinel.deny_scripts_reconfig = SENTINEL_DEFAULT_DENY_SCRIPTS_RECONFIG;
    memset(sentinel.myid,0,sizeof(sentinel.myid));
}

常用的sentinel命令,命令都对应具体的处理函数
struct redisCommand sentinelcmds[] = {
    {"ping",pingCommand,1,"",0,NULL,0,0,0,0,0},
    {"sentinel",sentinelCommand,-2,"",0,NULL,0,0,0,0,0},
    {"subscribe",subscribeCommand,-2,"",0,NULL,0,0,0,0,0},
    {"unsubscribe",unsubscribeCommand,-1,"",0,NULL,0,0,0,0,0},
    {"psubscribe",psubscribeCommand,-2,"",0,NULL,0,0,0,0,0},
    {"punsubscribe",punsubscribeCommand,-1,"",0,NULL,0,0,0,0,0},
    {"publish",sentinelPublishCommand,3,"",0,NULL,0,0,0,0,0},
    {"info",sentinelInfoCommand,-1,"",0,NULL,0,0,0,0,0},
    {"role",sentinelRoleCommand,1,"ok-loading",0,NULL,0,0,0,0,0},
    {"client",clientCommand,-2,"read-only no-script",0,NULL,0,0,0,0,0},
    {"shutdown",shutdownCommand,-1,"",0,NULL,0,0,0,0,0},
    {"auth",authCommand,2,"no-auth no-script ok-loading ok-stale fast",0,NULL,0,0,0,0,0},
    {"hello",helloCommand,-2,"no-auth no-script fast",0,NULL,0,0,0,0,0}
};
***************************************************************************************
在主函数的定时任务函数serverCron中
存在Sentinel的定时任务, 如下:
/* Run the Sentinel timer if we are in sentinel mode. */
if (server.sentinel_mode) sentinelTimer();
***************************************************************************************
这个任务是redis服务初始化的时候注册的时间事件,具体的代码如下
void initServer(void) {
。。。。。。。
    /* Create the timer callback, this is our way to process many background
     * operations incrementally, like clients timeout, eviction of unaccessed
     * expired keys and so forth. */
    if (aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL) == AE_ERR) { 
    注册serverCron时间事件,这是我们注册的唯一一个时间事件
        serverPanic("Can't create event loop timers.");
        exit(1);
    }
。。。。。。。
}
***************************************************************************************
正常情况下,通过AE.C的代码,我们可以看到
函数aeCreateTimeEvent创建一个时间事件的时候,
long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds,
        aeTimeProc *proc, void *clientData,
        aeEventFinalizerProc *finalizerProc)
{
。。。。。。
    aeAddMillisecondsToNow(milliseconds,&te->when_sec,&te->when_ms); 这里的milliseconds就是触发下次事件间隔时间
。。。。。。
}
***************************************************************************************
具体的触发处理调用过程如下
/* Process time events */
static int processTimeEvents(aeEventLoop *eventLoop) {
。。。。。。
        aeGetTime(&now_sec, &now_ms);
        if (now_sec > te->when_sec ||
            (now_sec == te->when_sec && now_ms >= te->when_ms))
        {
            int retval;

            id = te->id;
            te->refcount++;
            retval = te->timeProc(eventLoop, id, te->clientData); 这里的处理函数就是我们之前注册的serverCron
            te->refcount--;
            processed++;
            if (retval != AE_NOMORE) { 
            如果不是一次性的时间,需要循环触发的,这里需要再次加上下次触发的间隔时间
            这里的retval是处理函数的返回值,所以需要查看serverCron的返回值,可以看到函数serverCron的返回值
            为 return 1000/server.hz;可以看到初始值为 server.hz = CONFIG_DEFAULT_HZ; #define CONFIG_DEFAULT_HZ 10   
            因此每个默认情况下,每隔100毫秒触发一次
                aeAddMillisecondsToNow(retval,&te->when_sec,&te->when_ms);
            } else {
                te->id = AE_DELETED_EVENT_ID;
            }
        }
。。。。。。。
}
接下来我们的sentinel定时器默认每隔100毫秒会调用一次,开始正常sentinel的正常工作
***************************************************************************************

 

posted on 2021-11-30 19:37  子虚乌有  阅读(180)  评论(0)    收藏  举报