Merge branch 'introduce-new-sentinel-commands-added-to-Redis-2.8' of github.com:HeartSaVioR/jedis into HeartSaVioR-introduce-new-sentinel-commands-added-to-Redis-2.8

This commit is contained in:
Jonathan Leibiusky
2014-02-11 12:11:57 -05:00
8 changed files with 258 additions and 53 deletions

View File

@@ -65,6 +65,29 @@ appendonly no
slaveof localhost 6379 slaveof localhost 6379
endef endef
define REDIS7_CONF
daemonize yes
port 6385
requirepass foobared
masterauth foobared
pidfile /tmp/redis7.pid
logfile /tmp/redis7.log
save ""
appendonly no
endef
define REDIS8_CONF
daemonize yes
port 6386
requirepass foobared
masterauth foobared
pidfile /tmp/redis8.pid
logfile /tmp/redis8.log
save ""
appendonly no
slaveof localhost 6385
endef
# SENTINELS # SENTINELS
define REDIS_SENTINEL1 define REDIS_SENTINEL1
port 26379 port 26379
@@ -102,6 +125,18 @@ pidfile /tmp/sentinel3.pid
logfile /tmp/sentinel3.log logfile /tmp/sentinel3.log
endef endef
define REDIS_SENTINEL4
port 26382
daemonize yes
sentinel monitor mymasterfailover 127.0.0.1 6385 1
sentinel auth-pass mymasterfailover foobared
sentinel down-after-milliseconds mymasterfailover 3000
sentinel failover-timeout mymasterfailover 900000
sentinel parallel-syncs mymasterfailover 1
pidfile /tmp/sentinel4.pid
logfile /tmp/sentinel4.log
endef
# CLUSTER REDIS NODES # CLUSTER REDIS NODES
define REDIS_CLUSTER_NODE1_CONF define REDIS_CLUSTER_NODE1_CONF
daemonize yes daemonize yes
@@ -142,9 +177,12 @@ export REDIS3_CONF
export REDIS4_CONF export REDIS4_CONF
export REDIS5_CONF export REDIS5_CONF
export REDIS6_CONF export REDIS6_CONF
export REDIS7_CONF
export REDIS8_CONF
export REDIS_SENTINEL1 export REDIS_SENTINEL1
export REDIS_SENTINEL2 export REDIS_SENTINEL2
export REDIS_SENTINEL3 export REDIS_SENTINEL3
export REDIS_SENTINEL4
export REDIS_CLUSTER_NODE1_CONF export REDIS_CLUSTER_NODE1_CONF
export REDIS_CLUSTER_NODE2_CONF export REDIS_CLUSTER_NODE2_CONF
export REDIS_CLUSTER_NODE3_CONF export REDIS_CLUSTER_NODE3_CONF
@@ -156,11 +194,15 @@ start: cleanup
echo "$$REDIS4_CONF" | redis-server - echo "$$REDIS4_CONF" | redis-server -
echo "$$REDIS5_CONF" | redis-server - echo "$$REDIS5_CONF" | redis-server -
echo "$$REDIS6_CONF" | redis-server - echo "$$REDIS6_CONF" | redis-server -
echo "$$REDIS7_CONF" | redis-server -
echo "$$REDIS8_CONF" | redis-server -
echo "$$REDIS_SENTINEL1" > /tmp/sentinel1.conf && redis-server /tmp/sentinel1.conf --sentinel echo "$$REDIS_SENTINEL1" > /tmp/sentinel1.conf && redis-server /tmp/sentinel1.conf --sentinel
@sleep 0.5 @sleep 0.5
echo "$$REDIS_SENTINEL2" > /tmp/sentinel2.conf && redis-server /tmp/sentinel2.conf --sentinel echo "$$REDIS_SENTINEL2" > /tmp/sentinel2.conf && redis-server /tmp/sentinel2.conf --sentinel
@sleep 0.5 @sleep 0.5
echo "$$REDIS_SENTINEL3" > /tmp/sentinel3.conf && redis-server /tmp/sentinel3.conf --sentinel echo "$$REDIS_SENTINEL3" > /tmp/sentinel3.conf && redis-server /tmp/sentinel3.conf --sentinel
@sleep 0.5
echo "$$REDIS_SENTINEL4" > /tmp/sentinel4.conf && redis-server /tmp/sentinel4.conf --sentinel
echo "$$REDIS_CLUSTER_NODE1_CONF" | redis-server - echo "$$REDIS_CLUSTER_NODE1_CONF" | redis-server -
echo "$$REDIS_CLUSTER_NODE2_CONF" | redis-server - echo "$$REDIS_CLUSTER_NODE2_CONF" | redis-server -
echo "$$REDIS_CLUSTER_NODE3_CONF" | redis-server - echo "$$REDIS_CLUSTER_NODE3_CONF" | redis-server -
@@ -177,12 +219,19 @@ stop:
kill `cat /tmp/redis4.pid` || true kill `cat /tmp/redis4.pid` || true
kill `cat /tmp/redis5.pid` || true kill `cat /tmp/redis5.pid` || true
kill `cat /tmp/redis6.pid` || true kill `cat /tmp/redis6.pid` || true
kill `cat /tmp/redis7.pid`
kill `cat /tmp/redis8.pid`
kill `cat /tmp/sentinel1.pid` kill `cat /tmp/sentinel1.pid`
kill `cat /tmp/sentinel2.pid` kill `cat /tmp/sentinel2.pid`
kill `cat /tmp/sentinel3.pid` kill `cat /tmp/sentinel3.pid`
kill `cat /tmp/sentinel4.pid`
kill `cat /tmp/redis_cluster_node1.pid` || true kill `cat /tmp/redis_cluster_node1.pid` || true
kill `cat /tmp/redis_cluster_node2.pid` || true kill `cat /tmp/redis_cluster_node2.pid` || true
kill `cat /tmp/redis_cluster_node3.pid` || true kill `cat /tmp/redis_cluster_node3.pid` || true
rm -f /tmp/sentinel1.conf
rm -f /tmp/sentinel2.conf
rm -f /tmp/sentinel3.conf
rm -f /tmp/sentinel4.conf
rm -f /tmp/redis_cluster_node1.conf rm -f /tmp/redis_cluster_node1.conf
rm -f /tmp/redis_cluster_node2.conf rm -f /tmp/redis_cluster_node2.conf
rm -f /tmp/redis_cluster_node3.conf rm -f /tmp/redis_cluster_node3.conf

View File

@@ -45,8 +45,8 @@
</scm> </scm>
<properties> <properties>
<redis-hosts>localhost:6379,localhost:6380,localhost:6381,localhost:6382,localhost:6383,localhost:6384</redis-hosts> <redis-hosts>localhost:6379,localhost:6380,localhost:6381,localhost:6382,localhost:6383,localhost:6384,localhost:6385,localhost:6386</redis-hosts>
<sentinel-hosts>localhost:26379,localhost:26380,localhost:26381</sentinel-hosts> <sentinel-hosts>localhost:26379,localhost:26380,localhost:26381,localhost:26382</sentinel-hosts>
<cluster-hosts>localhost:7379,localhost:7380,localhost:7381</cluster-hosts> <cluster-hosts>localhost:7379,localhost:7380,localhost:7381</cluster-hosts>
<github.global.server>github</github.global.server> <github.global.server>github</github.global.server>
</properties> </properties>

View File

@@ -8,6 +8,7 @@ import java.util.Iterator;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import redis.clients.jedis.BinaryClient.LIST_POSITION; import redis.clients.jedis.BinaryClient.LIST_POSITION;
@@ -3012,6 +3013,40 @@ public class Jedis extends BinaryJedis implements JedisCommands,
return slaves; return slaves;
} }
public String sentinelFailover(String masterName) {
client.sentinel(Protocol.SENTINEL_FAILOVER, masterName);
return client.getStatusCodeReply();
}
public String sentinelMonitor(String masterName, String ip, int port,
int quorum) {
client.sentinel(Protocol.SENTINEL_MONITOR, masterName, ip,
String.valueOf(port), String.valueOf(quorum));
return client.getStatusCodeReply();
}
public String sentinelRemove(String masterName) {
client.sentinel(Protocol.SENTINEL_REMOVE, masterName);
return client.getStatusCodeReply();
}
public String sentinelSet(String masterName,
Map<String, String> parameterMap) {
int index = 0;
int paramsLength = parameterMap.size() * 2 + 2;
String[] params = new String[paramsLength];
params[index++] = Protocol.SENTINEL_SET;
params[index++] = masterName;
for (Entry<String, String> entry : parameterMap.entrySet()) {
params[index++] = entry.getKey();
params[index++] = entry.getValue();
}
client.sentinel(params);
return client.getStatusCodeReply();
}
public byte[] dump(final String key) { public byte[] dump(final String key) {
checkIsInMulti(); checkIsInMulti();
client.dump(key); client.dump(key);

View File

@@ -33,6 +33,10 @@ public final class Protocol {
public static final String SENTINEL_GET_MASTER_ADDR_BY_NAME = "get-master-addr-by-name"; public static final String SENTINEL_GET_MASTER_ADDR_BY_NAME = "get-master-addr-by-name";
public static final String SENTINEL_RESET = "reset"; public static final String SENTINEL_RESET = "reset";
public static final String SENTINEL_SLAVES = "slaves"; public static final String SENTINEL_SLAVES = "slaves";
public static final String SENTINEL_FAILOVER = "failover";
public static final String SENTINEL_MONITOR = "monitor";
public static final String SENTINEL_REMOVE = "remove";
public static final String SENTINEL_SET = "set";
public static final String CLUSTER_NODES = "nodes"; public static final String CLUSTER_NODES = "nodes";
public static final String CLUSTER_MEET = "meet"; public static final String CLUSTER_MEET = "meet";

View File

@@ -0,0 +1,22 @@
package redis.clients.jedis;
import java.util.List;
import java.util.Map;
public interface SentinelCommands {
public List<Map<String, String>> sentinelMasters();
public List<String> sentinelGetMasterAddrByName(String masterName);
public Long sentinelReset(String pattern);
public List<Map<String, String>> sentinelSlaves(String masterName);
public String sentinelFailover(String masterName);
public String sentinelMonitor(String masterName, String ip, int port, int quorum);
public String sentinelRemove(String masterName);
public String sentinelSet(String masterName, Map<String, String> parameterMap);
}

View File

@@ -12,42 +12,18 @@ public class HostAndPortUtil {
private static List<HostAndPort> clusterHostAndPortList = new ArrayList<HostAndPort>(); private static List<HostAndPort> clusterHostAndPortList = new ArrayList<HostAndPort>();
static { static {
redisHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_PORT));
redisHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_PORT + 1));
redisHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_PORT + 2));
redisHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_PORT + 3));
redisHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_PORT + 4));
redisHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_PORT + 5));
redisHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_PORT + 6));
HostAndPort defaulthnp1 = new HostAndPort("localhost", sentinelHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_SENTINEL_PORT));
Protocol.DEFAULT_PORT); sentinelHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_SENTINEL_PORT + 1));
redisHostAndPortList.add(defaulthnp1); sentinelHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_SENTINEL_PORT + 2));
sentinelHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_SENTINEL_PORT + 3));
HostAndPort defaulthnp2 = new HostAndPort("localhost",
Protocol.DEFAULT_PORT + 1);
redisHostAndPortList.add(defaulthnp2);
HostAndPort defaulthnp3 = new HostAndPort("localhost",
Protocol.DEFAULT_PORT + 2);
redisHostAndPortList.add(defaulthnp3);
HostAndPort defaulthnp4 = new HostAndPort("localhost",
Protocol.DEFAULT_PORT + 3);
redisHostAndPortList.add(defaulthnp4);
HostAndPort defaulthnp5 = new HostAndPort("localhost",
Protocol.DEFAULT_PORT + 4);
redisHostAndPortList.add(defaulthnp5);
HostAndPort defaulthnp6 = new HostAndPort("localhost",
Protocol.DEFAULT_PORT + 5);
redisHostAndPortList.add(defaulthnp6);
HostAndPort defaulthnp7 = new HostAndPort("localhost",
Protocol.DEFAULT_SENTINEL_PORT);
sentinelHostAndPortList.add(defaulthnp7);
HostAndPort defaulthnp8 = new HostAndPort("localhost",
Protocol.DEFAULT_SENTINEL_PORT + 1);
sentinelHostAndPortList.add(defaulthnp8);
HostAndPort defaulthnp9 = new HostAndPort("localhost",
Protocol.DEFAULT_SENTINEL_PORT + 2);
sentinelHostAndPortList.add(defaulthnp9);
clusterHostAndPortList.add(new HostAndPort("localhost", 7379)); clusterHostAndPortList.add(new HostAndPort("localhost", 7379));
clusterHostAndPortList.add(new HostAndPort("localhost", 7380)); clusterHostAndPortList.add(new HostAndPort("localhost", 7380));

View File

@@ -1,5 +1,6 @@
package redis.clients.jedis.tests; package redis.clients.jedis.tests;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -9,9 +10,15 @@ import org.junit.Test;
import redis.clients.jedis.HostAndPort; import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis; import redis.clients.jedis.Jedis;
import redis.clients.jedis.exceptions.JedisDataException;
import redis.clients.jedis.tests.utils.JedisSentinelTestUtil;
public class JedisSentinelTest extends JedisTestBase { public class JedisSentinelTest extends JedisTestBase {
private static final String MASTER_NAME = "mymaster"; private static final String MASTER_NAME = "mymaster";
private static final String MONITOR_MASTER_NAME = "mymastermonitor";
private static final String REMOVE_MASTER_NAME = "mymasterremove";
private static final String FAILOVER_MASTER_NAME = "mymasterfailover";
private static final String MASTER_IP = "127.0.0.1";
protected static HostAndPort master = HostAndPortUtil.getRedisServers() protected static HostAndPort master = HostAndPortUtil.getRedisServers()
.get(0); .get(0);
@@ -20,13 +27,13 @@ public class JedisSentinelTest extends JedisTestBase {
protected static HostAndPort sentinel = HostAndPortUtil protected static HostAndPort sentinel = HostAndPortUtil
.getSentinelServers().get(0); .getSentinelServers().get(0);
protected static Jedis masterJedis; protected static HostAndPort sentinelForFailover = HostAndPortUtil
protected static Jedis slaveJedis; .getSentinelServers().get(3);
protected static Jedis sentinelJedis; protected static HostAndPort masterForFailover = HostAndPortUtil
.getRedisServers().get(6);
@Before @Before
public void setup() throws InterruptedException { public void setup() throws InterruptedException {
} }
@After @After
@@ -36,30 +43,139 @@ public class JedisSentinelTest extends JedisTestBase {
// to restore it (demote) // to restore it (demote)
// so, promote(slaveof) slave to master has no effect, not same to old // so, promote(slaveof) slave to master has no effect, not same to old
// Sentinel's behavior // Sentinel's behavior
ensureRemoved(MONITOR_MASTER_NAME);
ensureRemoved(REMOVE_MASTER_NAME);
} }
@Test @Test
public void sentinel() { public void sentinel() {
Jedis j = new Jedis(sentinel.getHost(), sentinel.getPort()); Jedis j = new Jedis(sentinel.getHost(), sentinel.getPort());
List<Map<String, String>> masters = j.sentinelMasters(); List<Map<String, String>> masters = j.sentinelMasters();
final String masterName = masters.get(0).get("name");
assertEquals(MASTER_NAME, masterName); boolean inMasters = false;
for (Map<String, String> master : masters)
if (MASTER_NAME.equals(master.get("name")))
inMasters = true;
assertTrue(inMasters);
List<String> masterHostAndPort = j List<String> masterHostAndPort = j
.sentinelGetMasterAddrByName(masterName); .sentinelGetMasterAddrByName(MASTER_NAME);
HostAndPort masterFromSentinel = new HostAndPort( HostAndPort masterFromSentinel = new HostAndPort(
masterHostAndPort.get(0), Integer.parseInt(masterHostAndPort masterHostAndPort.get(0), Integer.parseInt(masterHostAndPort
.get(1))); .get(1)));
assertEquals(master, masterFromSentinel); assertEquals(master, masterFromSentinel);
List<Map<String, String>> slaves = j.sentinelSlaves(masterName); List<Map<String, String>> slaves = j.sentinelSlaves(MASTER_NAME);
assertTrue(slaves.size() > 0); assertTrue(slaves.size() > 0);
assertEquals(master.getPort(), assertEquals(master.getPort(),
Integer.parseInt(slaves.get(0).get("master-port"))); Integer.parseInt(slaves.get(0).get("master-port")));
// DO NOT RE-RUN TEST TOO FAST, RESET TAKES SOME TIME TO... RESET // DO NOT RE-RUN TEST TOO FAST, RESET TAKES SOME TIME TO... RESET
assertEquals(Long.valueOf(1), j.sentinelReset(masterName)); assertEquals(Long.valueOf(1), j.sentinelReset(MASTER_NAME));
assertEquals(Long.valueOf(0), j.sentinelReset("woof" + masterName)); assertEquals(Long.valueOf(0), j.sentinelReset("woof" + MASTER_NAME));
}
@Test
public void sentinelFailover() throws InterruptedException {
Jedis j = new Jedis(sentinelForFailover.getHost(),
sentinelForFailover.getPort());
HostAndPort currentMaster = new HostAndPort(
masterForFailover.getHost(), masterForFailover.getPort());
List<String> masterHostAndPort = j
.sentinelGetMasterAddrByName(FAILOVER_MASTER_NAME);
String result = j.sentinelFailover(FAILOVER_MASTER_NAME);
assertEquals("OK", result);
JedisSentinelTestUtil.waitForNewPromotedMaster(sentinelForFailover,
FAILOVER_MASTER_NAME, currentMaster);
masterHostAndPort = j.sentinelGetMasterAddrByName(FAILOVER_MASTER_NAME);
HostAndPort newMaster = new HostAndPort(masterHostAndPort.get(0),
Integer.parseInt(masterHostAndPort.get(1)));
assertNotEquals(newMaster, currentMaster);
}
@Test
public void sentinelMonitor() {
Jedis j = new Jedis(sentinel.getHost(), sentinel.getPort());
// monitor new master
String result = j.sentinelMonitor(MONITOR_MASTER_NAME, MASTER_IP,
master.getPort(), 1);
assertEquals("OK", result);
// already monitored
try {
j.sentinelMonitor(MONITOR_MASTER_NAME, MASTER_IP, master.getPort(),
1);
fail();
} catch (JedisDataException e) {
// pass
}
}
@Test
public void sentinelRemove() {
Jedis j = new Jedis(sentinel.getHost(), sentinel.getPort());
ensureMonitored(sentinel, REMOVE_MASTER_NAME, MASTER_IP,
master.getPort(), 1);
String result = j.sentinelRemove(REMOVE_MASTER_NAME);
assertEquals("OK", result);
// not exist
try {
result = j.sentinelRemove(REMOVE_MASTER_NAME);
assertNotEquals("OK", result);
fail();
} catch (JedisDataException e) {
// pass
}
}
@Test
public void sentinelSet() {
Jedis j = new Jedis(sentinel.getHost(), sentinel.getPort());
Map<String, String> parameterMap = new HashMap<String, String>();
parameterMap.put("down-after-milliseconds", String.valueOf(1234));
parameterMap.put("parallel-syncs", String.valueOf(3));
parameterMap.put("quorum", String.valueOf(2));
j.sentinelSet(MASTER_NAME, parameterMap);
List<Map<String, String>> masters = j.sentinelMasters();
for (Map<String, String> master : masters) {
if (master.get("name").equals(MASTER_NAME)) {
assertEquals(1234,
Integer.parseInt(master.get("down-after-milliseconds")));
assertEquals(3, Integer.parseInt(master.get("parallel-syncs")));
assertEquals(2, Integer.parseInt(master.get("quorum")));
}
}
parameterMap.put("quorum", String.valueOf(1));
j.sentinelSet(MASTER_NAME, parameterMap);
}
private void ensureMonitored(HostAndPort sentinel, String masterName,
String ip, int port, int quorum) {
Jedis j = new Jedis(sentinel.getHost(), sentinel.getPort());
try {
j.sentinelMonitor(masterName, ip, port, quorum);
} catch (JedisDataException e) {
}
}
private void ensureRemoved(String masterName) {
Jedis j = new Jedis(sentinel.getHost(), sentinel.getPort());
try {
j.sentinelRemove(masterName);
} catch (JedisDataException e) {
}
} }
} }

View File

@@ -46,8 +46,11 @@ public class JedisSentinelTestUtil {
List<String> sentinelMasterInfos = sentinelJedis List<String> sentinelMasterInfos = sentinelJedis
.sentinelGetMasterAddrByName(masterName); .sentinelGetMasterAddrByName(masterName);
if (sentinelMasterInfos == null) if (sentinelMasterInfos == null) {
System.out
.println("Cannot retrieve Sentinel's master address info, sleep...");
continue; continue;
}
newMaster = new HostAndPort(sentinelMasterInfos.get(0), newMaster = new HostAndPort(sentinelMasterInfos.get(0),
Integer.parseInt(sentinelMasterInfos.get(1))); Integer.parseInt(sentinelMasterInfos.get(1)));