redis源码分析(七):集群--哨兵模式

redis在启动时,如果进程名是"redis-sentinel",或者参数中带了"--sentinel",这时redis便以哨兵的方式运行。一个sentinel可以监控多个master。

sentinel的配置如下


// 当前Sentinel节点监控 127.0.0.1:6379 这个主节点
// 2代表判断主节点失败至少需要2个Sentinel节点节点同意
// mymaster是主节点的别名
sentinel monitor mymaster 127.0.0.1 6379 2

//每个Sentinel节点都要定期PING命令来判断Redis数据节点和其余Sentinel节点是否可达,如果超过30000毫秒且没有回复,则判定不可达
sentinel down-after-milliseconds mymaster 30000

//当Sentinel节点集合对主节点故障判定达成一致时,Sentinel领导者节点会做故障转移操作,选出新的主节点,原来的从节点会向新的主节点发起复制操作,限制每次向新的主节点发起复制操作的从节点个数为1
sentinel parallel-syncs mymaster 1

//故障转移超时时间为180000毫秒
sentinel failover-timeout mymaster 180000

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},
    {"shutdown",shutdownCommand,-1,"",0,NULL,0,0,0,0,0}
};

sentinel的时间事件也区别于一般服务,入口是sentinelTimer。

void sentinelTimer(void) {

    // 记录本次 sentinel 调用的事件,
    // 并判断是否需要进入 TITL 模式
    sentinelCheckTiltCondition();

    // 执行定期操作
    // 比如 PING 实例、分析主服务器和从服务器的 INFO 命令
    // 向其他监视相同主服务器的 sentinel 发送问候信息
    // 并接收其他 sentinel 发来的问候信息
    // 执行故障转移操作,等等
    sentinelHandleDictOfRedisInstances(sentinel.masters);

    // 运行等待执行的脚本
    sentinelRunPendingScripts();

    // 清理已执行完毕的脚本,并重试出错的脚本
    sentinelCollectTerminatedScripts();

    // 杀死运行超时的脚本
    sentinelKillTimedoutScripts();

    /* We continuously change the frequency of the Redis "timer interrupt"
     * in order to desynchronize every Sentinel from every other.
     * This non-determinism avoids that Sentinels started at the same time
     * exactly continue to stay synchronized asking to be voted at the
     * same time again and again (resulting in nobody likely winning the
     * election because of split brain voting). */
    server.hz = REDIS_DEFAULT_HZ + rand() % REDIS_DEFAULT_HZ;
}

一次时间事件中,主要做了以下几件事情。

  • 1.判断是否上次执行时间事件距今是否差了超过了2秒,则进入默认持续30秒的TITL模式,进入了此模式的sentinel认为当前自身的状态可能是有问题的,会阉割一部分选举master相关的功能。

  • 2.连接其他master/slave/sentinel,发送auth命令,master的地址是配置文件配好的,所以可以直接拿到;slave和其他sentinel的地址通过master拿到。

  • 3.向master和slave定期发送 ping,info命令。其中info命令可以得到对方的运行状态,主从关系等。

  • 4.哨兵在连接建立的时候会向master和其slave订阅频道"_sentinel_:hello"的消息,同时周期性的发布一条hello消息,给其他哨兵打招呼,这条消息包含了自身地址,自身runid,自身的epoch,master的基本信息和epoch。
    假设有个哨兵B也是检测这个master的,会接受到A发送的推送,把A保存到自己的哨兵列表中。

  • 5.根据redis服务回复ping的情况,判断redis是否已经主观下线(Subject Down),如果下线了,将结果告知给其他sentinel。

  • 6.如果master主观下线了,判断这个master是否客观下线(Object Down),方法就是收集其他sentinel的意见,如果认为该master下线的sentinel数量大于配置,则认为这个master下线了,此时开始执行故障转移逻辑(Failover)。

  • 7.故障转移,分为以下步骤:
    1)选举头领(leader)
    1-1)首先向其他sentinel发送纪元编号(为本sentinel自身当前的纪元自增1,同时记录为故障master的纪元),如果其他纪元收到了这条消息,如果比自己的大,则更新为此纪元,否则忽略;
    1-2)统计这个故障master下的所有sentinel投票结果,如果已经有其他sentinel发表意见了,则选取最高得票者,投他一票,如果没有,投自己一票。此时,如果最高得票者的得票数超过半数+1,则本次选举完成,否则进入下个纪元。引入纪元(epoch)这个参数是因为,选举不是每次都成功的,比如所有sentinel都选举了自己,这种情况下需要重新启动下一轮投票。
    2)由leader从slave当中选择一个作为新的master。
    2-1) 过滤掉Down掉的slave,判断slave的Info回复时长和与master的连接状态,太差的slave不考虑。
    2-2) 对符合条件的slave排序以选出最优,依据分别是slave的优先级,从原master复制的数据量大小,runid。

    1. 向选出来的slave发送 slaveof no one来提升该slave为master。确定该服务提升为master之后,给其他slave发送slaveof命令。
sentinel内部状态发生变化时,会调用sentinelEvent方法广播状态,我们可以使用redis-cli连接sentinel,用subscribe来查看sentinel的内部运行状态,可以订阅多个状态,用空格隔开,本机测试:
localhost:Debug jjchen$ redis-cli -p 26379
redis> subscribe +tilt -tilt
Reading messages... (press Ctrl-c to quit)
1. "subscribe"
2. "+tilt"
3. (integer) 1

1. "subscribe"
2. "-tilt"
3. (integer) 2

1. "message"
2. "+tilt"
3. "#tilt mode entered"

1. "message"
2. "-tilt"
3. "#tilt mode exited"

1. "message"
2. "+tilt"
3. "#tilt mode entered"
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,463评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,868评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,213评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,666评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,759评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,725评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,716评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,484评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,928评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,233评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,393评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,073评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,718评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,308评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,538评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,338评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,260评论 2 352

推荐阅读更多精彩内容