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.ShardedMasterSlaveJedisSentinelPool 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 ShardedMasterSlaveJedisSentinelPool extends Pool {
private Logger logger = LoggerFactory.getLogger(ShardedMasterSlaveJedisSentinelPool.class);
protected Set masterNames;
protected Set sentinels;
protected GenericObjectPoolConfig poolConfig;
protected int timeout = Protocol.DEFAULT_TIMEOUT;
protected String password;
protected int database = Protocol.DEFAULT_DATABASE;
protected volatile Set currentHostMasterSlaves;
protected Set shardedMasterSlaveListeners = new HashSet();
private volatile ShardedMasterSlaveJedisFactory factory;
public ShardedMasterSlaveJedisSentinelPool(Set masterNames, Set sentinels, final GenericObjectPoolConfig poolConfig) {
this(masterNames, sentinels, poolConfig, Protocol.DEFAULT_TIMEOUT, null, Protocol.DEFAULT_DATABASE);
}
public ShardedMasterSlaveJedisSentinelPool(Set masterNames, Set sentinels) {
this(masterNames, sentinels, new GenericObjectPoolConfig(), Protocol.DEFAULT_TIMEOUT, null, Protocol.DEFAULT_DATABASE);
}
public ShardedMasterSlaveJedisSentinelPool(Set masterNames, Set sentinels, String password) {
this(masterNames, sentinels, new GenericObjectPoolConfig(), Protocol.DEFAULT_TIMEOUT, password);
}
public ShardedMasterSlaveJedisSentinelPool(Set masterNames, Set sentinels, final GenericObjectPoolConfig poolConfig, int timeout, final String password) {
this(masterNames, sentinels, poolConfig, timeout, password, Protocol.DEFAULT_DATABASE);
}
public ShardedMasterSlaveJedisSentinelPool(Set masterNames, Set sentinels, final GenericObjectPoolConfig poolConfig, final int timeout) {
this(masterNames, sentinels, poolConfig, timeout, null, Protocol.DEFAULT_DATABASE);
}
public ShardedMasterSlaveJedisSentinelPool(Set masterNames, Set sentinels, final GenericObjectPoolConfig poolConfig, final String password) {
this(masterNames, sentinels, poolConfig, Protocol.DEFAULT_TIMEOUT, password);
}
/**
* Master-Slave must be use the same config
*/
public ShardedMasterSlaveJedisSentinelPool(Set masterNames, Set sentinels, final GenericObjectPoolConfig poolConfig, int timeout, final String password, final int database) {
if(!(masterNames instanceof LinkedHashSet)){
throw new IllegalArgumentException("Parameter 'masterNames' must be typeof java.util.LinkedHashSet.");
}
this.masterNames = masterNames;
this.sentinels = sentinels;
this.poolConfig = poolConfig;
this.timeout = timeout;
this.password = password;
this.database = database;
initSentinelPool();
initSentinelLiseners();
}
protected void initSentinelPool() {
Set masterSlaveHostAndPorts = sentinelGetMasterSlaves();
initPool(masterSlaveHostAndPorts);
}
protected Set sentinelGetMasterSlaves() {
Set masterSlaveHostAndPorts = new LinkedHashSet();
logger.info("Trying to find Sharded-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());
for(String masterName : masterNames){
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;
}
HostAndPort master = toHostAndPort(masterAddr);
Set slaves = new LinkedHashSet();
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 sharded master-slaves : {}", masterSlaveHostAndPort);
masterSlaveHostAndPorts.add(masterSlaveHostAndPort);
}
return masterSlaveHostAndPorts;
} 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(currentHostMasterSlaves != null){
logger.info("Starting Sentinel listeners...");
for (String sentinel : sentinels) {
try {
final HostAndPort hap = toHostAndPort(Arrays.asList(sentinel.split(":")));
ShardedMasterSlaveListener shardedMasterSlaveListener = new ShardedMasterSlaveListener(masterNames, hap.getHost(), hap.getPort());
shardedMasterSlaveListeners.add(shardedMasterSlaveListener);
shardedMasterSlaveListener.start();
} catch(Exception e) {
logger.error("Starting Sentinel listeners caught a exception: " + e.getMessage(), e);
}
}
}
}
protected synchronized void initPool(Set masterSlaveHostAndPorts){
if(masterSlaveHostAndPorts != null && !masterSlaveHostAndPorts.equals(currentHostMasterSlaves)){
currentHostMasterSlaves = masterSlaveHostAndPorts;
List shards = new ArrayList();
for(MasterSlaveHostAndPort masterSlaveHostAndPort : masterSlaveHostAndPorts){
JedisShardInfo masterShard = toJedisShardInfo(masterSlaveHostAndPort.getMaster(), masterSlaveHostAndPort.getMasterName());
List slaveShards = new ArrayList();
for(HostAndPort slave : masterSlaveHostAndPort.getSlaves()){
JedisShardInfo slaveShard = toJedisShardInfo(slave, masterSlaveHostAndPort.getMasterName());
slaveShards.add(slaveShard);
}
shards.add(new MasterSlaveJedisShardInfo(masterSlaveHostAndPort.getMasterName(), masterShard, slaveShards));
}
if(factory == null){
factory = new ShardedMasterSlaveJedisFactory(shards, Hashing.MURMUR_HASH, null);
initPool(poolConfig, factory);
}else{
factory.setShards(shards);
// 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 Sharded-Master-Slaves jedis pool for {}", currentHostMasterSlaves);
}
}
protected JedisShardInfo toJedisShardInfo(HostAndPort hostAndPort, String masterName) {
JedisShardInfo shard = new JedisShardInfo(hostAndPort.getHost(), hostAndPort.getPort(), timeout, masterName);
shard.setPassword(password);
return shard;
}
public ShardedMasterSlaveJedis getResource() {
while (true) {
ShardedMasterSlaveJedis shardedMasterSlaveJedis = super.getResource();
shardedMasterSlaveJedis.setDataSource(this);
// get a reference because it can change concurrently
final Set reference = currentHostMasterSlaves;
final Set connectionDesc = shardedMasterSlaveJedis.getConnectionDesc();
if (connectionDesc.equals(reference)) {
// connected to the correct master
return shardedMasterSlaveJedis;
} else {
returnBrokenResource(shardedMasterSlaveJedis);
}
}
}
public void returnBrokenResource(final ShardedMasterSlaveJedis resource) {
if (resource != null) {
returnBrokenResourceObject(resource);
}
}
public void returnResource(final ShardedMasterSlaveJedis resource) {
if (resource != null) {
// get a reference because it can change concurrently
final Set reference = currentHostMasterSlaves;
final Set connectionDesc = resource.getConnectionDesc();
if (connectionDesc.equals(reference)) {
resource.resetState();
returnResourceObject(resource);
} else {
returnBrokenResource(resource);
}
}
}
public void destroy() {
for (ShardedMasterSlaveListener m : shardedMasterSlaveListeners) {
m.shutdown();
}
super.destroy();
}
public Set getCurrentHostMasterSlaves() {
return currentHostMasterSlaves;
}
protected HostAndPort toHostAndPort(List hostAndPort){
return new HostAndPort(hostAndPort.get(0), Integer.parseInt(hostAndPort.get(1)));
}
protected class ShardedMasterSlaveListener extends Thread {
protected Set masterNames;
protected String host;
protected int port;
protected long subscribeRetryWaitTimeMillis = 5000;
protected Jedis sentinelJedis;
protected AtomicBoolean running = new AtomicBoolean(false);
protected ShardedMasterSlaveListener() {
}
public ShardedMasterSlaveListener(Set masterNames, String host, int port) {
this.masterNames = masterNames;
this.host = host;
this.port = port;
}
public ShardedMasterSlaveListener(Set masterNames, String host, int port, long subscribeRetryWaitTimeMillis) {
this(masterNames, 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(masterNames.contains(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, messages[5], masterIp + ":" + masterPort);
initSentinelPool();
}else{
logger.error("Ignoring message on +sdown for master name {}, but our master name is {}!", messages[5], masterNames);
}
}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(masterNames.contains(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, messages[5], masterIp + ":" + masterPort);
initSentinelPool();
}else{
logger.error("Ignoring message on -sdown for master name {}, but our master name is {}!", messages[5], masterNames);
}
}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(masterNames.contains(messages[0])){
String oldMasterIp = messages[1];
String oldMasterPort = messages[2];
String newMasterIp = messages[3];
String newMasterPort = messages[4];
logger.info("Switch master {} from [{}] to [{}]", messages[0], oldMasterIp + ":" + oldMasterPort, newMasterIp + ":" + newMasterPort);
initSentinelPool();
}else{
logger.error("Ignoring message on +switch-master for master name {}, but our master name is {}!", messages[5], masterNames);
}
}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(masterNames.contains(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, messages[5], masterIp + ":" + masterPort);
initSentinelPool();
}else{
logger.error("Ignoring message on +slave for master name {}, but our master name is {}!", messages[5], masterNames);
}
}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());
}
}
}
/**
* ShardedMasterSlaveJedis工厂类
*
* @author pengpeng
* @date 2015年3月14日 上午10:09:00
* @version 1.0
*/
protected class ShardedMasterSlaveJedisFactory implements PooledObjectFactory {
private List shards;
private Hashing algo;
private Pattern keyTagPattern;
public ShardedMasterSlaveJedisFactory(List shards, Hashing algo, Pattern keyTagPattern) {
this.shards = shards;
this.algo = algo;
this.keyTagPattern = keyTagPattern;
}
public void setShards(List shards) {
this.shards = shards;
}
public PooledObject makeObject() throws Exception {
ShardedMasterSlaveJedis shardedMasterSlaveJedis = new ShardedMasterSlaveJedis(shards, algo, keyTagPattern);
return new DefaultPooledObject(shardedMasterSlaveJedis);
}
public void destroyObject(PooledObject pooledShardedMasterSlaveJedis)
throws Exception {
pooledShardedMasterSlaveJedis.getObject().disconnect();
}
public boolean validateObject(PooledObject pooledObject) {
try {
ShardedMasterSlaveJedis pooledShardedMasterSlaveJedis = pooledObject.getObject();
if(pooledShardedMasterSlaveJedis.ping()){
return true;
}
return false;
} catch (Exception ex) {
return false;
}
}
public void activateObject(PooledObject p) throws Exception {
}
public void passivateObject(PooledObject p) throws Exception {
}
}
}