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模式下如何才能实现读写分离呢?
自己动手吧
网友评论