redis sentinel 读写分离(二)
2018-10-05 本文已影响820人
8e7f75130086
redis sentinel 读写分离(一)
redis sentinel 读写分离(二)
redis sentinel 读写分离(三)
redis sentinel 读写分离(四)
redis sentinel 读写分离(五)
redis sentinel 读写分离(六)
redis sentinel 读写分离(七)
redis sentinel 读写分离(八)
redis sentinel 读写分离(九)
探索sentinel模式下的读写分离解决方案——sentinel事件订阅
一、理论知识
1、主观下线、客观下线
- 主观下线(Subjectively Down, 简称 SDOWN)指的是单个 Sentinel 实例对服务器做出的下线判断。
- 客观下线(Objectively Down, 简称 ODOWN)指的是多个 Sentinel 实例在对同一个服务器做出 SDOWN 判断, 并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后, 得出的服务器下线判断。 (一个 Sentinel 可以通过向另一个 Sentinel 发送 SENTINEL is-master-down-by-addr 命令来询问对方是否认为给定的服务器已下线。)
The ODOWN condition only applies to masters. For other kind of instances Sentinel doesn't require to act, so the ODOWN state is never reached for slaves and other sentinels, but only SDOWN is.
2、Sentinel API
Sentinel provides an API in order to inspect its state, check the health of monitored masters and slaves, subscribe in order to receive specific notifications, and change the Sentinel configuration at run time.
Sentinel提供了API,可以用来检查它的状态,检查master节点和slave节点的健康,订阅事件通知,运行时改变Sentinel的配置。
有两种方式可以和 Sentinel 进行通讯:
- 第一种方法是通过直接发送命令来查询被监视 Redis 服务器的当前状态, 以及 Sentinel 所知道的关于其他 Sentinel 的信息
- 另一种方法是使用发布与订阅功能, 通过接收 Sentinel 发送的通知: 当执行故障转移操作, 或者某个被监视的服务器被判断为主观下线或者客观下线时, Sentinel 就会发送相应的信息。
频道的名称和事件的名称是一样的。比如说名称为+sdown的频道将收到所有的关于实例进入SDOWN 条件的通知。
二、思路?
- 从sentinel集群中获取slave节点信息(host:port)及健康状态
- 建立到slave节点的连接池
- 统一管理所有slave连接池,读请求时通过负载均衡访问所有slave连接池
- 当发生slave下线或者slave切换为master、或者新slave加入时,订阅这些事件,firelistener后重新初始化连接池
三、定义事件枚举
/**
*
* SentinetlEventChanelEnum
* sentinel事件订阅频道枚举
* @author lihhd(盘古)
* 2018年10月3日 下午8:11:15
*
*
*/
public enum SentinetlEventChanelEnum {
aresetmaster("+reset-master","master被重置"),
spubsublink("-pubsub-link",""),
apubsublink("+pubsub-link",""),
scmdlinkreconnection("-cmd-link-reconnection",""),
spubsublinkreconnection("-pubsub-link-reconnection",""),
areboot("+reboot",""),
aslave("+slave","检测到一个slave并添加进slave列表"),
apromotedslave("+promoted-slave",""),
afailoverstatereconfslaves("+failover-state-reconf-slaves","Failover状态变为reconf-slaves状态"),
aconverttoslave("+convert-to-slave",""),
afixslaveconfig("+fix-slave-config",""),
aslavereconfinprog("+slave-reconf-inprog","slave被重新配置为另外一个master的slave,但数据复制还未发生时"),
aslavereconfdone("+slave-reconf-done","slave被重新配置为另外一个master的slave并且数据复制已经与master同步时"),
sdupsentinel("-dup-sentinel","删除指定master上的冗余sentinel时 (当一个sentinel重新启动时,可能会发生这个事件)"),
asentinel("+sentinel","当master增加了一个sentinel时"),
anewepoch("+new-epoch","当前配置版本被更新时"),
aswitchmaster("+switch-master","当master的地址发生变化时"),
amonitor("+monitor",""),
smonitor("-monitor",""),
aset("+set",""),
asdown("+sdown","进入主观下线状态时"),
ssdown("-sdown","脱离主观下线状态"),
aodown("+odown","进入客观下线状态"),
sodown("-odown","脱离客观下线状态"),
avoteforleader("+vote-for-leader",""),
atryfailover("+try-failover","达到failover条件,正等待其他sentinel的选举"),
sfailoverabortnotelected("-failover-abort-not-elected",""),
aelectedleader("+elected-leader","被选举为去执行failover的时候"),
afailoverstateselectslave("+failover-state-select-slave","开始要选择一个slave当选新master时"),
sfailoverabortnogoodslave("-failover-abort-no-good-slave",""),
aselectedslave("+selected-slave",""),
afailoverstatesendslaveofnoone("+failover-state-send-slaveof-noone",""),
sfailoverabortslavetimeout("-failover-abort-slave-timeout",""),
afailoverstatewaitpromotion("+failover-state-wait-promotion",""),
afailoverendfortimeout("+failover-end-for-timeout","failover由于超时而失败时"),
afailoverend("+failover-end","failover成功完成时"),
aslavereconfsentbe("+slave-reconf-sent-be",""),
sslavereconfsenttimeout("-slave-reconf-sent-timeout",""),
aslavereconfsent("+slave-reconf-sent","sentinel发送SLAVEOF命令把它重新配置"),
stilt("-tilt","进入Tilt模式"),
atilt("+tilt","退出Tilt模式");
private String code;
private String name;
private SentinetlEventChanelEnum(String code,String name){
this.code=code;
this.name=name;
}
public String getCode() {
return code;
}
public String getName() {
return name;
}
private static final Map<String, SentinetlEventChanelEnum> codeMap = new HashMap<String, SentinetlEventChanelEnum>((int)(SentinetlEventChanelEnum.values().length/0.75)+1);
static{
for(SentinetlEventChanelEnum businessCodeEnum: values()){
codeMap.put(businessCodeEnum.getCode(), businessCodeEnum);
}
}
/**
* 根据code获取枚举值
* @param code 编码
* @return 对应的枚举
*/
public static SentinetlEventChanelEnum valueOfCode(String code){
return codeMap.get(code);
}