摘要:本系列通过作者对Redis Sentinel源码的理解,详细说明Sentinel的代码实现方式。

Redis Sentinel 是Redis提供的高可用模型解决方案。Sentinel可以自动监测一个或多个Redis主备实例,并在主实例宕机的情况下自动实行主备倒换。本系列通过作者对Redis Sentinel源码的理解,详细说明Sentinel的代码实现方式。

Sentinel使用Redis内核相同的事件驱动代码框架, 但Sentinel有自己独特的初始化步骤。在这篇文章里,作者会介绍Sentinel与Redis服务器不同的初始化部分。

我们可以通过redis-sentinel <path-to-configfile> 或者 redis-server <path-to-configfile> --sentinel 这两种方式启动并运行Sentinel实例,这两种方式是等价的。在Redis server.c 的main函数中,我们会看到Redis如何判断用户指定以Sentinel方式运行的逻辑:

int main(int argc, char **argv) { .......... server.sentinel_mode = checkForSentinelMode(argc,argv); ..........
} 

其中checkForSentinelMode函数会监测以下两种条件:

1. 程序使用redis-sentinel可执行文件执行。

2. 程序参数列表中有--sentinel 标志。

以上任何一种条件成立则Redis会使用Sentinel的方式运行。

/* Returns 1 if there is --sentinel among the arguments or if * argv[0] contains "redis-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的方式运行以后,我们会看到如下代码段:

int main(int argc, char **argv) { struct timeval tv; int j; ............
/* 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(); initSentinel(); } ............

在initSentinelConfig函数中,会使用Sentinel特定的端口(默认为26379)来替代Redis的默认端口(6379)。另外,在Sentinel模式下,需要禁用服务器运行保护模式。

/* This function overwrites a few normal Redis config default with Sentinel * specific defaults. */
void initSentinelConfig(void) { server.port = REDIS_SENTINEL_PORT; server.protected_mode = 0; /* Sentinel must be exposed. */
}

与此同时,initSentinel函数会做如下操作:

/* Perform the Sentinel mode initialization. */
void initSentinel(void) { unsigned int j; /* Remove usual Redis commands from the command table, then just add * the SENTINEL command. */ dictEmpty(server.commands,NULL); 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); serverAssert(retval == DICT_OK); {"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}
};

2.初始化Sentinel主状态结构,Sentinel主状态的定义及注释如下。

/* Main state. */ struct sentinelState { char myid[CONFIG_RUN_ID_SIZE+1]; /* This sentinel ID. */ uint64_t current_epoch; /* Current epoch. */ dict *masters; /* Dictionary of master sentinelRedisInstances. Key is the instance name, value is the sentinelRedisInstance structure pointer. */ int tilt; /* Are we in TILT mode? */ int running_scripts; /* Number of scripts in execution right now. */ mstime_t tilt_start_time; /* When TITL started. */ mstime_t previous_time; /* Last time we ran the time handler. */ list *scripts_queue; /* Queue of user scripts to execute. */ char *announce_ip; /* IP addr that is gossiped to other sentinels if not NULL. */ int announce_port; /* Port that is gossiped to other sentinels if non zero. */ unsigned long simfailure_flags; /* Failures simulation. */ int deny_scripts_reconfig; /* Allow SENTINEL SET ... to change script paths at runtime? */ } sentinel; 

其中masters字典指针中的每个值都对应着一个Sentinel检测的主实例。

在读取配置信息后,Redis服务器主函数会调用sentinelIsRunning函数, 做以下几个工作:

1. 检查配置文件是否被设置,并且检查程序对配置文件是否有写权限,因为如果Sentinel状态改变的话,会不断将自己当前状态记录在配置文件中。

2. 如果在配置文件中指定运行ID,Sentinel 会使用这个ID作为运行ID,相反地,如果没有指定运行ID,Sentinel会生成一个ID用来作为Sentinel的运行ID。

3. 对所有的Sentinel监测实例产生初始监测事件。

/* This function gets called when the server is in Sentinel mode, started, * loaded the configuration, and is ready for normal operations. */
void sentinelIsRunning(void) { int j; if (server.configfile == NULL) { serverLog(LL_WARNING, "Sentinel started without a config file. Exiting..."); exit(1); } else if (access(server.configfile,W_OK) == -1) { serverLog(LL_WARNING, "Sentinel config file %s is not writable: %s. Exiting...", server.configfile,strerror(errno)); exit(1); } /* If this Sentinel has yet no ID set in the configuration file, we * pick a random one and persist the config on disk. From now on this * will be this Sentinel ID across restarts. */ for (j = 0; j < CONFIG_RUN_ID_SIZE; j++) if (sentinel.myid[j] != 0) break; if (j == CONFIG_RUN_ID_SIZE) { /* Pick ID and persist the config. */ getRandomHexChars(sentinel.myid,CONFIG_RUN_ID_SIZE); sentinelFlushConfig(); } /* Log its ID to make debugging of issues simpler. */serverLog(LL_WARNING,"Sentinel ID is %s", sentinel.myid); /* We want to generate a +monitor event for every configured master * at startup. */ sentinelGenerateInitialMonitorEvents();
}

参考资料:

https://github.com/antirez/redis

https://redis.io/topics/sentinel

Redis设计与实现第二版 黄健宏著

本文分享自华为云社区《Redis Sentinel 源码分析(1)Sentinel的初始化》,原文作者:中间件小哥 。

点击关注,第一时间了解华为云新鲜技术~

一文带你探究Sentinel的独特初始化相关推荐

  1. 带您探究云存储的奥秘,三分钟帮您快速了解OSS

    摘要: 快来,带您探究云存储的奥秘,三分钟帮您快速了解OSS. 阿里云对象存储服务,简称 OSS,是一种面向海量数据规模的分布式存储服务,具有稳定.可靠.安全.低成本的特点,能够提供十一个九的数据可靠 ...

  2. python中集合运算_入门 | 一文带你了解Python集合与基本的集合运算

    原标题:入门 | 一文带你了解Python集合与基本的集合运算 选自DataCamp 作者:Michael Galarnyk 参与:Geek Ai.思源 一般我们熟悉 Python 中列表.元组及字典 ...

  3. 一文带你搞懂从动态代理实现到Spring AOP

    摘要:本文主要讲了Spring Aop动态代理实现的两种方式. 1. Spring AOP Spring是一个轻型容器,Spring整个系列的最最核心的概念当属IoC.AOP.可见AOP是Spring ...

  4. 一文带你全方位(架构,原理及代码实现)了解Flink(3.2W字建议收藏)

    注:最底部有PDF目录 一 flink简介 1.1 什么是flink Apache Flink是由Apache软件基金会开发的开源流处理框架,其核心是用Java和Scala编写的分布式流数据流引擎.F ...

  5. RPC框架:一文带你搞懂RPC

    RPC是什么(GPT答) ChatGPT回答: RPC(Remote Procedure Call)是一种分布式应用程序的编程模型,允许程序在不同的计算机上运行.它以一种透明的方式,将一个程序的函数调 ...

  6. 精华推荐 | 【JVM深层系列】「GC底层调优系列」一文带你彻底加强夯实底层原理之GC垃圾回收技术的分析指南(GC原理透析)

    前提介绍 很多小伙伴,都跟我反馈,说自己总是对JVM这一块的学习和认识不够扎实也不够成熟,因为JVM的一些特性以及运作机制总是混淆以及不确定,导致面试和工作实战中出现了很多的纰漏和短板,解决广大小伙伴 ...

  7. RPC框架:从原理到选型,一文带你搞懂RPC

    大家好,我是华仔,RPC系列的文章是我去年写的,当时写的比较散,现在重新进行整理.对于想学习RPC框架的同学,通过这篇文章,让你知其然并知其所以然,便于以后技术选型,下面是文章内容目录: RPC 什么 ...

  8. 计算机知识有什么用处,电脑内存作用是什么?一文带你了解电脑内存的基础知识...

    电脑内存是电脑中至关重要的硬件之一,是不可或缺的硬件.电脑内存作用是什么?下面装机之家一文带你了解电脑内存的基础知识,来看看吧! 电脑内存作用是什么? 内存是其他设备与CPU进行沟通的桥梁,计算机中所 ...

  9. linux awk语法格式,Awk是什么?一文带运维小白快速掌握Linux Awk用法

    原标题:Awk是什么?一文带运维小白快速掌握Linux Awk用法 作者:a8 Awk.sed与grep,俗称Linux下的三剑客,它们之间有很多相似点,但是同样也各有各的特色,相似的地方是它们都可以 ...

最新文章

  1. 手把手教你简单接入微信SDK
  2. RNAseq-GO、biomaRt转换ID
  3. 第四范式完成C+轮融资,估值约20亿美元
  4. c++ char*初始化_C开发实战-深入理解指针
  5. 开发指南专题十七-JEECG图表配置说明
  6. 日出时的画面_如何拍摄日出日落,老摄影家近30年创作经验分享
  7. eclipse springmvc+Thymeleaf
  8. 简记GAN网络的loss
  9. 怎么知道他人的 IP
  10. 网站盗取html文件工具,一键获取仿站精灵
  11. 吉他音阶训练——问题解答 (三)
  12. 用python来开发webgame服务端
  13. winpe 安装 win7 过程问题综述
  14. 红蓝对抗--sliver 搭建
  15. jquery简单赋值取值
  16. 什么是JS面向对象?
  17. 帝国cms 修改系统自带语言模板文件
  18. 2022年上海医院三基考试仿真试题(含答案)
  19. Wolfram Alpha 算微积分指令集合
  20. 注解 @TableField(exist = false) 注明非数据库字段属性

热门文章

  1. 人的手臂的自由度的数目以及六自由度机械臂的限制
  2. extjs 点击下拉框三角形触发事件_省市县三级联动下拉框的具体实现
  3. 社团管理系统用c语言1000,图书馆管理系统C语言啊1000行啊,哪位老哥有啊??...
  4. oracle dcd设置,Oracle配置DCD避免会话被防火墙强制断开
  5. 光驱怎么挂载第二个光驱_电脑光驱经常自己打开自己关闭,怎么回事
  6. (转) intellij idea部署web项目时的位置(Tomcat)
  7. python迭代-可迭代对象与迭代器对象
  8. git回滚命令reset、revert的区别
  9. Eclipse中Hibernate插件的安装
  10. Linux下ftp的安装配置