Redis 的 sentinel模式
启动并初始化Sentinel
- 初始化服务器
- 将普通reids服务器使用的代码替换成Sentinel专用代码
- 初始化Sentinel状态
- 根据给定的配置文件,初始化Sentinel的监视主服务器列表
- 创建连向主服务器的网络连接
初始化服务器
使用Sentinel专用代码
初始化Sentinel状态
struct sentinelState {
uint64_t current_epoch; // 当前纪元,用于实现故障转移
// 保存了所有被这个sentinel监视的主服务器
// 字典的键是主服务器的名字
// 字典的值是一个指向sentinelRedisInstance结构指针
dict *masters;
int tilt; // 是否进入TITLYT模式
int running_scripts; // 目前正在执行的脚本数量
mstime_t tilt_start_time; // 进入TILT模式的时间
mstime_t previous_time; // 最后一次执行时间处理器时间
list *scripts_queue; // 一个FIFO队列,包含了所有需要执行的用户脚本
} sentinel;
初始化Sentinel状态的masters属性
typedef struct sentinelAddr {
char *ip;
int port;
} sentinelAddr;
typedef struct sentinelRedisInstance {
int flags; // 标识值,记录了实例的类型以及该实例的当前状态
// 主服务器的名字由用户在配置文件中设置
// 从服务器以及sentinel的名字由sentinel自动设置
// 格式为ip:port,例如“127.0.0.1:26379”
char *name; // 实例的名字
char *runid; // 实例运行ID
uint64_t config_epoch; // 配置纪元,用于实现故障转移
sentinelAddr *addr; // 实例地址
// SENTINEL down-after-millisenconds 选项设定的值
mstime_t down_after_period; // 实例无响应多少毫秒之后才会被判断为主观下线
// SENTINEL monitor 选项中quorum参数
int quorum; // 判断这个实例为客观下线所需的支持投票数量
// SENTINEL parallel-syncs 选项的值
int parallel_syncs; // 在执行故障转移操作时,可以同时对新的主服务器进行同步的从服务器数量
// SENTINEL failover-timeout 选项的值
mstime_t failover_timeout; // 刷新故障迁移状态的最大时限
...;
} sentinelRedisInstance;
创建连向主服务器的网络连接
会创建两个连向主服务器的异步网络连接
- 命令连接
- 订阅连接
获取主服务器信息
sentinel默认每10秒一次的频率通过命令连接向被监视的主服务器发送INFO命令,并通过分析INFO命令的回复来获取主服务器的当前信息
对于获取的信息有两方面:
一方面是主服务器本身的信息
一方面的关于主服务器属下所有从服务器信息 - sentinel无需用户提供从服务器的地址信息就可以自动发现从服务器
获取从服务器信息
当sentinel发现主服务器有新的从服务器时,sentinel除了会为这些新的从服务器创建相信的实例结构之外,还会创建连接到从服务器的命令连接与订阅连接
向主服务器和从服务器发送信息
sentinel默认每2秒一次的频率通过命令连接向所有被监视的主服务器和从服务器发送以下格式的命令:
PUBLISH __sentinel__:hello ",,,,,,,"
这条命令向服务器的_sentinel_:hello频道发送了一条信息,信息的内容有多个参数组成(s_开头的参数记录的是sentinel本身的信息,m_开头的参数记录的则是主服务器的信息)
接受来自主服务器和从服务器的频道信息
当sentinel与一个主服务器或者从服务器建立起订阅连接之后,sentinel会通过订阅连接向服务器发送以下命令:
subscribe __sentinel__:hello
sentinel对_sentinel_:hello频道的订阅会一直持续到sentinel与服务器的连接断开为止
对于每个sentinel连接的服务器,sentinel既通过命令连接向服务器的_sentinel_:hello频道发送信息,又通过订阅连接从服务器的_sentinel_:hello频道接收消息
更新sentinel字典
sentinel为主服务器创建的实例结构中的sentinel字典保存了除sentinel本身之外,所有同样监视这个主服务器的其他sentinel的资料
创建连向其他sentinel的命令连接
当sentinel通过频道信息发现一个新的sentinel时,它不仅会为新的sentinel在sentinels字典中创建相应的实例结构,还会创建一个连向新的sentinel的命令连接。而新的sentinel也同样会创建连向这个sentinel的命令连接。
sentinel之间不会创建订阅连接
检测主观下线状态
sentinel默认以每秒一次的频率向所有与它创建了命令连接的实例(包括主服务器、从服务器、其他sentinel在内)发送PING命令,并通过实例返回的PING命令回复来判断实例是否在线。
sentinel配置文件中的down_after_milliseconds选项制定了sentinel判断实例进入主观下线所需的时间长度
如果一个实例在down_after_milliseconds毫秒内,连续向sentinel返回无效回复,那么sentinel会修改这个实例对应的实例结构,在结构flags属性中打开SRI_S_DOWN标识,以此来表示这个实例已经进入主观状态
多个sentinel设置的主观下线时常可能不同
检查客观下线状态
当sentinel将一个主服务器判断为主观下线之后,为了确认这个主服务器是否真的下线,它会向同样监视这一主服务器的其他sentinel进行询问,看他们是否也认为主服务器已经进入了下线状态(可以是主观下线或者客观下线)。
当sentinel从其他sentinel哪里接受到足够数量已经下线的判断之后,sentinel就会将从服务器判定位客观下线,并对主服务器执行故障转移操作。
发送SENTINEL is-master-down-by-addr命令
sentinel使用:
SENTINEL is-master-down-by-addr
命令询问其他sentinel是否同意主服务器已下线。
接受SENTINEL is-master-down-by-addr命令
down_state为1代表主服务器已下线,0表示主服务器未下线
接受SENTINEL is-master-down-by-addr命令回复
根据其他sentinel发回的SENTINEL is-master-down-by-addr命令回复,sentinel将统计其他sentinel同意主服务器已下线数量,当这一数量达到配置指定的判断客观下线所需数量时,sentinel会将主服务器实例结构flags属性的SRI_O_DOWN标识打开,表示主服务器已经进入客观下线状态
客观下线状态判断条件如下配置文件所示:
sentinel monitor master 127.0.0.1 6379 2
只要有两个sentinel认为主服务器已经进入下线状态,那么当前sentinel判定主服务器为客观下线状态
不同sentinel判断客观下线状态的条件可能不同
选举领头Sentinel
当一个主服务器被判定为客观下线,监视这个下线的主服务器的各个sentinel会进行协商,选举出一个领头Sentinel,并由领头Sentinel对下线服务器执行故障转移操作
选举领头Sentinel自己看书吧
故障转移
- 在已下线的主服务器属下的所有从服务器里面,挑选出一个从服务器,并将其转换为主服务器
- 让已下线的主服务器属下的所有从服务器改为复制新的主服务器
- 将已下线的主服务器设置为新的主服务器的从服务器,当这个旧的主服务器重新上线时,它就会成为新的主服务器的从服务器
参考:
黄键宏老师的《redis设计与实现》,机械工业出版社