http://www.cnblogs.com/zgx/archive/2011/08/10/2134097.html
使用xmemcached的时候,
可以参考这里,http://code.google.com/p/xmemcached/wiki/memcached_distributed,使用xmemcached提供的分布式算法。
如果使用普通的取余算法,那么在增加更多节点的时候,会使得命中率迅速下降。但是当使用一致性哈希算法的时候,会很大程度的减少重新填充缓存的部分。进而使得命中率不至于下降太多。
使用一致性哈希的时候,看代码:
package comz;
import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import java.util.concurrent.TimeoutException;
import net.rubyeye.xmemcached.MemcachedClient;
import net.rubyeye.xmemcached.MemcachedClientBuilder;
import net.rubyeye.xmemcached.XMemcachedClient;
import net.rubyeye.xmemcached.XMemcachedClientBuilder;
import net.rubyeye.xmemcached.exception.MemcachedException;
import net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator;
import net.rubyeye.xmemcached.utils.AddrUtil;
/**
* 测试节点的添加和删除对缓存命中率的影响
*
* 从一篇英文文章中做单词频率统计,以单词为key,统计的次数为value,存储在10个节点上 添加两个节点后测试,查看各个节点的命中率变化。
*
* @author Administrator
*
*/
public class CacheHitRateTest {
public static void main(String[] args) throws Exception {
String ip = "127.0.0.1";
// 替换这个HashAlgorithm进行测试
// HashAlgorithm hashAlg = HashAlgorithm.NATIVE_HASH;
// XMemcachedClient client = new XMemcachedClient(
// new KetamaMemcachedSessionLocator(hashAlg));
MemcachedClientBuilder builder = new XMemcachedClientBuilder();
builder.setSessionLocator(new KetamaMemcachedSessionLocator());
MemcachedClient mc = builder.build();
mc.addServer(ip, 11211);
mc.addServer(ip, 11212);
mc.addServer(ip, 11213);
mc.addServer(ip, 11214);
mc.addServer(ip, 11215);
mc.addServer(ip, 11216);
mc.addServer(ip, 11217);
mc.addServer(ip, 11218);
mc.addServer(ip, 11219);
// 初始化数据
Set<String> keys = init(mc);
// testHashPerfromance(keys, HashAlgorithm.CRC32_HASH);
// testHashPerfromance(keys, HashAlgorithm.KETAMA_HASH);
// testHashPerfromance(keys, HashAlgorithm.FNV1_32_HASH);
// testHashPerfromance(keys, HashAlgorithm.NATIVE_HASH);
// testHashPerfromance(keys, HashAlgorithm.MYSQL_HASH);
// 此时应该是100%
printHitRate(mc, keys);
// 添加两个节点后,查看命中率
mc.addServer(ip, 11220);
printHitRate(mc, keys);
mc.shutdown();
}
// private static void testHashPerfromance(Set<String> keys,
// HashAlgorithm hashAlg) {
// long start = System.currentTimeMillis();
// for (int i = 0; i < 1000; i++) {
// for (String key : keys) {
// hashAlg.hash(key);
// }
// }
// System.out.println(hashAlg.name() + ":"
// + (System.currentTimeMillis() - start));
// }
private static void printHitRate(MemcachedClient client, Set<String> keys)
throws TimeoutException, InterruptedException, MemcachedException {
int total = 0;
int hits = 0;
for (String key : keys) {
total++;
if (client.get(key) != null)
hits++;
}
System.out.println("hit rate=" + (double) hits / total);
}
/**
* 初始化,统计单词并存储到10个节点,单词统计并不严谨,只是为了让key比较随机
*
* @param client
* @throws Exception
*/
public static Set<String> init(MemcachedClient client) throws Exception {
// BufferedReader reader = new BufferedReader(
// ResourcesUtils.getResourceAsReader("a.txt"));
File file = new File("a.txt");
Scanner cin = new Scanner(file);
String line = null;
Map<String, Integer> counters = new HashMap<String, Integer>();
int i = 0;
while (i++ != 20) {
line = cin.nextLine();
String[] words = line.split("[\\s,.,\"'?\t]+");
for (String word : words) {
word = word.trim();
if (word.length() == 0)
continue;
if (counters.containsKey(word)) {
counters.put(word, counters.get(word).intValue() + 1);
} else {
counters.put(word, 1);
}
}
}
System.out.println("words number=" + counters.keySet().size());
Iterator<Map.Entry<String, Integer>> it = counters.entrySet()
.iterator();
while (it.hasNext()) {
Map.Entry<String, Integer> entry = it.next();
if (!client.set(entry.getKey(), 0, entry.getValue()))
System.err.println("put error");
}
System.out.println("initialize successfully!");
cin.close();
return counters.keySet();
}
}
输出:
words number=196
initialize successfully!
hit rate=1.0
hit rate=0.8877551020408163
可以看到,命中率在添加一个节点之后,仍然会达到88%以上。如果是按照取余的算法,那么可能就只有10-20%多了。
------------------------------------------------------
上面的这段代码是借鉴别人的 。在基础上改了一点地方,就是构建一致性哈希的那三句代码。
别人本来的意思是,测试哈希性能的。就是上面被注释掉的部分。
哈希性能,mysql_hash据说是从mysql中取出的哈希源码。性能最好的是native_hash。默认是KETAMA_HASH,它维持了一个最佳平衡,在增加两个节点后还能访问到绝大部分单词,并且数据分布在各个节点上的数目也相对平均,难怪作为默认散列算法。