Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.penglecode.common.redis.jedis.ms.MasterSlaveJedisSentinelPool Maven / Gradle / Ivy
Go to download
commons is a little java tool to make your development easier in your work.
package com.penglecode.common.redis.jedis.ms;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.exceptions.JedisConnectionException;
import redis.clients.util.Hashing;
import redis.clients.util.Pool;
public class MasterSlaveJedisSentinelPool extends Pool {
private Logger logger = LoggerFactory.getLogger(MasterSlaveJedisSentinelPool.class);
protected String masterName;
protected Set sentinels;
protected GenericObjectPoolConfig poolConfig;
protected int timeout = Protocol.DEFAULT_TIMEOUT;
protected String password;
protected int database = Protocol.DEFAULT_DATABASE;
protected volatile MasterSlaveHostAndPort currentHostMasterSlave;
protected Set masterSlaveListeners = new HashSet();
private volatile MasterSlaveJedisFactory factory;
public MasterSlaveJedisSentinelPool(String masterName, Set sentinels, final GenericObjectPoolConfig poolConfig) {
this(masterName, sentinels, poolConfig, Protocol.DEFAULT_TIMEOUT, null, Protocol.DEFAULT_DATABASE);
}
public MasterSlaveJedisSentinelPool(String masterName, Set sentinels) {
this(masterName, sentinels, new GenericObjectPoolConfig(), Protocol.DEFAULT_TIMEOUT, null, Protocol.DEFAULT_DATABASE);
}
public MasterSlaveJedisSentinelPool(String masterName, Set sentinels, String password) {
this(masterName, sentinels, new GenericObjectPoolConfig(), Protocol.DEFAULT_TIMEOUT, password);
}
public MasterSlaveJedisSentinelPool(String masterName, Set sentinels, final GenericObjectPoolConfig poolConfig, int timeout, final String password) {
this(masterName, sentinels, poolConfig, timeout, password, Protocol.DEFAULT_DATABASE);
}
public MasterSlaveJedisSentinelPool(String masterName, Set sentinels, final GenericObjectPoolConfig poolConfig, final int timeout) {
this(masterName, sentinels, poolConfig, timeout, null, Protocol.DEFAULT_DATABASE);
}
public MasterSlaveJedisSentinelPool(String masterName, Set sentinels, final GenericObjectPoolConfig poolConfig, final String password) {
this(masterName, sentinels, poolConfig, Protocol.DEFAULT_TIMEOUT, password);
}
/**
* Master-Slave must be use the same config
*/
public MasterSlaveJedisSentinelPool(String masterName, Set sentinels, final GenericObjectPoolConfig poolConfig, int timeout, final String password, final int database) {
this.masterName = masterName;
this.sentinels = sentinels;
this.poolConfig = poolConfig;
this.timeout = timeout;
this.password = password;
this.database = database;
initSentinelPool();
initSentinelLiseners();
}
protected void initSentinelPool() {
MasterSlaveHostAndPort masterSlaveHostAndPort = sentinelGetMasterSlaves();
initPool(masterSlaveHostAndPort);
}
protected MasterSlaveHostAndPort sentinelGetMasterSlaves() {
HostAndPort master = null;
Set slaves = new LinkedHashSet();
logger.info("Trying to find Master-Slaves from available sentinels...");
for (String sentinel : sentinels) {
final HostAndPort hap = toHostAndPort(Arrays.asList(sentinel.split(":")));
logger.info("Connecting to sentinel " + hap);
Jedis jedis = null;
try {
jedis = new Jedis(hap.getHost(), hap.getPort());
List masterAddr = jedis.sentinelGetMasterAddrByName(masterName);
List> slaveAddrs = jedis.sentinelSlaves(masterName);
if (masterAddr == null || masterAddr.size() != 2) {
logger.warn("Can not get master addr, master name: {}. Sentinel: {}.", masterName, hap);
continue;
}
if (slaveAddrs == null || slaveAddrs.isEmpty()) {
logger.warn("Can not get slave addr, master name: {}. Sentinel: {}.", masterName, hap);
continue;
}
master = toHostAndPort(masterAddr);
for(Map slave : slaveAddrs){
if("slave".equals(slave.get("flags"))){ //is normal worked slave at now
slaves.add(toHostAndPort(Arrays.asList(slave.get("ip"), slave.get("port"))));
}
}
MasterSlaveHostAndPort masterSlaveHostAndPort = new MasterSlaveHostAndPort(masterName, master, slaves);
logger.info("Found Master-Slaves : {}", masterSlaveHostAndPort);
return masterSlaveHostAndPort;
} catch (JedisConnectionException e) {
logger.warn("Cannot connect to sentinel running @ {}. Trying next one.", hap);
} finally {
if (jedis != null) {
jedis.close();
}
}
}
return null;
}
protected void initSentinelLiseners() {
if(currentHostMasterSlave != null){
logger.info("Starting Sentinel listeners...");
for (String sentinel : sentinels) {
try {
final HostAndPort hap = toHostAndPort(Arrays.asList(sentinel.split(":")));
MasterSlaveListener masterSlaveListener = new MasterSlaveListener(masterName, hap.getHost(), hap.getPort());
masterSlaveListeners.add(masterSlaveListener);
masterSlaveListener.start();
} catch(Exception e) {
logger.error("Starting Starting Sentinel listeners caught a exception: " + e.getMessage(), e);
}
}
}
}
protected synchronized void initPool(MasterSlaveHostAndPort masterSlaveHostAndPort){
if(masterSlaveHostAndPort != null && !masterSlaveHostAndPort.equals(currentHostMasterSlave)){
currentHostMasterSlave = masterSlaveHostAndPort;
JedisShardInfo masterShard = toJedisShardInfo(masterSlaveHostAndPort.getMaster(), masterSlaveHostAndPort.getMasterName());
List slaveShards = new ArrayList();
for(HostAndPort slave : masterSlaveHostAndPort.getSlaves()){
JedisShardInfo slaveShard = toJedisShardInfo(slave, null);
slaveShards.add(slaveShard);
}
if(factory == null){
factory = new MasterSlaveJedisFactory(masterShard, slaveShards, Hashing.MURMUR_HASH, null);
initPool(poolConfig, factory);
}else{
factory.setMasterShard(masterShard);
factory.setSlaveShards(slaveShards);
// although we clear the pool, we still have to check the
// returned object
// in getResource, this call only clears idle instances, not
// borrowed instances
internalPool.clear();
}
logger.info("Create Master-Slaves jedis pool for {}", currentHostMasterSlave);
}
}
protected JedisShardInfo toJedisShardInfo(HostAndPort hostAndPort, String name) {
JedisShardInfo shard = new JedisShardInfo(hostAndPort.getHost(), hostAndPort.getPort(), timeout, name);
shard.setPassword(password);
return shard;
}
public MasterSlaveJedis getResource() {
while (true) {
MasterSlaveJedis masterSlaveJedis = super.getResource();
masterSlaveJedis.setDataSource(this);
// get a reference because it can change concurrently
final MasterSlaveHostAndPort reference = currentHostMasterSlave;
final MasterSlaveHostAndPort connectionDesc = masterSlaveJedis.getConnectionDesc();
if (connectionDesc.equals(reference)) {
// connected to the correct master
return masterSlaveJedis;
} else {
returnBrokenResource(masterSlaveJedis);
}
}
}
public void returnBrokenResource(final MasterSlaveJedis resource) {
if (resource != null) {
returnBrokenResourceObject(resource);
}
}
public void returnResource(final MasterSlaveJedis resource) {
if (resource != null) {
// get a reference because it can change concurrently
final MasterSlaveHostAndPort reference = currentHostMasterSlave;
final MasterSlaveHostAndPort connectionDesc = resource.getConnectionDesc();
if (connectionDesc.equals(reference)) {
// connected to the correct master
resource.resetState();
returnResourceObject(resource);
} else {
returnBrokenResource(resource);
}
}
}
public void destroy() {
for (MasterSlaveListener m : masterSlaveListeners) {
m.shutdown();
}
super.destroy();
}
public MasterSlaveHostAndPort getCurrentHostMasterSlave() {
return currentHostMasterSlave;
}
protected HostAndPort toHostAndPort(List hostAndPort){
return new HostAndPort(hostAndPort.get(0), Integer.parseInt(hostAndPort.get(1)));
}
protected class MasterSlaveListener extends Thread {
protected String masterName;
protected String host;
protected int port;
protected long subscribeRetryWaitTimeMillis = 5000;
protected Jedis sentinelJedis;
protected AtomicBoolean running = new AtomicBoolean(false);
protected MasterSlaveListener() {
}
public MasterSlaveListener(String masterName, String host, int port) {
this.masterName = masterName;
this.host = host;
this.port = port;
}
public MasterSlaveListener(String masterName, String host, int port, long subscribeRetryWaitTimeMillis) {
this(masterName, host, port);
this.subscribeRetryWaitTimeMillis = subscribeRetryWaitTimeMillis;
}
public void run() {
running.set(true);
while (running.get()) {
logger.debug(">>> Runing!");
sentinelJedis = new Jedis(host, port);
try {
sentinelJedis.subscribe(new JedisPubSub() {
public void onMessage(String channel, String message) {
logger.info("Sentinel {} published: {} {}", host + ":" + port, channel, message);
if("+sdown".equals(channel)){ //has slave offline
String[] messages = message.split(" ");
if(messages.length == 8){
if("slave".equals(messages[0])){
if(masterName.equals(messages[5])){
String slaveIp = messages[2];
String slavePort = messages[3];
String masterIp = messages[6];
String masterPort = messages[7];
logger.error("Found unavailable redis slave[{}] for master[{}@{}]", slaveIp + ":" + slavePort, masterName, masterIp + ":" + masterPort);
initSentinelPool();
}else{
logger.error("Ignoring message on +sdown for master name {}, but our master name is {}!", messages[5], masterName);
}
}else{
logger.error("Invalid message received on Sentinel {} on channel +sdown: {}", host + ":" + port, message);
}
}
}
if("-sdown".equals(channel)){ //has slave online
String[] messages = message.split(" ");
if(messages.length == 8){
if("slave".equals(messages[0])){
if(masterName.equals(messages[5])){
String slaveIp = messages[2];
String slavePort = messages[3];
String masterIp = messages[6];
String masterPort = messages[7];
logger.info("Found available redis slave[{}] for master[{}@{}]", slaveIp + ":" + slavePort, masterName, masterIp + ":" + masterPort);
initSentinelPool();
}else{
logger.error("Ignoring message on -sdown for master name {}, but our master name is {}!", messages[5], masterName);
}
}else{
logger.error("Invalid message received on Sentinel {} on channel -sdown: {}", host + ":" + port, message);
}
}
}
if("+switch-master".equals(channel)){ //master has been switched
String[] messages = message.split(" ");
if(messages.length == 5){
if(masterName.equals(messages[0])){
String oldMasterIp = messages[1];
String oldMasterPort = messages[2];
String newMasterIp = messages[3];
String newMasterPort = messages[4];
logger.info("Switch master {} from [{}] to [{}]", masterName, oldMasterIp + ":" + oldMasterPort, newMasterIp + ":" + newMasterPort);
initSentinelPool();
}else{
logger.error("Ignoring message on +switch-master for master name {}, but our master name is {}!", messages[5], masterName);
}
}else{
logger.error("Invalid message received on Sentinel {} on channel +switch-master: {}", host + ":" + port, message);
}
}
if("+slave".equals(channel)){ //has new slave joined
String[] messages = message.split(" ");
if(messages.length == 8){
if("slave".equals(messages[0])){
if(masterName.equals(messages[5])){
String slaveIp = messages[2];
String slavePort = messages[3];
String masterIp = messages[6];
String masterPort = messages[7];
logger.error("Found available redis slave[{}] for master[{}@{}]", slaveIp + ":" + slavePort, masterName, masterIp + ":" + masterPort);
initSentinelPool();
}else{
logger.error("Ignoring message on +slave for master name {}, but our master name is {}!", messages[5], masterName);
}
}else{
logger.error("Invalid message received on Sentinel {} on channel +slave: {}", host + ":" + port, message);
}
}
}
}
}, "+switch-master", "+sdown", "-sdown", "+slave");
} catch (JedisConnectionException e) {
if (running.get()) {
logger.error("Lost connection to Sentinel at {}. Sleeping {}ms and retrying.", host + ":" + port, subscribeRetryWaitTimeMillis);
try {
Thread.sleep(subscribeRetryWaitTimeMillis);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
} else {
logger.error("Listener stop running and unsubscribing from Sentinel at {}.", host + ":" + port);
}
}
}
}
public void shutdown() {
try {
logger.info("Shutting down listener on {}.", host + ":" + port);
running.set(false);
// This isn't good, the Jedis object is not thread safe
sentinelJedis.disconnect();
} catch (Exception e) {
logger.error("Caught exception while shutting down: " + e.getMessage());
}
}
}
/**
* MasterSlaveJedis工厂类
*
* @author pengpeng
* @date 2015年3月14日 上午10:09:00
* @version 1.0
*/
protected static class MasterSlaveJedisFactory implements PooledObjectFactory {
private JedisShardInfo masterShard;
private List slaveShards;
private Hashing algo;
private Pattern keyTagPattern;
public MasterSlaveJedisFactory(JedisShardInfo masterShard, List slaveShards, Hashing algo, Pattern keyTagPattern) {
this.masterShard = masterShard;
this.slaveShards = slaveShards;
this.algo = algo;
this.keyTagPattern = keyTagPattern;
}
public void setMasterShard(JedisShardInfo masterShard) {
this.masterShard = masterShard;
}
public void setSlaveShards(List slaveShards) {
this.slaveShards = slaveShards;
}
public PooledObject makeObject() throws Exception {
MasterSlaveJedis masterSlaveJedis = new MasterSlaveJedis(masterShard, slaveShards, algo, keyTagPattern);
return new DefaultPooledObject(masterSlaveJedis);
}
public void destroyObject(PooledObject pooledMasterSlaveJedis)
throws Exception {
pooledMasterSlaveJedis.getObject().disconnect();
}
public boolean validateObject(PooledObject pooledMasterSlaveJedis) {
try {
MasterSlaveJedis masterSlaveJedis = pooledMasterSlaveJedis.getObject();
if(!"PONG".equals(masterSlaveJedis.ping())){
return false;
}
for (Jedis slaveJedis : masterSlaveJedis.getAllShards()) {
if (!"PONG".equals(slaveJedis.ping())) {
return false;
}
}
return true;
} catch (Exception ex) {
return false;
}
}
public void activateObject(PooledObject p) throws Exception {
}
public void passivateObject(PooledObject p) throws Exception {
}
}
}