|
|
@ -17,11 +17,16 @@ package org.redisson.connection;
|
|
|
|
|
|
|
|
|
|
|
|
import java.net.URI;
|
|
|
|
import java.net.URI;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
|
|
|
import java.util.Collections;
|
|
|
|
import java.util.HashSet;
|
|
|
|
import java.util.HashSet;
|
|
|
|
|
|
|
|
import java.util.Iterator;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.Map;
|
|
|
|
import java.util.Map;
|
|
|
|
import java.util.Set;
|
|
|
|
import java.util.Set;
|
|
|
|
import java.util.concurrent.ConcurrentMap;
|
|
|
|
import java.util.concurrent.ConcurrentMap;
|
|
|
|
|
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
|
|
|
import java.util.concurrent.atomic.AtomicBoolean;
|
|
|
|
|
|
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
|
|
import java.util.concurrent.atomic.AtomicReference;
|
|
|
|
import java.util.concurrent.atomic.AtomicReference;
|
|
|
|
|
|
|
|
|
|
|
|
import org.redisson.api.NodeType;
|
|
|
|
import org.redisson.api.NodeType;
|
|
|
@ -40,6 +45,7 @@ import org.redisson.config.Config;
|
|
|
|
import org.redisson.config.MasterSlaveServersConfig;
|
|
|
|
import org.redisson.config.MasterSlaveServersConfig;
|
|
|
|
import org.redisson.config.SentinelServersConfig;
|
|
|
|
import org.redisson.config.SentinelServersConfig;
|
|
|
|
import org.redisson.connection.ClientConnectionsEntry.FreezeReason;
|
|
|
|
import org.redisson.connection.ClientConnectionsEntry.FreezeReason;
|
|
|
|
|
|
|
|
import org.redisson.misc.RPromise;
|
|
|
|
import org.redisson.misc.RedissonPromise;
|
|
|
|
import org.redisson.misc.RedissonPromise;
|
|
|
|
import org.redisson.misc.URIBuilder;
|
|
|
|
import org.redisson.misc.URIBuilder;
|
|
|
|
import org.slf4j.Logger;
|
|
|
|
import org.slf4j.Logger;
|
|
|
@ -47,6 +53,7 @@ import org.slf4j.LoggerFactory;
|
|
|
|
|
|
|
|
|
|
|
|
import io.netty.util.concurrent.Future;
|
|
|
|
import io.netty.util.concurrent.Future;
|
|
|
|
import io.netty.util.concurrent.FutureListener;
|
|
|
|
import io.netty.util.concurrent.FutureListener;
|
|
|
|
|
|
|
|
import io.netty.util.concurrent.ScheduledFuture;
|
|
|
|
import io.netty.util.internal.PlatformDependent;
|
|
|
|
import io.netty.util.internal.PlatformDependent;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
@ -60,9 +67,10 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
|
|
|
|
|
|
|
|
|
|
|
|
private final ConcurrentMap<String, RedisClient> sentinels = PlatformDependent.newConcurrentHashMap();
|
|
|
|
private final ConcurrentMap<String, RedisClient> sentinels = PlatformDependent.newConcurrentHashMap();
|
|
|
|
private final AtomicReference<String> currentMaster = new AtomicReference<String>();
|
|
|
|
private final AtomicReference<String> currentMaster = new AtomicReference<String>();
|
|
|
|
private final ConcurrentMap<String, Boolean> slaves = PlatformDependent.newConcurrentHashMap();
|
|
|
|
private final Set<String> slaves = Collections.newSetFromMap(PlatformDependent.<String, Boolean>newConcurrentHashMap());
|
|
|
|
|
|
|
|
|
|
|
|
private final Set<URI> disconnectedSlaves = new HashSet<URI>();
|
|
|
|
private final Set<URI> disconnectedSlaves = new HashSet<URI>();
|
|
|
|
|
|
|
|
private ScheduledFuture<?> monitorFuture;
|
|
|
|
|
|
|
|
|
|
|
|
public SentinelConnectionManager(SentinelServersConfig cfg, Config config) {
|
|
|
|
public SentinelConnectionManager(SentinelServersConfig cfg, Config config) {
|
|
|
|
super(config);
|
|
|
|
super(config);
|
|
|
@ -82,13 +90,12 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TODO async
|
|
|
|
|
|
|
|
List<String> master = connection.sync(RedisCommands.SENTINEL_GET_MASTER_ADDR_BY_NAME, cfg.getMasterName());
|
|
|
|
List<String> master = connection.sync(RedisCommands.SENTINEL_GET_MASTER_ADDR_BY_NAME, cfg.getMasterName());
|
|
|
|
String masterHost = createAddress(master.get(0), master.get(1));
|
|
|
|
String masterHost = createAddress(master.get(0), master.get(1));
|
|
|
|
this.config.setMasterAddress(masterHost);
|
|
|
|
this.config.setMasterAddress(masterHost);
|
|
|
|
currentMaster.set(masterHost);
|
|
|
|
currentMaster.set(masterHost);
|
|
|
|
log.info("master: {} added", masterHost);
|
|
|
|
log.info("master: {} added", masterHost);
|
|
|
|
slaves.put(masterHost, true);
|
|
|
|
slaves.add(masterHost);
|
|
|
|
|
|
|
|
|
|
|
|
List<Map<String, String>> sentinelSlaves = connection.sync(StringCodec.INSTANCE, RedisCommands.SENTINEL_SLAVES, cfg.getMasterName());
|
|
|
|
List<Map<String, String>> sentinelSlaves = connection.sync(StringCodec.INSTANCE, RedisCommands.SENTINEL_SLAVES, cfg.getMasterName());
|
|
|
|
for (Map<String, String> map : sentinelSlaves) {
|
|
|
|
for (Map<String, String> map : sentinelSlaves) {
|
|
|
@ -103,7 +110,7 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
|
|
|
|
String host = createAddress(ip, port);
|
|
|
|
String host = createAddress(ip, port);
|
|
|
|
|
|
|
|
|
|
|
|
this.config.addSlaveAddress(host);
|
|
|
|
this.config.addSlaveAddress(host);
|
|
|
|
slaves.put(host, true);
|
|
|
|
slaves.add(host);
|
|
|
|
log.debug("slave {} state: {}", host, map);
|
|
|
|
log.debug("slave {} state: {}", host, map);
|
|
|
|
log.info("slave: {} added", host);
|
|
|
|
log.info("slave: {} added", host);
|
|
|
|
|
|
|
|
|
|
|
@ -113,6 +120,27 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
|
|
|
|
log.warn("slave: {} is down", host);
|
|
|
|
log.warn("slave: {} is down", host);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
List<Map<String, String>> sentinelSentinels = connection.sync(StringCodec.INSTANCE, RedisCommands.SENTINEL_SENTINELS, cfg.getMasterName());
|
|
|
|
|
|
|
|
List<RFuture<Void>> connectionFutures = new ArrayList<RFuture<Void>>(sentinelSentinels.size());
|
|
|
|
|
|
|
|
for (Map<String, String> map : sentinelSentinels) {
|
|
|
|
|
|
|
|
if (map.isEmpty()) {
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String ip = map.get("ip");
|
|
|
|
|
|
|
|
String port = map.get("port");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String host = createAddress(ip, port);
|
|
|
|
|
|
|
|
URI sentinelAddr = URIBuilder.create(host);
|
|
|
|
|
|
|
|
RFuture<Void> future = registerSentinel(cfg, sentinelAddr, this.config);
|
|
|
|
|
|
|
|
connectionFutures.add(future);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (RFuture<Void> future : connectionFutures) {
|
|
|
|
|
|
|
|
future.awaitUninterruptibly(this.config.getConnectTimeout());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
} catch (RedisConnectionException e) {
|
|
|
|
} catch (RedisConnectionException e) {
|
|
|
|
log.warn("Can't connect to sentinel server. {}", e.getMessage());
|
|
|
|
log.warn("Can't connect to sentinel server. {}", e.getMessage());
|
|
|
@ -128,16 +156,181 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
|
|
|
|
|
|
|
|
|
|
|
|
initSingleEntry();
|
|
|
|
initSingleEntry();
|
|
|
|
|
|
|
|
|
|
|
|
List<RFuture<RedisPubSubConnection>> connectionFutures = new ArrayList<RFuture<RedisPubSubConnection>>(cfg.getSentinelAddresses().size());
|
|
|
|
scheduleChangeCheck(cfg, null);
|
|
|
|
for (URI addr : cfg.getSentinelAddresses()) {
|
|
|
|
}
|
|
|
|
RFuture<RedisPubSubConnection> future = registerSentinel(cfg, addr, this.config);
|
|
|
|
|
|
|
|
connectionFutures.add(future);
|
|
|
|
private void scheduleChangeCheck(final SentinelServersConfig cfg, final Iterator<RedisClient> iterator) {
|
|
|
|
|
|
|
|
monitorFuture = group.schedule(new Runnable() {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public void run() {
|
|
|
|
|
|
|
|
AtomicReference<Throwable> lastException = new AtomicReference<Throwable>();
|
|
|
|
|
|
|
|
Iterator<RedisClient> iter = iterator;
|
|
|
|
|
|
|
|
if (iter == null) {
|
|
|
|
|
|
|
|
iter = sentinels.values().iterator();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
checkState(cfg, iter, lastException);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}, cfg.getScanInterval(), TimeUnit.MILLISECONDS);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected void checkState(final SentinelServersConfig cfg, final Iterator<RedisClient> iterator, final AtomicReference<Throwable> lastException) {
|
|
|
|
|
|
|
|
if (!iterator.hasNext()) {
|
|
|
|
|
|
|
|
log.error("Can't update cluster state", lastException.get());
|
|
|
|
|
|
|
|
scheduleChangeCheck(cfg, null);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!getShutdownLatch().acquire()) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
RedisClient client = iterator.next();
|
|
|
|
|
|
|
|
RFuture<RedisConnection> connectionFuture = connectToNode(null, null, client);
|
|
|
|
|
|
|
|
connectionFuture.addListener(new FutureListener<RedisConnection>() {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public void operationComplete(Future<RedisConnection> future) throws Exception {
|
|
|
|
|
|
|
|
if (!future.isSuccess()) {
|
|
|
|
|
|
|
|
lastException.set(future.cause());
|
|
|
|
|
|
|
|
getShutdownLatch().release();
|
|
|
|
|
|
|
|
checkState(cfg, iterator, lastException);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
RedisConnection connection = future.getNow();
|
|
|
|
|
|
|
|
updateState(cfg, connection, iterator);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected void updateState(final SentinelServersConfig cfg, final RedisConnection connection, final Iterator<RedisClient> iterator) {
|
|
|
|
|
|
|
|
final AtomicInteger commands = new AtomicInteger(2);
|
|
|
|
|
|
|
|
FutureListener<Object> commonListener = new FutureListener<Object>() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final AtomicBoolean failed = new AtomicBoolean();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public void operationComplete(Future<Object> future) throws Exception {
|
|
|
|
|
|
|
|
if (commands.decrementAndGet() == 0) {
|
|
|
|
|
|
|
|
getShutdownLatch().release();
|
|
|
|
|
|
|
|
if (failed.get()) {
|
|
|
|
|
|
|
|
scheduleChangeCheck(cfg, iterator);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
scheduleChangeCheck(cfg, null);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!future.isSuccess() && failed.compareAndSet(false, true)) {
|
|
|
|
|
|
|
|
log.error("Can't execute SENTINEL commands on " + connection.getRedisClient().getAddr(), future.cause());
|
|
|
|
|
|
|
|
closeNodeConnection(connection);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
RFuture<List<String>> masterFuture = connection.async(StringCodec.INSTANCE, RedisCommands.SENTINEL_GET_MASTER_ADDR_BY_NAME, cfg.getMasterName());
|
|
|
|
|
|
|
|
masterFuture.addListener(new FutureListener<List<String>>() {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public void operationComplete(Future<List<String>> future) throws Exception {
|
|
|
|
|
|
|
|
if (!future.isSuccess()) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
List<String> master = future.getNow();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String current = currentMaster.get();
|
|
|
|
|
|
|
|
String newMaster = createAddress(master.get(0), master.get(1));
|
|
|
|
|
|
|
|
if (!newMaster.equals(current)
|
|
|
|
|
|
|
|
&& currentMaster.compareAndSet(current, newMaster)) {
|
|
|
|
|
|
|
|
changeMaster(singleSlotRange.getStartSlot(), URIBuilder.create(newMaster));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
masterFuture.addListener(commonListener);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!config.checkSkipSlavesInit()) {
|
|
|
|
|
|
|
|
RFuture<List<Map<String, String>>> slavesFuture = connection.async(StringCodec.INSTANCE, RedisCommands.SENTINEL_SLAVES, cfg.getMasterName());
|
|
|
|
|
|
|
|
commands.incrementAndGet();
|
|
|
|
|
|
|
|
slavesFuture.addListener(new FutureListener<List<Map<String, String>>>() {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public void operationComplete(Future<List<Map<String, String>>> future) throws Exception {
|
|
|
|
|
|
|
|
if (!future.isSuccess()) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (RFuture<RedisPubSubConnection> future : connectionFutures) {
|
|
|
|
List<Map<String, String>> slavesMap = future.getNow();
|
|
|
|
future.awaitUninterruptibly();
|
|
|
|
final Set<String> currentSlaves = new HashSet<String>(slavesMap.size());
|
|
|
|
|
|
|
|
List<RFuture<Void>> futures = new ArrayList<RFuture<Void>>();
|
|
|
|
|
|
|
|
for (Map<String, String> map : slavesMap) {
|
|
|
|
|
|
|
|
if (map.isEmpty()) {
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String ip = map.get("ip");
|
|
|
|
|
|
|
|
String port = map.get("port");
|
|
|
|
|
|
|
|
String flags = map.get("flags");
|
|
|
|
|
|
|
|
String masterHost = map.get("master-host");
|
|
|
|
|
|
|
|
String masterPort = map.get("master-port");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!isUseSameMaster(ip, port, masterHost, masterPort)) {
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags.contains("s_down") || flags.contains("disconnected")) {
|
|
|
|
|
|
|
|
slaveDown(ip, port);
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String slaveAddr = createAddress(ip, port);
|
|
|
|
|
|
|
|
currentSlaves.add(slaveAddr);
|
|
|
|
|
|
|
|
RFuture<Void> slaveFuture = addSlave(ip, port, slaveAddr);
|
|
|
|
|
|
|
|
futures.add(slaveFuture);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CountableListener<Void> listener = new CountableListener<Void>() {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
protected void onSuccess(Void value) {
|
|
|
|
|
|
|
|
Set<String> removedSlaves = new HashSet<String>(slaves);
|
|
|
|
|
|
|
|
removedSlaves.removeAll(currentSlaves);
|
|
|
|
|
|
|
|
for (String slave : removedSlaves) {
|
|
|
|
|
|
|
|
slaves.remove(slave);
|
|
|
|
|
|
|
|
String[] parts = slave.replace("redis://", "").split(":");
|
|
|
|
|
|
|
|
slaveDown(parts[0], parts[1]);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
listener.setCounter(futures.size());
|
|
|
|
|
|
|
|
for (RFuture<Void> f : futures) {
|
|
|
|
|
|
|
|
f.addListener(listener);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
slavesFuture.addListener(commonListener);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
RFuture<List<Map<String, String>>> sentinelsFuture = connection.async(StringCodec.INSTANCE, RedisCommands.SENTINEL_SENTINELS, cfg.getMasterName());
|
|
|
|
|
|
|
|
sentinelsFuture.addListener(new FutureListener<List<Map<String, String>>>() {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public void operationComplete(Future<List<Map<String, String>>> future) throws Exception {
|
|
|
|
|
|
|
|
if (!future.isSuccess()) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
List<Map<String, String>> list = future.getNow();
|
|
|
|
|
|
|
|
for (Map<String, String> map : list) {
|
|
|
|
|
|
|
|
if (map.isEmpty()) {
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String ip = map.get("ip");
|
|
|
|
|
|
|
|
String port = map.get("port");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String host = createAddress(ip, port);
|
|
|
|
|
|
|
|
URI sentinelAddr = URIBuilder.create(host);
|
|
|
|
|
|
|
|
registerSentinel(cfg, sentinelAddr, getConfig());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
sentinelsFuture.addListener(commonListener);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private String createAddress(String host, Object port) {
|
|
|
|
private String createAddress(String host, Object port) {
|
|
|
|
if (host.contains(":")) {
|
|
|
|
if (host.contains(":")) {
|
|
|
@ -157,9 +350,15 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
|
|
|
|
return entry;
|
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private RFuture<RedisPubSubConnection> registerSentinel(final SentinelServersConfig cfg, final URI addr, final MasterSlaveServersConfig c) {
|
|
|
|
private RFuture<Void> registerSentinel(final SentinelServersConfig cfg, final URI addr, final MasterSlaveServersConfig c) {
|
|
|
|
RedisClient client = createClient(NodeType.SENTINEL, addr, c.getConnectTimeout(), c.getRetryInterval() * c.getRetryAttempts());
|
|
|
|
String key = addr.getHost() + ":" + addr.getPort();
|
|
|
|
RedisClient oldClient = sentinels.putIfAbsent(addr.getHost() + ":" + addr.getPort(), client);
|
|
|
|
RedisClient client = sentinels.get(key);
|
|
|
|
|
|
|
|
if (client != null) {
|
|
|
|
|
|
|
|
return RedissonPromise.newSucceededFuture(null);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
client = createClient(NodeType.SENTINEL, addr, c.getConnectTimeout(), c.getRetryInterval() * c.getRetryAttempts());
|
|
|
|
|
|
|
|
RedisClient oldClient = sentinels.putIfAbsent(key, client);
|
|
|
|
if (oldClient != null) {
|
|
|
|
if (oldClient != null) {
|
|
|
|
return RedissonPromise.newSucceededFuture(null);
|
|
|
|
return RedissonPromise.newSucceededFuture(null);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -178,6 +377,8 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
|
public void onMessage(String channel, Object msg) {
|
|
|
|
public void onMessage(String channel, Object msg) {
|
|
|
|
|
|
|
|
log.debug("message {} from {}", msg, channel);
|
|
|
|
|
|
|
|
|
|
|
|
if ("+sentinel".equals(channel)) {
|
|
|
|
if ("+sentinel".equals(channel)) {
|
|
|
|
onSentinelAdded(cfg, (String) msg, c);
|
|
|
|
onSentinelAdded(cfg, (String) msg, c);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -209,7 +410,7 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
return pubsubFuture;
|
|
|
|
return RedissonPromise.newSucceededFuture(null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected void onSentinelAdded(SentinelServersConfig cfg, String msg, MasterSlaveServersConfig c) {
|
|
|
|
protected void onSentinelAdded(SentinelServersConfig cfg, String msg, MasterSlaveServersConfig c) {
|
|
|
@ -228,17 +429,24 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
|
|
|
|
|
|
|
|
|
|
|
|
if (parts.length > 4
|
|
|
|
if (parts.length > 4
|
|
|
|
&& "slave".equals(parts[0])) {
|
|
|
|
&& "slave".equals(parts[0])) {
|
|
|
|
final String ip = parts[2];
|
|
|
|
String ip = parts[2];
|
|
|
|
final String port = parts[3];
|
|
|
|
String port = parts[3];
|
|
|
|
|
|
|
|
|
|
|
|
final String slaveAddr = createAddress(ip, port);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!isUseSameMaster(parts)) {
|
|
|
|
if (!isUseSameMaster(parts)) {
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String slaveAddr = createAddress(ip, port);
|
|
|
|
|
|
|
|
addSlave(ip, port, slaveAddr);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
log.warn("onSlaveAdded. Invalid message: {} from Sentinel {}:{}", msg, addr.getHost(), addr.getPort());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected RFuture<Void> addSlave(final String ip, final String port, final String slaveAddr) {
|
|
|
|
|
|
|
|
final RPromise<Void> result = new RedissonPromise<Void>();
|
|
|
|
// to avoid addition twice
|
|
|
|
// to avoid addition twice
|
|
|
|
if (slaves.putIfAbsent(slaveAddr, true) == null && !config.checkSkipSlavesInit()) {
|
|
|
|
if (slaves.add(slaveAddr) && !config.checkSkipSlavesInit()) {
|
|
|
|
final MasterSlaveEntry entry = getEntry(singleSlotRange.getStartSlot());
|
|
|
|
final MasterSlaveEntry entry = getEntry(singleSlotRange.getStartSlot());
|
|
|
|
RFuture<Void> future = entry.addSlave(URIBuilder.create(slaveAddr));
|
|
|
|
RFuture<Void> future = entry.addSlave(URIBuilder.create(slaveAddr));
|
|
|
|
future.addListener(new FutureListener<Void>() {
|
|
|
|
future.addListener(new FutureListener<Void>() {
|
|
|
@ -246,6 +454,7 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
|
|
|
|
public void operationComplete(Future<Void> future) throws Exception {
|
|
|
|
public void operationComplete(Future<Void> future) throws Exception {
|
|
|
|
if (!future.isSuccess()) {
|
|
|
|
if (!future.isSuccess()) {
|
|
|
|
slaves.remove(slaveAddr);
|
|
|
|
slaves.remove(slaveAddr);
|
|
|
|
|
|
|
|
result.tryFailure(future.cause());
|
|
|
|
log.error("Can't add slave: " + slaveAddr, future.cause());
|
|
|
|
log.error("Can't add slave: " + slaveAddr, future.cause());
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -254,16 +463,16 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
|
|
|
|
if (entry.slaveUp(uri, FreezeReason.MANAGER)) {
|
|
|
|
if (entry.slaveUp(uri, FreezeReason.MANAGER)) {
|
|
|
|
String slaveAddr = ip + ":" + port;
|
|
|
|
String slaveAddr = ip + ":" + port;
|
|
|
|
log.info("slave: {} added", slaveAddr);
|
|
|
|
log.info("slave: {} added", slaveAddr);
|
|
|
|
|
|
|
|
result.trySuccess(null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
slaveUp(ip, port);
|
|
|
|
slaveUp(ip, port);
|
|
|
|
|
|
|
|
result.trySuccess(null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return result;
|
|
|
|
log.warn("onSlaveAdded. Invalid message: {} from Sentinel {}:{}", msg, addr.getHost(), addr.getPort());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected URI convert(String ip, String port) {
|
|
|
|
protected URI convert(String ip, String port) {
|
|
|
@ -322,15 +531,14 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private boolean isUseSameMaster(String[] parts) {
|
|
|
|
private boolean isUseSameMaster(String[] parts) {
|
|
|
|
String ip = parts[2];
|
|
|
|
return isUseSameMaster(parts[2], parts[3], parts[6], parts[7]);
|
|
|
|
String port = parts[3];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
String slaveAddr = ip + ":" + port;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected boolean isUseSameMaster(String slaveIp, String slavePort, String slaveMasterHost, String slaveMasterPort) {
|
|
|
|
String master = currentMaster.get();
|
|
|
|
String master = currentMaster.get();
|
|
|
|
String slaveMaster = createAddress(parts[6], parts[7]);
|
|
|
|
String slaveMaster = createAddress(slaveMasterHost, slaveMasterPort);
|
|
|
|
if (!master.equals(slaveMaster)) {
|
|
|
|
if (!master.equals(slaveMaster)) {
|
|
|
|
log.warn("Skipped slave up {} for master {} differs from current {}", slaveAddr, slaveMaster, master);
|
|
|
|
log.warn("Skipped slave up {} for master {} differs from current {}", slaveIp + ":" + slavePort, slaveMaster, master);
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
@ -410,6 +618,8 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
|
public void shutdown() {
|
|
|
|
public void shutdown() {
|
|
|
|
|
|
|
|
monitorFuture.cancel(true);
|
|
|
|
|
|
|
|
|
|
|
|
List<RFuture<Void>> futures = new ArrayList<RFuture<Void>>();
|
|
|
|
List<RFuture<Void>> futures = new ArrayList<RFuture<Void>>();
|
|
|
|
for (RedisClient sentinel : sentinels.values()) {
|
|
|
|
for (RedisClient sentinel : sentinels.values()) {
|
|
|
|
RFuture<Void> future = sentinel.shutdownAsync();
|
|
|
|
RFuture<Void> future = sentinel.shutdownAsync();
|
|
|
|