[size=x-large][color=black][b]Redis 哨兵的服务框架[/b][/color][/size]
哨兵也是 Redis 服务器,只是它与我们平时提到的 Redis 服务器职能不同,哨兵负责监视普通的 Redis 服务器,提高一个服务器集群的健壮和可靠性。哨兵和普通的 Redis 服务器所用的是同一套服务器框架,这包括:网络框架,底层数据结构,订阅发布机制等。
从主函数开始,来看看哨兵服务器是怎么诞生,它在什么时候和普通的 Redis 服务器分道扬镳:
在上面,通过判断命令行参数来判断 Redis 服务器是否启用哨兵模式,会设置服务器参数结构体中的redisServer.sentinel_mode 的值。在上面的主函数调用了一个很关键的函数:initSentinel(),它完成了哨兵服务器特有的初始化程序,包括填充哨兵服务器特有的命令表,struct sentinel 结构体。
我们查看 struct redisCommand sentinelcmds 这个全局变量就会发现,它里面只有七个命令,难道哨兵仅仅提供了这种服务?为了能让哨兵自动管理普通的 Redis 服务器,哨兵还添加了一个定时程序,我们从 serverCron() 定时程序中就会发现,哨兵的定时程序被调用执行了,这里包含了哨兵的主要工作:
[size=x-large][color=black][b]定时程序[/b][/color][/size]
定时程序是哨兵服务器的重要角色,所做的工作主要包括:监视普通的 Redis 服务器(包括主机和从机),执行故障修复,执行脚本命令。
[size=x-large][color=black][b]哨兵与 Redis 服务器的互联[/b][/color][/size]
每个哨兵都有一个 struct sentinel 结构体,里面维护了多个主机的连接,与每个主机连接的相关信息都存储在 struct sentinelRedisInstance。透过这两个结构体,很快就可以描绘出,一个哨兵服务器所维护的机器的信息:
哨兵服务器所能描述的 Redis 信息:
[img]http://wiki.jikexueyuan.com/project/redis/images/a.png[/img]
参考:http://p.primeton.com/articles/559e431d608f8f5438000059
http://wiki.jikexueyuan.com/project/redis/guard-mechanism.html
哨兵也是 Redis 服务器,只是它与我们平时提到的 Redis 服务器职能不同,哨兵负责监视普通的 Redis 服务器,提高一个服务器集群的健壮和可靠性。哨兵和普通的 Redis 服务器所用的是同一套服务器框架,这包括:网络框架,底层数据结构,订阅发布机制等。
从主函数开始,来看看哨兵服务器是怎么诞生,它在什么时候和普通的 Redis 服务器分道扬镳:
int main(int argc, char **argv) {
// 随机种子,一般rand() 产生随机数的函数会用到
srand(time(NULL)^getpid());
gettimeofday(&tv,NULL);
dictSetHashFunctionSeed(tv.tv_sec^tv.tv_usec^getpid());
// 通过命令行参数确认是否启动哨兵模式
server.sentinel_mode = checkForSentinelMode(argc,argv);
// 初始化服务器配置,主要是填充redisServer 结构体中的各种参数
initServerConfig();
// 将服务器配置为哨兵模式,与普通的redis 服务器不同
/* 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. */
if (server.sentinel_mode) {
// initSentinelConfig() 只指定哨兵服务器的端口
initSentinelConfig();
initSentinel();
}
......
// 普通redis 服务器模式
if (!server.sentinel_mode) {
......
// 哨兵服务器模式
} else {
// 检测哨兵模式是否正常配置
sentinelIsRunning();
}
......
// 进入事件循环
aeMain(server.el);
// 去除事件循环系统
aeDeleteEventLoop(server.el);
return 0;
}在上面,通过判断命令行参数来判断 Redis 服务器是否启用哨兵模式,会设置服务器参数结构体中的redisServer.sentinel_mode 的值。在上面的主函数调用了一个很关键的函数:initSentinel(),它完成了哨兵服务器特有的初始化程序,包括填充哨兵服务器特有的命令表,struct sentinel 结构体。
// 哨兵服务器特有的初始化程序
/* Perform the Sentinel mode initialization. */
void initSentinel(void) {
int j;
// 如果 redis 服务器是哨兵模式,则清空命令列表。哨兵会有一套专门的命令列表,
// 这与普通的 redis 服务器不同
/* Remove usual Redis commands from the command table, then just add
* the SENTINEL command. */
dictEmpty(server.commands,NULL);
// 将sentinelcmds 命令列表中的命令填充到server.commands
for (j = 0; j < sizeof(sentinelcmds)/sizeof(sentinelcmds[0]); j++) {
int retval;
struct redisCommand *cmd = sentinelcmds+j;
retval = dictAdd(server.commands, sdsnew(cmd->name), cmd);
redisAssert(retval == DICT_OK);
}
/* Initialize various data structures. */
// sentinel.current_epoch 用以指定版本
sentinel.current_epoch = 0;
// 哨兵监视的 redis 服务器哈希表
sentinel.masters = dictCreate(&instancesDictType,NULL);
// sentinel.tilt 用以处理系统时间出错的情况
sentinel.tilt = 0;
// TILT 模式开始的时间
sentinel.tilt_start_time = 0;
// sentinel.previous_time 是哨兵服务器上一次执行定时程序的时间
sentinel.previous_time = mstime();
// 哨兵服务器当前正在执行的脚本数量
sentinel.running_scripts = 0;
// 脚本队列
sentinel.scripts_queue = listCreate();
}我们查看 struct redisCommand sentinelcmds 这个全局变量就会发现,它里面只有七个命令,难道哨兵仅仅提供了这种服务?为了能让哨兵自动管理普通的 Redis 服务器,哨兵还添加了一个定时程序,我们从 serverCron() 定时程序中就会发现,哨兵的定时程序被调用执行了,这里包含了哨兵的主要工作:
int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
......
run_with_period(100) {
if (server.sentinel_mode) sentinelTimer();
}
}[size=x-large][color=black][b]定时程序[/b][/color][/size]
定时程序是哨兵服务器的重要角色,所做的工作主要包括:监视普通的 Redis 服务器(包括主机和从机),执行故障修复,执行脚本命令。
// 哨兵定时程序
void sentinelTimer(void) {
// 检测是否需要启动sentinel TILT 模式
sentinelCheckTiltCondition();
// 对哈希表中的每个服务器实例执行调度任务,这个函数很重要
sentinelHandleDictOfRedisInstances(sentinel.masters);
// 执行脚本命令,如果正在执行脚本的数量没有超出限定
sentinelRunPendingScripts();
// 清理已经执行完脚本的进程,如果执行成功从脚本队列中删除脚本
sentinelCollectTerminatedScripts();
// 停止执行时间超时的脚本进程
sentinelKillTimedoutScripts();
// 为了防止多个哨兵同时选举,故意错开定时程序执行的时间。通过调整周期可以
// 调整哨兵定时程序执行的时间,即默认值REDIS_DEFAULT_HZ 加上一个任意值
server.hz = REDIS_DEFAULT_HZ + rand() % REDIS_DEFAULT_HZ;
}[size=x-large][color=black][b]哨兵与 Redis 服务器的互联[/b][/color][/size]
每个哨兵都有一个 struct sentinel 结构体,里面维护了多个主机的连接,与每个主机连接的相关信息都存储在 struct sentinelRedisInstance。透过这两个结构体,很快就可以描绘出,一个哨兵服务器所维护的机器的信息:
typedef struct sentinelRedisInstance {
......
/* Master specific. */
// 其他正在监视此主机的哨兵
dict *sentinels; /* Other sentinels monitoring the same master. */
// 次主机的从机列表
dict *slaves; /* Slaves for this master instance. */
......
// 如果是从机,master 则指向它的主机
struct sentinelRedisInstance *master; /* Master instance if it's slave. */
......
} sentinelRedisInstance;哨兵服务器所能描述的 Redis 信息:
[img]http://wiki.jikexueyuan.com/project/redis/images/a.png[/img]
参考:http://p.primeton.com/articles/559e431d608f8f5438000059
http://wiki.jikexueyuan.com/project/redis/guard-mechanism.html
本文介绍了Redis哨兵的服务框架,包括其如何与普通Redis服务器交互、如何通过定时程序执行主要任务,如监视、故障恢复及命令执行等。
956

被折叠的 条评论
为什么被折叠?



