java使用Redis7--分布式存储并实现sentinel主从自动切换
前面实现了分布式存储,也实现了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主从自动切换的更多相关文章
- Dledger的是如何实现主从自动切换的
前言 hello小伙伴们,今天王子又来继续和大家聊RocketMQ了,之前的文章我们一直说Broker的主从切换是可以基于Dledger实现自动切换的,那么小伙伴们是不是很好奇它究竟是如何实现的呢?今 ...
- 利用Redis Sentinel实现redis主从自动切换
redis主从配置很简单,只需要在slave的配置里加slaveof 192.168.0.100 6379(master的ip和端口) 如果master有密码再设置 masterauth passwo ...
- redis哨兵主从自动切换
1.用的是TP5框架,改写框架自带的redis类 thinkphp/library/think/cache/driver/Redis.php //两台服务器都配置好了监控哨兵 //主从配置要设置好密码 ...
- 【转】双机高可用、负载均衡、MySQL(读写分离、主从自动切换)架构设计
架构简介 前几天网友来信说帮忙实现这样一个架构:只有两台机器,需要实现其中一台死机之后另一台能接管这台机器的服务,并且在两台机器正常服务时,两台机器都能用上.于是设计了如下的架构.此架构主要是由kee ...
- 双机高可用、负载均衡、MySQL(读写分离、主从自动切换)架构设计
前几天网友来信说帮忙实现这样一个架构:只有两台机器,需要实现其中一台死机之后另一台能接管这台机器的服务,并且在两台机器正常服务时,两台机器都能用上.于是设计了如下的架构. 架构简介 此架构主要是由ke ...
- java使用Redis6--sentinel单点故障主从自动切换
Redis SentinelSentinel(哨兵)是用于监控redis集群中Master状态的工具,其已经被集成在redis2.4+的版本中 一.Sentinel作用:1):Master状态检测 2 ...
- Redis集群_3.redis主从自动切换Sentinel(转)
Redis SentinelSentinel(哨兵)是用于监控redis集群中Master状态的工具,其已经被集成在redis2.4+的版本中 一.Sentinel作用:1):Master状态检测 2 ...
- mysql mha 主从自动切换 高可用
mha(Master High Availability)目前在MySQL多服务器(超过二台),高可用方面是一个相对成熟的解决方案. 一,什么是mha,有什么特性 1. 主服务器的自动监控和故障转移 ...
- 在Service Fabric上部署Java应用,体验一把微服务的自动切换
虽然Service Fabric的Java支持版本还没有正式发布,但是Service Fabric本身的服务管理.部署.升级等功能是非常好用的,那么Java的开发者可以如何利用上Service Fab ...
随机推荐
- Unity加载二进制数据
[Unity加载二进制数据] The first step is to save your binary data file with the ".bytes" extension ...
- redis的连接方法|连接池|操作
1.先看下redis的连接 import redis # 连接服务端 r = redis.Redis(host="127.0.0.1",port=6379) #获取所有的key值 ...
- JSFF或JSF页面加载时触发JavaScript之方法
现象一 最近在项目中遇到这么一个问题,有些页面元素是在页面加载时通过JavaScript动态渲染而成.当生成这些元素的JavaScript脚本被放置于JSPX文件中时,界面渲染没有问题.但是当我们把生 ...
- windows安装mysql-5.7压缩版详细教程
前言 今天安装mysql数据库,进入mysql官网,对于windows来说有两个版本的文件可下载,一是.msi安装文件,二是.biz压缩包.以前一直用安装文件进行安装,百试不爽.今天突然不想用安装文件 ...
- 清官谈mysql中utf8和utf8mb4区别
清官谈mysql中utf8和utf8mb4区别 发布时间:2015 年 10 月 4 日 发布者: OurMySQL 来源:JavaRanger - 专注JAVA高性能程序开发.JVM.Mysql优化 ...
- 20172325《Java程序设计》第一周学习总结
20172325<Java程序设计>第一周学习总结 教材学习内容总结 第一章 1.1软件质量 软件工程是一门关于高质量软件开发的技术和理论的学科. 高质量软件的特征 1.2 数据结构 软件 ...
- Excel中保留有效数字的问题
在工作表界面中按 <alt>+<F11>,进入代码页面,然后再 WORKBOOK中插入模块,把以下代码COPY入模块中.就可以在工作表中使用 =YXSZ(数值,保留位数). 如 ...
- CoreText
[CoreText] Core Text is designed for development of higher-level text-handling frameworks. General ...
- Tomcat的windows10集群搭建(一台电脑同时运行多个tomcat配置方法)
配置方法(好久不配置了,忘记了,今天还是总结下吧): 1.官网下载tomcat ,我下载了tomcat6.0和tomcat7.0(以便区分) 官网地址:http://tomcat.apache.org ...
- C++ 类 & 对象-C++ 内联函数-C++ this 指针-C++ 类的静态成员
C++ 内联函数 C++ 内联函数是通常与类一起使用.如果一个函数是内联的,那么在编译时,编译器会把该函数的代码副本放置在每个调用该函数的地方. 对内联函数进行任何修改,都需要重新编译函数的所有客户端 ...