memcachedçæ»ç»ååå¸å¼ä¸è´æ§hash
å½åå¾å¤å¤§åçwebç³»ç»ä¸ºäºåè½»æ°æ®åºæå¡å¨è´è½½ï¼ä¼éç¨memchachedä½ä¸ºç¼åç³»ç»ä»¥æé«ååºé度ã
ç®å½ï¼ ï¼
http://houdunwang.com/lesson.htmlï¼
memchachedç®ä»
hash
å模
ä¸è´æ§hash
èæèç¹
æºç 解æ
åèèµæ
1. memchachedç®ä»
memcachedæ¯ä¸ä¸ªå¼æºçé«æ§è½åå¸å¼å
å对象ç¼åç³»ç»ã
å
¶å®ææ³è¿æ¯æ¯è¾ç®åçï¼å®ç°å
æ¬server端ï¼memcachedå¼æºé¡¹ç®ä¸è¬åªåæserver端ï¼åclient端两é¨å:
server端æ¬è´¨æ¯ä¸ä¸ªin-memory key-value storeï¼éè¿å¨å
åä¸ç»´æ¤ä¸ä¸ªå¤§çhashmapç¨æ¥åå¨å°åçä»»ææ°æ®ï¼å¯¹å¤éè¿ç»ä¸çç®åæ¥å£ï¼memcached protocolï¼æ¥æä¾æä½ã
client端æ¯ä¸ä¸ªlibraryï¼è´è´£å¤çmemcached protocolçç½ç»éä¿¡ç»èï¼ä¸memcached serveréä¿¡ï¼é对åç§è¯è¨çä¸åå®ç°åè£
äºæç¨çAPIå®ç°äºä¸ä¸åè¯è¨å¹³å°çéæã
webç³»ç»åéè¿clientåºæ¥ä½¿ç¨memcachedè¿è¡å¯¹è±¡ç¼åã
2. hash
memcachedçåå¸å¼ä¸»è¦ä½ç°å¨client端ï¼å¯¹äºserver端ï¼ä»
ä»
æ¯é¨ç½²å¤ä¸ªmemcached serverç»æé群ï¼æ¯ä¸ªserverç¬èªç»´æ¤èªå·±çæ°æ®ï¼äºç¸ä¹é´æ²¡æä»»ä½éä¿¡ï¼ï¼éè¿daemonçå¬ç«¯å£çå¾
client端ç请æ±ã
èå¨client端ï¼éè¿ä¸è´çhashç®æ³ï¼å°è¦åå¨çæ°æ®åå¸å°æ个ç¹å®çserverä¸è¿è¡åå¨ï¼åç»è¯»åæ¥è¯¢ä½¿ç¨åæ ·çhashç®æ³å³å¯å®ä½ã
client端å¯ä»¥éç¨åç§hashç®æ³æ¥å®ä½serverï¼
å模
æç®åçhashç®æ³
targetServer = serverList[hash(key) % serverList.size]
ç´æ¥ç¨keyçhashå¼ï¼è®¡ç®keyçhashå¼çæ¹æ³å¯ä»¥èªç±éæ©ï¼æ¯å¦ç®æ³CRC32ãMD5,çè³æ¬å°hashç³»ç»ï¼å¦javaçhashcodeï¼æ¨¡ä¸serveræ»æ°æ¥å®ä½ç®æ serverãè¿ç§ç®æ³ä¸ä»
ç®åï¼èä¸å
·æä¸éçéæºåå¸ç¹æ§ã
ä½æ¯é®é¢ä¹å¾ææ¾ï¼serveræ»æ°ä¸è½è½»æååãå 为å¦æå¢å /åå°memcached serverçæ°éï¼å¯¹åå
åå¨çæækeyçåç»æ¥è¯¢é½å°å®ä½å°å«çserverä¸ï¼å¯¼è´ææçcacheé½ä¸è½è¢«å½ä¸è失æã
ä¸è´æ§hash
为äºè§£å³è¿ä¸ªé®é¢ï¼éè¦éç¨ä¸è´æ§hashç®æ³ï¼consistent hashï¼
ç¸å¯¹äºå模çç®æ³ï¼ä¸è´æ§hashç®æ³é¤äºè®¡ç®keyçhashå¼å¤ï¼è¿ä¼è®¡ç®æ¯ä¸ªserver对åºçhashå¼ï¼ç¶åå°è¿äºhashå¼æ å°å°ä¸ä¸ªæéçå¼åä¸ï¼æ¯å¦0~2^32ï¼ãéè¿å¯»æ¾hashå¼å¤§äºhash(key)çæå°serverä½ä¸ºåå¨è¯¥keyæ°æ®çç®æ serverãå¦ææ¾ä¸å°ï¼åç´æ¥æå
·ææå°hashå¼çserverä½ä¸ºç®æ serverã
为äºæ¹ä¾¿ç解ï¼å¯ä»¥æè¿ä¸ªæéå¼åç解æä¸ä¸ªç¯ï¼å¼é¡ºæ¶ééå¢ã
å¦ä¸å¾æ示ï¼é群ä¸ä¸å
±æ5个memcached serverï¼å·²éè¿serverçhashå¼åå¸å°ç¯ä¸ã
å¦æç°å¨æä¸ä¸ªåå
¥cacheç请æ±ï¼é¦å
计ç®x=hash(key)ï¼æ å°å°ç¯ä¸ï¼ç¶åä»x顺æ¶éæ¥æ¾ï¼ææ¾å°ç第ä¸ä¸ªserverä½ä¸ºç®æ serveræ¥åå¨cacheï¼å¦æè¶
è¿äº2^32ä»ç¶æ¾ä¸å°ï¼åå½ä¸ç¬¬ä¸ä¸ªserverãæ¯å¦xçå¼ä»äºA~Bä¹é´ï¼é£ä¹å½ä¸çserverèç¹åºè¯¥æ¯Bèç¹
å¯ä»¥çå°ï¼éè¿è¿ç§ç®æ³ï¼å¯¹äºåä¸ä¸ªkeyï¼åå¨ååç»çæ¥è¯¢é½ä¼å®ä½å°åä¸ä¸ªmemcached serverä¸ã
é£ä¹å®æ¯æä¹è§£å³å¢/å server导è´çcacheä¸è½å½ä¸çé®é¢å¢ï¼
å设ï¼ç°å¨å¢å ä¸ä¸ªserver Fï¼å¦ä¸å¾
æ¤æ¶ï¼cacheä¸è½å½ä¸çé®é¢ä»ç¶åå¨ï¼ä½æ¯åªåå¨äºB~Fä¹é´çä½ç½®ï¼ç±CåæäºFï¼ï¼å
¶ä»ä½ç½®ï¼å
æ¬F~Cï¼çcacheçå½ä¸ä¸åå½±åï¼å é¤serverçæ
åµç±»ä¼¼ï¼ã尽管ä»ç¶æcacheä¸è½å½ä¸çåå¨ï¼ä½æ¯ç¸å¯¹äºå模çæ¹å¼å·²ç»å¤§å¹
åå°äºä¸è½å½ä¸çcacheæ°éã
èæèç¹
ä½æ¯ï¼è¿ç§ç®æ³ç¸å¯¹äºå模æ¹å¼ä¹æä¸ä¸ªç¼ºé·ï¼å½serveræ°éå¾å°æ¶ï¼å¾å¯è½ä»ä»¬å¨ç¯ä¸çåå¸ä¸æ¯ç¹å«ååï¼è¿è导è´cacheä¸è½åååå¸å°ææçserverä¸ã
å¦å¾ï¼ä¸å
±æ3å°server â 1ï¼2ï¼4ãå½ä¸4çå çè¿è¿é«äº1å2ã
为解å³è¿ä¸ªé®é¢ï¼éè¦ä½¿ç¨èæèç¹çææ³ï¼ä¸ºæ¯ä¸ªç©çèç¹ï¼serverï¼å¨ç¯ä¸åé
100ï½200个ç¹ï¼è¿æ ·ç¯ä¸çèç¹è¾å¤ï¼å°±è½æå¶åå¸ä¸ååã
å½ä¸ºcacheå®ä½ç®æ serveræ¶ï¼å¦æå®ä½å°èæèç¹ä¸ï¼å°±è¡¨ç¤ºcacheçæ£çåå¨ä½ç½®æ¯å¨è¯¥èæèç¹ä»£è¡¨çå®é
ç©çserverä¸ã
å¦å¤ï¼å¦ææ¯ä¸ªå®é
serverçè´è½½è½åä¸åï¼å¯ä»¥èµäºä¸åçæéï¼æ ¹æ®æéåé
ä¸åæ°éçèæèç¹ã
// éç¨æåºmapæ¥æ¨¡æç¯
this.consistentBuckets = new TreeMap();
MessageDigest md5 = MD5.get();//ç¨MD5æ¥è®¡ç®keyåserverçhashå¼
// 计ç®æ»æé
if ( this.totalWeight for ( int i = 0; i < this.weights.length; i++ )
this.totalWeight += ( this.weights[i] == null ) ? 1 : this.weights[i];
} else if ( this.weights == null ) {
this.totalWeight = this.servers.length;
}
// 为æ¯ä¸ªserveråé
èæèç¹
for ( int i = 0; i < servers.length; i++ ) {
// 计ç®å½åserverçæé
int thisWeight = 1;
if ( this.weights != null && this.weights[i] != null )
thisWeight = this.weights[i];
// factorç¨æ¥æ§å¶æ¯ä¸ªserveråé
çèæèç¹æ°é
// æéé½ç¸åæ¶ï¼factor=40
// æéä¸åæ¶ï¼factor=40*serveræ»æ°*该serveræéæå çç¾åæ¯
// æ»çæ¥è¯´ï¼æéè¶å¤§ï¼factorè¶å¤§ï¼å¯ä»¥åé
è¶å¤çèæèç¹
double factor = Math.floor( ((double)(40 * this.servers.length * thisWeight)) / (double)this.totalWeight );
for ( long j = 0; j < factor; j++ ) {
// æ¯ä¸ªserveræfactor个hashå¼
// 使ç¨serverçååæIPå ä¸ç¼å·æ¥è®¡ç®hashå¼
// æ¯å¦server - "172.45.155.25:11111"å°±æfactor个æ°æ®ç¨æ¥çæhashå¼ï¼
// 172.45.155.25:11111-1, 172.45.155.25:11111-2, ..., 172.45.155.25:11111-factor
byte[] d = md5.digest( ( servers[i] + "-" + j ).getBytes() );
// æ¯ä¸ªhashå¼çæ4个èæèç¹
for ( int h = 0 ; h < 4; h++ ) {
Long k =
((long)(d[3+h*4]&0xFF) << 24)
| ((long)(d[2+h*4]&0xFF) << 16)
| ((long)(d[1+h*4]&0xFF) << 8 )
| ((long)(d[0+h*4]&0xFF));
// å¨ç¯ä¸ä¿åèç¹
consistentBuckets.put( k, servers[i] );
}
}
// æ¯ä¸ªserverä¸å
±åé
4*factor个èæèç¹
}
// éç¨æåºmapæ¥æ¨¡æç¯
this.consistentBuckets = new TreeMap();
MessageDigest md5 = MD5.get();//ç¨MD5æ¥è®¡ç®keyåserverçhashå¼
// 计ç®æ»æé
if ( this.totalWeight for ( int i = 0; i < this.weights.length; i++ )
this.totalWeight += ( this.weights[i] == null ) ? 1 : this.weights[i];
} else if ( this.weights == null ) {
this.totalWeight = this.servers.length;
}
// 为æ¯ä¸ªserveråé
èæèç¹
for ( int i = 0; i < servers.length; i++ ) {
// 计ç®å½åserverçæé
int thisWeight = 1;
if ( this.weights != null && this.weights[i] != null )
thisWeight = this.weights[i];
// factorç¨æ¥æ§å¶æ¯ä¸ªserveråé
çèæèç¹æ°é
// æéé½ç¸åæ¶ï¼factor=40
// æéä¸åæ¶ï¼factor=40*serveræ»æ°*该serveræéæå çç¾åæ¯
// æ»çæ¥è¯´ï¼æéè¶å¤§ï¼factorè¶å¤§ï¼å¯ä»¥åé
è¶å¤çèæèç¹
double factor = Math.floor( ((double)(40 * this.servers.length * thisWeight)) / (double)this.totalWeight );
for ( long j = 0; j < factor; j++ ) {
// æ¯ä¸ªserveræfactor个hashå¼
// 使ç¨serverçååæIPå ä¸ç¼å·æ¥è®¡ç®hashå¼
// æ¯å¦server - "172.45.155.25:11111"å°±æfactor个æ°æ®ç¨æ¥çæhashå¼ï¼
// 172.45.155.25:11111-1, 172.45.155.25:11111-2, ..., 172.45.155.25:11111-factor
byte[] d = md5.digest( ( servers[i] + "-" + j ).getBytes() );
// æ¯ä¸ªhashå¼çæ4个èæèç¹
for ( int h = 0 ; h < 4; h++ ) {
Long k =
((long)(d[3+h*4]&0xFF) << 24)
| ((long)(d[2+h*4]&0xFF) << 16)
| ((long)(d[1+h*4]&0xFF) << 8 )
| ((long)(d[0+h*4]&0xFF));
// å¨ç¯ä¸ä¿åèç¹
consistentBuckets.put( k, servers[i] );
}
}
// æ¯ä¸ªserverä¸å
±åé
4*factor个èæèç¹
}
// ç¨MD5æ¥è®¡ç®keyçhashå¼
MessageDigest md5 = MD5.get();
md5.reset();
md5.update( key.getBytes() );
byte[] bKey = md5.digest();
// åMD5å¼çä½32ä½ä½ä¸ºkeyçhashå¼
long hv = ((long)(bKey[3]&0xFF) << 24) | ((long)(bKey[2]&0xFF) << 16) | ((long)(bKey[1]&0xFF) << 8 ) | (long)(bKey[0]&0xFF);
// hvçtailMapç第ä¸ä¸ªèæèç¹å¯¹åºçå³æ¯ç®æ server
SortedMap tmap = this.consistentBuckets.tailMap( hv );
return ( tmap.isEmpty() ) ? this.consistentBuckets.firstKey() : tmap.firstKey();
æ´å¤é®é¢å°é®é¢æ±å©ä¸åºï¼
http://bbs.houdunwang.com/ï¼