> 文章列表 > 详解redis的哨兵模式(1)

详解redis的哨兵模式(1)

详解redis的哨兵模式(1)

目录

1.背景

 2.实现过程

2.1)初始化服务器

 2.2)将普通Redis服务器使用的代码替换成Sentinel专用代码

2.3初始化Sentinel状态

2.4初始化sentinel状态的masters属性

2.5创建连向主服务器的网络连接

3.获取服务器信息

3.1获取主服务器信息

 3.2获取从服务器的信息


1.背景

Sentinel(哨岗、哨兵)是Redis的高可用性(high availability)解决 方案:由一个或多个Sentinel实例(instance)组成的Sentinel系统 (system)可以监视任意多个主服务器,以及这些主服务器属下的所有 从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务 器属下的某个从服务器升级为新的主服务器,然后由新的主服务器代替 已下线的主服务器继续处理命令请求。

图解1:

 解析:

1.用双环图案表示的是当前的主服务器server1。

2.用单环图案表示的是主服务器的三个从服务器server2、server3以 及server4。

3.server2、server3、server4三个从服务器正在复制主服务器server1, 而Sentinel系统则在监视所有四个服务器

图解二:

 

主服务器server1进入下线状态,那么从服务器server2、 server3、server4对主服务器的复制操作将被中止,并且Sentinel系统会察 觉到server1已下线

解析1

首先,Sentinel系统会挑选server1属下的其中一个从服务器,并将这个被选中的从服务器升级为新的主服务器。

·之后,Sentinel系统会向server1属下的所有从服务器发送新的复制 指令,让它们成为新的主服务器的从服务器,当所有从服务器都开始复制新的主服务器时,故障转移操作执行完毕。

图解三:Sentinel还会继续监视已下线的server1,并在它重新上线时,将它设置为新的主服务器的从服务器

 

 2.实现过程

$ redis-sentinel /path/to/your/sentinel.conf

当一个Sentinel启动时,它需要执行以下步骤:

1)初始化服务器。

2)将普通Redis服务器使用的代码替换成Sentinel专用代码。

3)初始化Sentinel状态。

4)根据给定的配置文件,初始化Sentinel的监视主服务器列表。

5)创建连向主服务器的网络连接。

2.1)初始化服务器

首先,因为Sentinel本质上只是一个运行在特殊模式下的Redis服务器,所以启动Sentinel的第一步,就是初始化一个普通的Redis服务器.

区别:Redis服务器在Sentinel模式下运行时,服务器各个主要功能的使用情况

 2.2)将普通Redis服务器使用的代码替换成Sentinel专用代码

启动Sentinel的第二个步骤就是将一部分普通Redis服务器使用的代 码替换成Sentinel专用代码

比如:

普通Redis服务器使用 redis.h/REDIS_SERVERPORT常量的值作为服务器端口:

#define REDIS_SERVERPORT 6379

Sentinel则使用sentinel.c/REDIS_SENTINEL_PORT常量的值作为 服务器端口

#define REDIS_SENTINEL_PORT 26379

普通Redis服务器使用redis.c/redisCommandTable作为服 务器的命令表

struct redisCommand redisCommandTable[] = {
{"get",getCommand,2,"r",0,NULL,1,1,1,0,0},
{"set",setCommand,-3,"wm",0,noPreloadGetKeys,1,1,1,0,0},
{"setnx",setnxCommand,3,"wm",0,noPreloadGetKeys,1,1,1,0,0},
// ...
{"script",scriptCommand,-2,"ras",0,NULL,0,0,0,0,0},
{"time",timeCommand,1,"rR",0,NULL,0,0,0,0,0},
{"bitop",bitopCommand,-4,"wm",0,NULL,2,-1,1,0,0},
{"bitcount",bitcountCommand,-2,"r",0,NULL,1,1,1,0,0}
}

而Sentinel则使用sentinel.c/sentinelcmds作为服务器的命令表,并且 其中的INFO命令会使用Sentinel模式下的专用实现 sentinel.c/sentinelInfoCommand函数


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

与上面相呼应:PING、SENTINEL、INFO、 SUBSCRIBE、UNSUBSCRIBE、PSUBSCRIBE和PUNSUBSCRIBE这七 个命令就是客户端可以对Sentinel执行的全部命令了

2.3初始化Sentinel状态

在应用了Sentinel的专用代码之后,接下来,服务器会初始化一个 sentinel.c/sentinelState结构(后面简称“Sentinel状态”),这个结构保存 了服务器中所有和Sentinel功能有关的状态(服务器的一般状态仍然由 redis.h/redisServer结构保存)

struct sentinelState {
//
当前纪元,用于实现故障转移
uint64_t current_epoch;
//
保存了所有被这个sentinel
监视的主服务器
//
字典的键是主服务器的名字
//
字典的值则是一个指向sentinelRedisInstance
结构的指针
dict *masters;
//
是否进入了TILT
模式?
int tilt;
//
目前正在执行的脚本的数量
int running_scripts;
//
进入TILT
模式的时间
mstime_t tilt_start_time;
//
最后一次执行时间处理器的时间
mstime_t previous_time;
//
一个FIFO
队列,包含了所有需要执行的用户脚本
list *scripts_queue;
} sentinel;

2.4初始化sentinel状态的masters属性

Sentinel状态中的masters字典记录了所有被Sentinel监视的主服务器 的相关信息,

其中:

·字典的键是被监视主服务器的名字。

·而字典的值则是被监视主服务器对应的 sentinel.c/sentinelRedisInstance结构. 每个sentinelRedisInstance结构(后面简称“实例结构”)代表一个被 Sentinel监视的Redis服务器实例(instance)这个实例可以是主服务器、从服务器,或者另外一个Sentine

2.5创建连向主服务器的网络连接

初始化Sentinel的最后一步是创建连向被监视主服务器的网络连 接,Sentinel将成为主服务器的客户端,它可以向主服务器发送命令, 并从命令回复中获取相关的信息

对于每个被Sentinel监视的主服务器来说,Sentinel会创建两个连向 主服务器的异步网络连接:

·一个是命令连接,这个连接专门用于向主服务器发送命令,并接 收命令回复。 ·

另一个是订阅连接,这个连接专门用于订阅主服务器的 __sentinel__:hello频

3.获取服务器信息

3.1获取主服务器信息

Sentinel默认会以每十秒一次的频率,通过命令连接向被监视的主服务器发送INFO命令,并通过分析INFO命令的回复来获取主服务器的当前信息

 举个例子:

主服务器master有三个从服务器 slave0、slave1和slave2,并且一个Sentinel正在连接主服务器,那么 Sentinel将持续地向主服务器发送INFO命令,并获得类似于以下内容的 回复

# Server
...
run_id:7611c59dc3a29aa6fa0609f841bb6a1019008a9c
...
# Replication
role:master
...
slave0:ip=127.0.0.1,port=11111,state=online,offset=43,lag=0
slave1:ip=127.0.0.1,port=22222,state=online,offset=43,lag=0
slave2:ip=127.0.0.1,port=33333,state=online,offset=43,lag=0
...
# Other sections

解析:

1.一方面是关于主服务器本身的信息,包括run_id域记录的服务器运 行ID,以及role域记录的服务器角色

2.另一方面是关于主服务器属下所有从服务器的信息,每个从服务 器都由一个"slave"字符串开头的行记录,每行的ip=域记录了从服务器 的IP地址,而port=域则记录了从服务器的端口号。根据这些IP地址和端 口号,Sentinel无须用户提供从服务器的地址信息,就可以自动发现从服务器

 3.2获取从服务器的信息

当Sentinel发现主服务器有新的从服务器出现时,Sentinel除了会为 这个新的从服务器创建相应的实例结构之外,Sentinel还会创建连接到 从服务器的命令连接和订阅连接

举个例子 对于下图所示的主从服务器关系来说,Sentinel将对 slave0、slave1和slave2三个从服务器分别创建命令连接和订阅连接

 在创建命令连接之后,Sentinel在默认情况下,会以每十秒一次的 频率通过命令连接向从服务器发送INFO命令,并获得类似于以下内容 的回复

run_id:32be0699dd27b410f7c90dada3a6fab17f97899f
...
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
slave_repl_offset:11887
slave_priority:100
# Other sections

根据INFO命令的回复,Sentinel会提取出以下信息:

·从服务器的运行ID run_id。

·从服务器的角色role。

·主服务器的IP地址master_host,以及主服务器的端口号 master_port。

·主从服务器的连接状态master_link_status。

·从服务器的优先级slave_priority。

·从服务器的复制偏移量slave_repl_offset