Memcached 集群,客户端自动Hash到不同服务器的实现

首先分析一下Java client 启动时的部分代码

Memcached 支持直接设置多个servers属性 来实现多个memcahced均衡,对应还有一个属性是weights,字面意思就是权重,分析了一下代码,和我想的是一样的

启动memcached的代码通常是这样的

Java代码
  1. SockIOPoolpool=SockIOPool.getInstance(poolname);
  2. pool.setServers(servers);
  3. pool.setWeights(weights);
  4. pool.setInitConn(initConn);
  5. pool.setMinConn(minConn);
  6. pool.setMaxConn(maxConn);
  7. pool.setMaxIdle(maxIdle);
  8. pool.setMaxBusyTime(maxBusyTime);
  9. pool.setMaintSleep(maintSleep);
  10. pool.setSocketTO(socketTO);
  11. pool.setSocketConnectTO(socketConnectTO);
  12. pool.setNagle(nagle);
  13. pool.setHashingAlg(SockIOPool.NEW_COMPAT_HASH);
  14. pool.initialize();
  15. MemCachedClientclient=newMemCachedClient(poolname);



servers 和 weights 都是一个数组,就是说可以同时设置多个server

然后看一下 pool.initialize() 做了什么

Java代码
  1. availPool=newHashMap<String,Map<SockIO,Long>>(servers.length*initConn);
  2. busyPool=newHashMap<String,Map<SockIO,Long>>(servers.length*initConn);
  3. deadPool=newIdentityHashMap<SockIO,Integer>();
  4. hostDeadDur=newHashMap<String,Long>();
  5. hostDead=newHashMap<String,Date>();
  6. maxCreate=(poolMultiplier>minConn)?minConn:minConn/poolMultiplier;//onlycreateuptomaxCreateconnectionsatonce
  7. if(log.isDebugEnabled()){
  8. log.debug("++++initializingpoolwithfollowingsettings:");
  9. log.debug("++++initialsize:"+initConn);
  10. log.debug("++++minspare:"+minConn);
  11. log.debug("++++maxspare:"+maxConn);
  12. }
  13. //ifserversisnotset,oritempty,then
  14. //throwaruntimeexception
  15. if(servers==null||servers.length<=0){
  16. log.error("++++tryingtoinitializewithnoservers");
  17. thrownewIllegalStateException("++++tryingtoinitializewithnoservers");
  18. }
  19. //initalizeourinternalhashingstructures
  20. if(this.hashingAlg==CONSISTENT_HASH)
  21. populateConsistentBuckets();
  22. else
  23. populateBuckets();


看到这里就是开辟一些连接池的空间,然后调用了根据我们选择的hash 算法 执行populateBuckets();或者populateConsistentBuckets();

hash算法共有4种

Java代码
  1. //nativeString.hashCode();
  2. publicstaticfinalintNATIVE_HASH=0;
  3. //originalcompatibilityhashingalgorithm(workswithotherclients)
  4. publicstaticfinalintOLD_COMPAT_HASH=1;
  5. //newCRC32basedcompatibilityhashingalgorithm(workswithotherclients)
  6. publicstaticfinalintNEW_COMPAT_HASH=2;
  7. //MD5Based--Stopsthrashingwhenaserveraddedorremoved
  8. publicstaticfinalintCONSISTENT_HASH=3;



我们通常用的是 NEW_COMPAT_HASH,这个保证可以wokrs with other clients

所以看一下populateBuckets()做了什么

Java代码
  1. this.buckets=newArrayList<String>();
  2. for(inti=0;i<servers.length;i++){
  3. if(this.weights!=null&&this.weights.length>i){
  4. for(intk=0;k<this.weights[i].intValue();k++){
  5. this.buckets.add(servers[i]);
  6. if(log.isDebugEnabled())
  7. log.debug("++++added"+servers[i]+"toserverbucket");
  8. }
  9. }
  10. else{
  11. this.buckets.add(servers[i]);
  12. }
  13. //createinitialconnections
  14. for(intj=0;j<initConn;j++){
  15. SockIOsocket=createSocket(servers[i]);
  16. if(socket==null){
  17. break;
  18. }
  19. addSocketToPool(availPool,servers[i],socket);
  20. }
  21. }



假如我们设置的servers是 192.168.0.1:44444和192.168.0.2:22222
然后我们设置了weights是 5和3 那么
buckets list的值最终会是
[
192.168.0.1:44444,
192.168.0.1:44444,
192.168.0.1:44444,
192.168.0.1:44444,
192.168.0.1:44444,
192.168.0.2:22222,
192.168.0.2:22222.
192.168.0.2:22222.
]
然后就开始根据initCon初始连接数按servers分别创建socket
那么究竟这个buckets做什么用呢?

在我们使用set存放对象时会调用

Java代码
  1. SockIOPool.SockIOsock=pool.getSock(key,hashCode);



看一看pool.getSock的代码

Java代码
  1. //getinitialbucket
  2. longbucket=getBucket(key,hashCode);
  3. Stringserver=(this.hashingAlg==CONSISTENT_HASH)
  4. ?consistentBuckets.get(bucket)
  5. :buckets.get((int)bucket);



其中有段代码是这样的,看看getBucket

Java代码
  1. privatelonggetBucket(Stringkey,IntegerhashCode){
  2. longhc=getHash(key,hashCode);
  3. if(this.hashingAlg==CONSISTENT_HASH){
  4. returnfindPointFor(hc);
  5. }
  6. else{
  7. longbucket=hc%buckets.size();
  8. if(bucket<0)bucket*=-1;
  9. returnbucket;
  10. }
  11. }



先不管key和hashCode,我们看到首先算出一个hc值后会直接做hc%buckets.size()实际上就是根据buckets的数量散列,最终值一定是buckets.size()范围里的一个值
然后最终server值就根据buckets.get( (int)bucket )得到,那么假如我们得到bucket是3,则参照上面buckets 里的值,得到 list.get(3)=192.168.0.1:44444 所以会根据weight设置的值的不同得到不同的server ,如果 weights设置10:1 那buckets里就是10个相同的server和另一个不同的,将来散列得到的server很大可能性是servers里设置的第一个server。

 

原文地址:http://bachmozart.javaeye.com/blog/211836

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值