redis sentinel 读写分离(一)
2018-10-05 本文已影响966人
8e7f75130086
redis sentinel 读写分离(一)
redis sentinel 读写分离(二)
redis sentinel 读写分离(三)
redis sentinel 读写分离(四)
redis sentinel 读写分离(五)
redis sentinel 读写分离(六)
redis sentinel 读写分离(七)
redis sentinel 读写分离(八)
redis sentinel 读写分离(九)
你是否想当然的认为sentinel帮你实现了读写分离
一、背景:
为了提高redis集群的高可用性,redis架构由master-slave结构切换为了sentinel模式。架构图如下:
redis架构.png
sentinel能够提供的特性:
- 监控(Monitoring)
sentinel会不间断地检查Redis master和Redis slave是否正常运行 - 提醒(Notification)
当其中一个被监控的Redis实例出现问题,sentinel能通过API或其他程序通知管理员 - 自动故障转移(Automatic failover)
当Redis master故障不能正常工作时,sentinel会故障切换进程,将一个slave提升为master,另外的Redis slave将更新配置使用新的master,此后有新连接时,会连接到新的Redis master - 配置提供者(Configuration provider)
Redis充当客户端服务发现的权威来源:客户端连接到sentinel,以请求当前可靠的Redis master地址,若发生故障转移,sentinels将报告新地址
二、问题
引入sentinel之后如何实现读写分离呢?
三、先来看看官方推荐的客户端jedis
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.7.2</version>
</dependency>
- redis.clients.jedis.JedisSentinelPool
通过源码分析可知,JedisSentinelPool只是建立了一个到master的连接。所有的slave仅仅起到了一个备的作用,没有任何流量会打进来,大大减低了redis集群的性能。
public JedisSentinelPool(String masterName, Set<String> sentinels,
final GenericObjectPoolConfig poolConfig, int timeout, final String password,
final int database) {
this.poolConfig = poolConfig;
this.timeout = timeout;
this.password = password;
this.database = database;
HostAndPort master = initSentinels(sentinels, masterName);
initPool(master);
}
private HostAndPort initSentinels(Set<String> sentinels, final String masterName) {
HostAndPort master = null;
boolean sentinelAvailable = false;
log.info("Trying to find master from available Sentinels...");
for (String sentinel : sentinels) {
final HostAndPort hap = toHostAndPort(Arrays.asList(sentinel.split(":")));
log.fine("Connecting to Sentinel " + hap);
Jedis jedis = null;
try {
jedis = new Jedis(hap.getHost(), hap.getPort());
List<String> masterAddr = jedis.sentinelGetMasterAddrByName(masterName);
// connected to sentinel...
sentinelAvailable = true;
if (masterAddr == null || masterAddr.size() != 2) {
log.warning("Can not get master addr, master name: " + masterName + ". Sentinel: " + hap
+ ".");
continue;
}
master = toHostAndPort(masterAddr);
log.fine("Found Redis master at " + master);
break;
} catch (JedisConnectionException e) {
log.warning("Cannot connect to sentinel running @ " + hap + ". Trying next one.");
} finally {
if (jedis != null) {
jedis.close();
}
}
}
if (master == null) {
if (sentinelAvailable) {
// can connect to sentinel, but master name seems to not
// monitored
throw new JedisException("Can connect to sentinel, but " + masterName
+ " seems to be not monitored...");
} else {
throw new JedisConnectionException("All sentinels down, cannot determine where is "
+ masterName + " master is running...");
}
}
log.info("Redis master running at " + master + ", starting Sentinel listeners...");
for (String sentinel : sentinels) {
final HostAndPort hap = toHostAndPort(Arrays.asList(sentinel.split(":")));
MasterListener masterListener = new MasterListener(masterName, hap.getHost(), hap.getPort());
masterListeners.add(masterListener);
masterListener.start();
}
return master;
}
四、在sentinel模式下如何才能实现读写分离呢?
自己动手吧