Memcached一致性哈希測(cè)試
1. 準(zhǔn)備
- 兩臺(tái)已經(jīng)裝好memached的機(jī)器,假如ip分別為192.168.1.2和192.168.1.3
- spy memcached 客戶端jar包
- 啟動(dòng)memached
2. 編寫(xiě)Java測(cè)試程序
- 測(cè)試哈希一致性的寫(xiě)入
@Test
public void testSetWithConsistentHashing() throws IOException, InterruptedException {
ConnectionFactory connFactory = new ConnectionFactoryBuilder().setLocatorType(Locator.CONSISTENT).build();
MemcachedClient clusterClient = new MemcachedClient(
connFactory,
AddrUtil.getAddresses("192.168.6.201:11211 192.168.6.205:11211"));
MemcachedClient clientOne = new MemcachedClient(AddrUtil.getAddresses("192.168.6.201:11211"));
MemcachedClient clientTwo = new MemcachedClient(AddrUtil.getAddresses("192.168.6.205:11211"));
// 放1000個(gè)
for (int i = 0; i < 1000; i++) {
clusterClient.set("test" + i, 300, "test" + i);
}
while (true) {
System.out.println("===================== in one =================================");
// 從one中獲取,看是否存在,存在的key
int oneCount = 0;
for (int i = 0; i < 1000; i++) {
Object value = clientOne.get("test" + i);
if (value != null) {
oneCount++;
System.out.println(value);
}
}
Assert.assertTrue(oneCount > 0);
Thread.sleep(3 * 1000);
System.out.println("======================= in two ===============================");
// 從one中獲取,看是否存在,存在的key
int twoCount = 0;
for (int i = 0; i < 1000; i++) {
Object value = clientTwo.get("test" + i);
if (value != null) {
twoCount++;
System.out.println(value);
}
}
Assert.assertTrue(twoCount > 0);
}
}
- 改造程序一,測(cè)試寫(xiě)入和讀取過(guò)程中啟動(dòng)或者停掉加入的節(jié)點(diǎn)機(jī)器
@Test
public void testGetValueWithConsistentHashing() throws IOException, InterruptedException {
ConnectionFactory connFactory = new ConnectionFactoryBuilder().setLocatorType(Locator.CONSISTENT).build();
MemcachedClient clusterClient = new MemcachedClient(
connFactory,
AddrUtil.getAddresses("192.168.6.201:11211 192.168.6.205:11211"));
MemcachedClient clientOne = new MemcachedClient(AddrUtil.getAddresses("192.168.6.201:11211"));
MemcachedClient clientTwo = new MemcachedClient(AddrUtil.getAddresses("192.168.6.205:11211"));
while (true) {
try {
// 存數(shù)據(jù)
for (int i = 0; i < 1000; i++) {
clusterClient.set("test" + i, 300, "test" + i);
}
// 校驗(yàn)one中是否有數(shù)據(jù)
System.out.println("===================== in one =================================");
int oneCount = 0;
for (int i = 0; i < 1000; i++) {
Object value = clientOne.get("test" + i);
if (value != null) {
oneCount++;
if (oneCount > 3) {
continue;
}
System.out.println(value);
}
}
System.out.println("one count: " + oneCount);
// //校驗(yàn)two中是否有數(shù)據(jù)
System.out.println("===================== in two =================================");
int twoCount = 0;
for (int i = 0; i < 1000; i++) {
Object value = clientTwo.get("test" + i);
if (value != null) {
twoCount++;
if (twoCount > 3) {
continue;
}
System.out.println(value);
}
}
System.out.println("two count: " + twoCount);
Thread.sleep(3 * 1000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
3. 測(cè)試
同時(shí)開(kāi)啟兩臺(tái)memcached,然后執(zhí)行第一個(gè)測(cè)試程序,結(jié)果執(zhí)行通過(guò),發(fā)現(xiàn)兩臺(tái)機(jī)器的memcached中都有要設(shè)置的數(shù)據(jù),而且是不同的.
同時(shí)開(kāi)啟兩臺(tái)memcached,然后執(zhí)行第二個(gè)測(cè)試程序,開(kāi)始執(zhí)行征程.然后停掉其中一臺(tái),沒(méi)多長(zhǎng)時(shí)間,測(cè)試程序拋出異常
2014-08-29 19:27:57.752 INFO net.spy.memcached.MemcachedConnection: Reconnecting {QA sa=/192.168.1.2:11211, #Rops=0, #Wops=23, #iq=0, topRop=null, topWop=net.spy.memcached.protocol.ascii.StoreOperationImpl@567a380b, toWrite=0, interested=0}
2014-08-29 19:27:57.753 INFO net.spy.memcached.MemcachedConnection: Connection state changed for sun.nio.ch.SelectionKeyImpl@5e94fd79
2014-08-29 19:27:57.754 INFO net.spy.memcached.MemcachedConnection: Reconnecting due to failure to connect to {QA sa=/192.168.1.2:11211, #Rops=0, #Wops=23, #iq=0, topRop=null, topWop=net.spy.memcached.protocol.ascii.StoreOperationImpl@567a380b, toWrite=0, interested=0}
java.net.ConnectException: 拒絕連接
at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method)
at sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:712)
at net.spy.memcached.MemcachedConnection.handleIO(MemcachedConnection.java:313)
at net.spy.memcached.MemcachedConnection.handleIO(MemcachedConnection.java:199)
at net.spy.memcached.MemcachedClient.run(MemcachedClient.java:1622)
2014-08-29 19:27:57.754 WARN net.spy.memcached.MemcachedConnection: Closing, and reopening {QA sa=/192.168.1.2:11211, #Rops=0, #Wops=23, #iq=0, topRop=null, topWop=net.spy.memcached.protocol.ascii.StoreOperationImpl@567a380b, toWrite=0, interested=0}, attempt 1.
然后就隔一段時(shí)間拋出一次異常,且每次拋出異常的時(shí)間是不斷推遲的,具體推遲到多久這個(gè)尚未測(cè)試.同時(shí)所要寫(xiě)入的1000個(gè)值全部寫(xiě)入到了另一臺(tái)機(jī)器中.
- 開(kāi)啟停掉的那臺(tái)機(jī)器,客戶端自動(dòng)重新鏈接了,同時(shí)恢復(fù)了對(duì)剛剛恢復(fù)的機(jī)器的寫(xiě)入和讀取
2014-08-29 20:03:06.157 WARN net.spy.memcached.MemcachedConnection: Could not redistribute to another node, retrying primary node for test0.
2014-08-29 20:03:06.234 INFO net.spy.memcached.MemcachedConnection: Reconnecting {QA sa=/192.168.1.2:11211, #Rops=0, #Wops=22, #iq=0, topRop=null, topWop=net.spy.memcached.protocol.ascii.StoreOperationImpl@6d2cb32a, toWrite=0, interested=0}
2014-08-29 20:03:06.235 INFO net.spy.memcached.MemcachedConnection: Connection state changed for sun.nio.ch.SelectionKeyImpl@51906e2
2014-08-29 20:03:06.476 INFO net.spy.memcached.MemcachedConnection: Reconnecting {QA sa=/192.168.1.2:11211, #Rops=0, #Wops=3, #iq=0, topRop=null, topWop=net.spy.memcached.protocol.ascii.GetOperationImpl@59b3d57, toWrite=0, interested=0}
2014-08-29 20:03:06.477 INFO net.spy.memcached.MemcachedConnection: Connection state changed for sun.nio.ch.SelectionKeyImpl@399931f9
4. 結(jié)果
spymemcached 客戶端對(duì)memcached哈希一致性比較i理想,在有多臺(tái)memcached的情況下,掛掉一臺(tái),不會(huì)造成全部損失,但會(huì)失去這臺(tái)機(jī)器的緩存,導(dǎo)致這部分?jǐn)?shù)據(jù)可能會(huì)落在數(shù)據(jù)庫(kù)上,相比單節(jié)點(diǎn)掛掉,情況要理想的多.
5. 探索
如果支持主備方案,那么情況會(huì)更加理想.