前面实现了分布式存储,也实现了sentinel单点故障时主从自动切换,现在还需要一种机制,实现分布式存储下,单点故障时的主从自动切换。

Server配置

# cd /usr/redis/src/test

创建4个配置文件

redis6378.conf redis6379.conf redis6380.conf redis6381.conf

启动4个服务

# redis-server redis6378.conf &

# redis-server redis6379.conf &

# redis-server redis6380.conf &

# redis-server redis6381.conf &

登陆6379设置master:6378

# redis-cli -p 6379

127.0.0.1:6379> slaveof 127.0.0.1 6378

登陆6381设置master:6380

# redis-cli -p 6381

127.0.0.1:6381> slaveof 127.0.0.1 6380

创建sentinel配置文件,同时监控2个分片

# vim sentinel29379.conf

port 26379
dir "/tmp"
#shard1
sentinel monitor shard1 192.168.77.135 6378 2
sentinel down-after-milliseconds shard1 30000
sentinel parallel-syncs shard1 1
sentinel failover-timeout shard1 180000

#shard2
sentinel monitor shard2 192.168.77.136 6380 2
sentinel down-after-milliseconds shard2 30000
sentinel parallel-syncs shard2 1
sentinel failover-timeout shard2 180000

# wq

创建sentinel29380.conf 修改port 26380

创建sentinel29381.conf 修改port 26381

启动sentlnel

#redis-sentinel sentinel26379.conf &

#redis-sentinel sentinel26380.conf &

#redis-sentinel sentinel26381.conf &

java端实现

package redis;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
import java.util.regex.Pattern; import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPubSub;
import redis.clients.jedis.JedisShardInfo;
import redis.clients.jedis.Protocol;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.exceptions.JedisConnectionException;
import redis.clients.util.Hashing;
import redis.clients.util.Pool; public class ShardedJedisSentinelPool extends Pool<ShardedJedis> { public static final int MAX_RETRY_SENTINEL = 10; protected final Logger log = Logger.getLogger(getClass().getName()); protected GenericObjectPoolConfig poolConfig; protected int timeout = Protocol.DEFAULT_TIMEOUT; private int sentinelRetry = 0; protected String password; protected int database = Protocol.DEFAULT_DATABASE; protected Set<MasterListener> masterListeners = new HashSet<MasterListener>(); private volatile List<HostAndPort> currentHostMasters; public ShardedJedisSentinelPool(List<String> masters, Set<String> sentinels) {
this(masters, sentinels, new GenericObjectPoolConfig(), Protocol.DEFAULT_TIMEOUT, null, Protocol.DEFAULT_DATABASE);
} public ShardedJedisSentinelPool(List<String> masters, Set<String> sentinels, String password) {
this(masters, sentinels, new GenericObjectPoolConfig(), Protocol.DEFAULT_TIMEOUT, password);
} public ShardedJedisSentinelPool(final GenericObjectPoolConfig poolConfig, List<String> masters, Set<String> sentinels) {
this(masters, sentinels, poolConfig, Protocol.DEFAULT_TIMEOUT, null, Protocol.DEFAULT_DATABASE);
} public ShardedJedisSentinelPool(List<String> masters, Set<String> sentinels, final GenericObjectPoolConfig poolConfig, int timeout, final String password) {
this(masters, sentinels, poolConfig, timeout, password, Protocol.DEFAULT_DATABASE);
} public ShardedJedisSentinelPool(List<String> masters, Set<String> sentinels, final GenericObjectPoolConfig poolConfig, final int timeout) {
this(masters, sentinels, poolConfig, timeout, null, Protocol.DEFAULT_DATABASE);
} public ShardedJedisSentinelPool(List<String> masters, Set<String> sentinels, final GenericObjectPoolConfig poolConfig, final String password) {
this(masters, sentinels, poolConfig, Protocol.DEFAULT_TIMEOUT, password);
} public ShardedJedisSentinelPool(List<String> masters, 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; List<HostAndPort> masterList = initSentinels(sentinels, masters);
initPool(masterList);
} public void destroy() {
for (MasterListener m : masterListeners) {
m.shutdown();
} super.destroy();
} public List<HostAndPort> getCurrentHostMaster() {
return currentHostMasters;
} private void initPool(List<HostAndPort> masters) {
if (!equals(currentHostMasters, masters)) {
StringBuffer sb = new StringBuffer();
for (HostAndPort master : masters) {
sb.append(master.toString());
sb.append(" ");
}
log.info("Created ShardedJedisPool to master at [" + sb.toString() + "]");
List<JedisShardInfo> shardMasters = makeShardInfoList(masters);
initPool(poolConfig, new ShardedJedisFactory(shardMasters, Hashing.MURMUR_HASH, null));
currentHostMasters = masters;
}
} private boolean equals(List<HostAndPort> currentShardMasters, List<HostAndPort> shardMasters) {
if (currentShardMasters != null && shardMasters != null) {
if (currentShardMasters.size() == shardMasters.size()) {
for (int i = 0; i < currentShardMasters.size(); i++) {
if (!currentShardMasters.get(i).equals(shardMasters.get(i)))
return false;
}
return true;
}
}
return false;
} private List<JedisShardInfo> makeShardInfoList(List<HostAndPort> masters) {
List<JedisShardInfo> shardMasters = new ArrayList<JedisShardInfo>();
for (HostAndPort master : masters) {
JedisShardInfo jedisShardInfo = new JedisShardInfo(master.getHost(), master.getPort(), timeout);
jedisShardInfo.setPassword(password); shardMasters.add(jedisShardInfo);
}
return shardMasters;
} private List<HostAndPort> initSentinels(Set<String> sentinels, final List<String> masters) { Map<String, HostAndPort> masterMap = new HashMap<String, HostAndPort>();
List<HostAndPort> shardMasters = new ArrayList<HostAndPort>(); log.info("Trying to find all master from available Sentinels..."); for (String masterName : masters) {
HostAndPort master = null;
boolean fetched = false; while (!fetched && sentinelRetry < MAX_RETRY_SENTINEL) {
for (String sentinel : sentinels) {
final HostAndPort hap = toHostAndPort(Arrays.asList(sentinel.split(":"))); System.out.println("Connecting to Sentinel " + hap); try {
Jedis jedis = new Jedis(hap.getHost(), hap.getPort());
master = masterMap.get(masterName);
if (master == null) {
List<String> hostAndPort = jedis.sentinelGetMasterAddrByName(masterName);
if (hostAndPort != null && hostAndPort.size() > 0) {
master = toHostAndPort(hostAndPort);
System.out.println("Found Redis master at " + master);
shardMasters.add(master);
masterMap.put(masterName, master);
fetched = true;
jedis.disconnect();
break;
}
}
} catch (JedisConnectionException e) {
log.warning("Cannot connect to sentinel running @ " + hap + ". Trying next one.");
}
} if (null == master) {
try {
log.severe("All sentinels down, cannot determine where is " + masterName + " master is running... sleeping 1000ms, Will try again.");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
fetched = false;
sentinelRetry++;
}
} // Try MAX_RETRY_SENTINEL times.
if (!fetched && sentinelRetry >= MAX_RETRY_SENTINEL) {
log.severe("All sentinels down and try " + MAX_RETRY_SENTINEL + " times, Abort.");
throw new JedisConnectionException("Cannot connect all sentinels, Abort.");
}
} // All shards master must been accessed.
if (masters.size() != 0 && masters.size() == shardMasters.size()) { log.info("Starting Sentinel listeners...");
for (String sentinel : sentinels) {
final HostAndPort hap = toHostAndPort(Arrays.asList(sentinel.split(":")));
MasterListener masterListener = new MasterListener(masters, hap.getHost(), hap.getPort());
masterListeners.add(masterListener);
masterListener.start();
}
} return shardMasters;
} private HostAndPort toHostAndPort(List<String> getMasterAddrByNameResult) {
String host = getMasterAddrByNameResult.get(0);
int port = Integer.parseInt(getMasterAddrByNameResult.get(1)); return new HostAndPort(host, port);
} /**
* PoolableObjectFactory custom impl.
*/
protected static class ShardedJedisFactory implements PooledObjectFactory<ShardedJedis> {
private List<JedisShardInfo> shards;
private Hashing algo;
private Pattern keyTagPattern; public ShardedJedisFactory(List<JedisShardInfo> shards, Hashing algo, Pattern keyTagPattern) {
this.shards = shards;
this.algo = algo;
this.keyTagPattern = keyTagPattern;
} public PooledObject<ShardedJedis> makeObject() throws Exception {
ShardedJedis jedis = new ShardedJedis(shards, algo, keyTagPattern);
return new DefaultPooledObject<ShardedJedis>(jedis);
} public void destroyObject(PooledObject<ShardedJedis> pooledShardedJedis) throws Exception {
final ShardedJedis shardedJedis = pooledShardedJedis.getObject();
for (Jedis jedis : shardedJedis.getAllShards()) {
try {
try {
jedis.quit();
} catch (Exception e) { }
jedis.disconnect();
} catch (Exception e) { }
}
} public boolean validateObject(PooledObject<ShardedJedis> pooledShardedJedis) {
try {
ShardedJedis jedis = pooledShardedJedis.getObject();
for (Jedis shard : jedis.getAllShards()) {
if (!shard.ping().equals("PONG")) {
return false;
}
}
return true;
} catch (Exception ex) {
return false;
}
} public void activateObject(PooledObject<ShardedJedis> p) throws Exception { } public void passivateObject(PooledObject<ShardedJedis> p) throws Exception { }
} protected class JedisPubSubAdapter extends JedisPubSub {
@Override
public void onMessage(String channel, String message) {
} @Override
public void onPMessage(String pattern, String channel, String message) {
} @Override
public void onPSubscribe(String pattern, int subscribedChannels) {
} @Override
public void onPUnsubscribe(String pattern, int subscribedChannels) {
} @Override
public void onSubscribe(String channel, int subscribedChannels) {
} @Override
public void onUnsubscribe(String channel, int subscribedChannels) {
}
} protected class MasterListener extends Thread { protected List<String> masters;
protected String host;
protected int port;
protected long subscribeRetryWaitTimeMillis = 5000;
protected Jedis jedis;
protected AtomicBoolean running = new AtomicBoolean(false); protected MasterListener() {
} public MasterListener(List<String> masters, String host, int port) {
this.masters = masters;
this.host = host;
this.port = port;
} public MasterListener(List<String> masters, String host, int port, long subscribeRetryWaitTimeMillis) {
this(masters, host, port);
this.subscribeRetryWaitTimeMillis = subscribeRetryWaitTimeMillis;
} public void run() { running.set(true); while (running.get()) { jedis = new Jedis(host, port); try {
jedis.subscribe(new JedisPubSubAdapter() {
@Override
public void onMessage(String channel, String message) {
System.out.println("Sentinel " + host + ":" + port + " published: " + message + ".");
// 1) "message"
// 2) "+switch-master"
// 3) "shard1 192.168.77.135 6379 192.168.77.135 6378"
String[] switchMasterMsg = message.split(" "); if (switchMasterMsg.length > 3) { int index = masters.indexOf(switchMasterMsg[0]);
if (index >= 0) {
HostAndPort newHostMaster = toHostAndPort(Arrays.asList(switchMasterMsg[3], switchMasterMsg[4]));
List<HostAndPort> newHostMasters = new ArrayList<HostAndPort>();
for (int i = 0; i < masters.size(); i++) {
newHostMasters.add(null);
}
Collections.copy(newHostMasters, currentHostMasters);
newHostMasters.set(index, newHostMaster); initPool(newHostMasters);
} else {
StringBuffer sb = new StringBuffer();
for (String masterName : masters) {
sb.append(masterName);
sb.append(",");
}
System.out.println("Ignoring message on +switch-master for master name " + switchMasterMsg[0] + ", our monitor master name are ["
+ sb + "]");
} } else {
log.severe("Invalid message received on Sentinel " + host + ":" + port + " on channel +switch-master: " + message);
}
}
}, "+switch-master"); } catch (JedisConnectionException e) { if (running.get()) {
log.severe("Lost connection to Sentinel at " + host + ":" + port + ". Sleeping 5000ms and retrying.");
try {
Thread.sleep(subscribeRetryWaitTimeMillis);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
} else {
System.out.println("Unsubscribing from Sentinel at " + host + ":" + port);
}
}
}
} public void shutdown() {
try {
System.out.println("Shutting down listener on " + host + ":" + port);
running.set(false);
// This isn't good, the Jedis object is not thread safe
jedis.disconnect();
} catch (Exception e) {
log.severe("Caught exception while shutting down: " + e.getMessage());
}
}
}
}

测试类

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set; import junit.framework.TestCase; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import redis.ShardedJedisSentinelPool;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.exceptions.JedisConnectionException; public class ShardedJedisSentinelPoolTest extends TestCase { public void testX() throws Exception { GenericObjectPoolConfig config = new GenericObjectPoolConfig(); List<String> masters = new ArrayList<String>();
masters.add("shard1");
masters.add("shard2");
Set<String> sentinels = new HashSet<String>();
sentinels.add("192.168.77.135:26379");
sentinels.add("192.168.77.135:26380");
sentinels.add("192.168.77.135:26381"); ShardedJedisSentinelPool pool = new ShardedJedisSentinelPool(masters, sentinels, config, 60000); ShardedJedis jedis = null;
try {
jedis = pool.getResource();
System.out.println("Current master: " + pool.getCurrentHostMaster().toString());
jedis.set("b","liangzhichao1");
String value = jedis.get("b");
System.out.println("b: " + value);
} finally {
if (jedis != null) pool.returnResource(jedis);
// pool.destroy();
} ShardedJedis j = null;
for (int i = 0; i < 50; i++) {
try {
j = pool.getResource();
j.set("KEY: " + i, "" + i);
System.out.print(i);
System.out.print(" ");
Thread.sleep(500);
pool.returnResource(j);
} catch (JedisConnectionException e) {
System.out.print("x");
i--;
Thread.sleep(1000);
}
} System.out.println(""); for (int i = 0; i < 50; i++) {
try {
j = pool.getResource();
assertEquals(j.get("KEY: " + i), "" + i);
System.out.print(".");
Thread.sleep(500);
pool.returnResource(j);
} catch (JedisConnectionException e) {
System.out.print("x");
i--;
Thread.sleep(1000);
}
} pool.destroy();
} public static void main(String[] args) throws Exception {
new ShardedJedisSentinelPoolTest().testX();
}
}

测试过程中,可以进入linux后台,终止掉6378的进程,查看主从切换情况

java使用Redis7--分布式存储并实现sentinel主从自动切换的更多相关文章

  1. Dledger的是如何实现主从自动切换的

    前言 hello小伙伴们,今天王子又来继续和大家聊RocketMQ了,之前的文章我们一直说Broker的主从切换是可以基于Dledger实现自动切换的,那么小伙伴们是不是很好奇它究竟是如何实现的呢?今 ...

  2. 利用Redis Sentinel实现redis主从自动切换

    redis主从配置很简单,只需要在slave的配置里加slaveof 192.168.0.100 6379(master的ip和端口) 如果master有密码再设置 masterauth passwo ...

  3. redis哨兵主从自动切换

    1.用的是TP5框架,改写框架自带的redis类 thinkphp/library/think/cache/driver/Redis.php //两台服务器都配置好了监控哨兵 //主从配置要设置好密码 ...

  4. 【转】双机高可用、负载均衡、MySQL(读写分离、主从自动切换)架构设计

    架构简介 前几天网友来信说帮忙实现这样一个架构:只有两台机器,需要实现其中一台死机之后另一台能接管这台机器的服务,并且在两台机器正常服务时,两台机器都能用上.于是设计了如下的架构.此架构主要是由kee ...

  5. 双机高可用、负载均衡、MySQL(读写分离、主从自动切换)架构设计

    前几天网友来信说帮忙实现这样一个架构:只有两台机器,需要实现其中一台死机之后另一台能接管这台机器的服务,并且在两台机器正常服务时,两台机器都能用上.于是设计了如下的架构. 架构简介 此架构主要是由ke ...

  6. java使用Redis6--sentinel单点故障主从自动切换

    Redis SentinelSentinel(哨兵)是用于监控redis集群中Master状态的工具,其已经被集成在redis2.4+的版本中 一.Sentinel作用:1):Master状态检测 2 ...

  7. Redis集群_3.redis主从自动切换Sentinel(转)

    Redis SentinelSentinel(哨兵)是用于监控redis集群中Master状态的工具,其已经被集成在redis2.4+的版本中 一.Sentinel作用:1):Master状态检测 2 ...

  8. mysql mha 主从自动切换 高可用

    mha(Master High Availability)目前在MySQL多服务器(超过二台),高可用方面是一个相对成熟的解决方案. 一,什么是mha,有什么特性 1. 主服务器的自动监控和故障转移 ...

  9. 在Service Fabric上部署Java应用,体验一把微服务的自动切换

    虽然Service Fabric的Java支持版本还没有正式发布,但是Service Fabric本身的服务管理.部署.升级等功能是非常好用的,那么Java的开发者可以如何利用上Service Fab ...

随机推荐

  1. eclipse里启动tomcat无法通过127.0.0.1访问

    在eclipse里面添加tomcat,再发布一个web项目进去,然后启动tomcat,日志显示tomcat在eclipse里面正常启动,hosts里面配置了ip跟域名的对应关系. 通过域名访问可以正常 ...

  2. 什么是UE、UI、UCD、UED?UE、UI、UCD、UED四者的区别(转)

    字面释义: UE (User Experience) : 用户体验 UI (User Interface) : 用户界面 UCD (User-Centered Design) :以用户为中心的设计 U ...

  3. go_组合接口

    main函数入口 package main import ( "fmt" "learngo/retriever/mock" "learngo/retr ...

  4. Redis高可用及分片集群

    一.主从复制 使用异步复制 一个服务器可以有多个从服务器 从服务器也可以有自己的从服务器 复制功能不会阻塞主服务器 可以通过服务功能来上主服务器免于持久化操作,由从服务器去执行持久化操作即可. 以下是 ...

  5. DNS开源服务器BIND最小配置详解

    一,简介 相对于存储和大数据领域,CDN是一个相对小的领域,但行行出状元,BIND就是CDN领域的蝉联N届的状元郎.BIND是一款非常常用的DNS开源服务器,全球有90%的DNS用BIND实现.值得一 ...

  6. linux 关闭电子邮件传输服务

    1.检查sendmail的哪些runlevel开启: chkconfig --list sendmail

  7. mysql启动参数 skip-grant-tables

    非常有用的mysql启动参数—— --skip-grant-tables. 顾名思义,就是在启动mysql时不启动grant-tables,授权表.有什么用呢?当然是忘记管理员密码后有用. 在mysq ...

  8. Associate File Type with Qt In Mac Os and Win

    Win Registry Question One day, my boss want me to finish one function which let the users can double ...

  9. sklearn中决策树算法DesiciontTreeClassifier()调用以及sklearn自带的数据包sklearn.datasets.load_iris()的应用

    决策树方法的简单调用记录一下 clf=tree.DecisionTreeClassifier() dataMat=[];labelMat=[] dataPath='D:/machinelearning ...

  10. mysql查询今天、昨天、近7天、近30天、本月、上一月的SQL语句

    mysql查询今天.昨天.近7天.近30天.本月.上一月的SQL语句 这篇文章主要介绍了mysql查询今天.昨天.近7天.近30天.本月.上一月的SQL语句,一般在一些统计报表中比较常用这个时间段,需 ...