一致性哈希算法 应用
互聯(lián)網(wǎng)創(chuàng)業(yè)中大部分人都是草根創(chuàng)業(yè),這個(gè)時(shí)候沒有強(qiáng)勁的服務(wù)器,也沒有錢去買很昂貴的海量數(shù)據(jù)庫。在這樣嚴(yán)峻的條件下,一批又一批的創(chuàng)業(yè)者從創(chuàng)業(yè)中獲得成 功,這個(gè)和當(dāng)前的開源技術(shù)、海量數(shù)據(jù)架構(gòu)有著必不可分的關(guān)系。比如我們使用mysql、nginx等開源軟件,通過架構(gòu)和低成本服務(wù)器也可以搭建千萬級(jí)用 戶訪問量的系統(tǒng)。新浪微博、淘寶網(wǎng)、騰訊等大型互聯(lián)網(wǎng)公司都使用了很多開源免費(fèi)系統(tǒng)搭建了他們的平臺(tái)。所以,用什么沒關(guān)系,只要能夠在合理的情況下采用合 理的解決方案。
那怎么搭建一個(gè)好的系統(tǒng)架構(gòu)呢?這個(gè)話題太大,這里主要說一下數(shù)據(jù)分流的方式。比如我們的數(shù)據(jù)庫服務(wù)器只能存儲(chǔ)200個(gè)數(shù)據(jù),突然要搞一個(gè)活動(dòng)預(yù)估達(dá)到600個(gè)數(shù)據(jù)。
可以采用兩種方式:橫向擴(kuò)展或者縱向擴(kuò)展。
縱向擴(kuò)展是升級(jí)服務(wù)器的硬件資源。但是隨著機(jī)器的性能配置越高,價(jià)格越高,這個(gè)代價(jià)對(duì)于一般的小公司是承擔(dān)不起的。
橫向擴(kuò)展是采用多個(gè)廉價(jià)的機(jī)器提供服務(wù)。這樣一個(gè)機(jī)器只能處理200個(gè)數(shù)據(jù)、3個(gè)機(jī)器就可以處理600個(gè)數(shù)據(jù)了,如果以后業(yè)務(wù)量增加還可以快速配置增加。在大多數(shù)情況都選擇橫向擴(kuò)展的方式。如下圖:
現(xiàn)在有個(gè)問題了,這600個(gè)數(shù)據(jù)如何路由到對(duì)應(yīng)的機(jī)器。需要考慮如果均衡分配,假設(shè)我們600個(gè)數(shù)據(jù)都是統(tǒng)一的自增id數(shù)據(jù),從1~600,分成3 堆可以采用 id mod 3的方式。其實(shí)在真實(shí)環(huán)境可能不是這種id是字符串。需要把字符串轉(zhuǎn)變?yōu)閔ashcode再進(jìn)行取模。
目前看起來是不是解決我們的問題了,所有數(shù)據(jù)都很好的分發(fā)并且沒有達(dá)到系統(tǒng)的負(fù)載。但如果我們的數(shù)據(jù)需要存儲(chǔ)、需要讀取就沒有這么容易了。業(yè)務(wù)增多 怎么辦,大家按照上面的橫向擴(kuò)展知道需要增加一臺(tái)服務(wù)器。但是就是因?yàn)樵黾舆@一臺(tái)服務(wù)器帶來了一些問題。看下面這個(gè)例子,一共9個(gè)數(shù),需要放到2臺(tái)機(jī)器 (1、2)上。各個(gè)機(jī)器存放為:1號(hào)機(jī)器存放1、3、5、7、9 ,2號(hào)機(jī)器存放 2、4、6、8。如果擴(kuò)展一臺(tái)機(jī)器3如何,數(shù)據(jù)就要發(fā)生大遷移,1號(hào)機(jī)器存放1、4、7, 2號(hào)機(jī)器存放2、5、8, 3號(hào)機(jī)器存放3、6、9。如圖:
從圖中可以看出 1號(hào)機(jī)器的3、5、9遷移出去了、2好機(jī)器的4、6遷移出去了,按照新的秩序再重新分配了一遍。數(shù)據(jù)量小的話重新分配一遍代價(jià)并不大,但如果我們擁有上 億、上T級(jí)的數(shù)據(jù)這個(gè)操作成本是相當(dāng)?shù)母?#xff0c;少則幾個(gè)小時(shí)多則數(shù)天。并且遷移的時(shí)候原數(shù)據(jù)庫機(jī)器負(fù)載比較高,那大家就有疑問了,是不是這種水平擴(kuò)展的架構(gòu)方 式不太合理?
—————————–華麗分割線—————————————
一致性hash就是在這種應(yīng)用背景提出來的,現(xiàn)在被廣泛應(yīng)用于分布式緩存,比如memcached。下面簡(jiǎn)單介紹下一致性hash的基本原理。最早 的版本 http://dl.acm.org/citation.cfm?id=258660。國內(nèi)網(wǎng)上有很多文章都寫的比較好。如: http://blog.csdn.net/x15594/article/details/6270242
下面簡(jiǎn)單舉個(gè)例子來說明一致性hash。
準(zhǔn)備:1、2、3 三臺(tái)機(jī)器
還有待分配的9個(gè)數(shù) 1、2、3、4、5、6、7、8、9
一致性hash算法架構(gòu)
步驟
一、構(gòu)造出來 2的32次方 個(gè)虛擬節(jié)點(diǎn)出來,因?yàn)橛?jì)算機(jī)里面是01的世界,進(jìn)行劃分時(shí)采用2的次方數(shù)據(jù)容易分配均衡。另 2的32次方是42億,我們就算有超大量的服務(wù)器也不可能超過42億臺(tái)吧,擴(kuò)展和均衡性都保證了。
二、將三臺(tái)機(jī)器分別取IP進(jìn)行hashcode計(jì)算(這里也可以取hostname,只要能夠唯一區(qū)別各個(gè)機(jī)器就可以了),然后映射到2的32次方上去。 比如1號(hào)機(jī)器算出來的hashcode并且mod (2^32)為 123(這個(gè)是虛構(gòu)的),2號(hào)機(jī)器算出來的值為 2300420,3號(hào)機(jī)器算出來為 90203920。這樣三臺(tái)機(jī)器就映射到了這個(gè)虛擬的42億環(huán)形結(jié)構(gòu)的節(jié)點(diǎn)上了。
三、將數(shù)據(jù)(1-9)也用同樣的方法算出hashcode并對(duì)42億取模將其配置到環(huán)形節(jié)點(diǎn)上。假設(shè)這幾個(gè)節(jié)點(diǎn)算出來的值為 1:10,2:23564,3:57,4:6984,5:5689632,6:86546845,7:122,8:3300689,9:135468。可 以看出 1、3、7小于123, 2、4、9 小于 2300420 大于 123, 5、6、8 大于 2300420 小于90203920。從數(shù)據(jù)映射到的位置開始順時(shí)針查找,將數(shù)據(jù)保存到找到的第一個(gè)Cache節(jié)點(diǎn)上。如果超過2^32仍然找不到Cache節(jié)點(diǎn),就會(huì) 保存到第一個(gè)Cache節(jié)點(diǎn)上。也就是1、3、7將分配到1號(hào)機(jī)器,2、4、9將分配到2號(hào)機(jī)器,5、6、8將分配到3號(hào)機(jī)器。
這個(gè)時(shí)候大家可能會(huì)問,我到現(xiàn)在沒有看見一致性hash帶來任何好處,比傳統(tǒng)的取模還增加了復(fù)雜度。現(xiàn)在馬上來做一些關(guān)鍵性的處理,比如我們?cè)黾右慌_(tái)機(jī) 器。按照原來我們需要把所有的數(shù)據(jù)重新分配到四臺(tái)機(jī)器。一致性hash怎么做呢?現(xiàn)在4號(hào)機(jī)器加進(jìn)來,他的hash值算出來取模后是12302012。 5、8 大于2300420 小于12302012 ,6 大于 12302012 小于90203920 。這樣調(diào)整的只是把5、8從3號(hào)機(jī)器刪除,4號(hào)機(jī)器中加入 5、6。
同理,刪除機(jī)器怎么做呢,假設(shè)2號(hào)機(jī)器掛掉,受影響的也只是2號(hào)機(jī)器上的數(shù)據(jù)被遷移到離它節(jié)點(diǎn),上圖為4號(hào)機(jī)器。
大家應(yīng)該明白一致性hash的基本原理了吧。不過這種算法還是有缺陷,比如在機(jī)器節(jié)點(diǎn)比較少、數(shù)據(jù)量大的時(shí)候,數(shù)據(jù)的分布可能不是很均衡,就會(huì)導(dǎo)致其中一 臺(tái)服務(wù)器的數(shù)據(jù)比其他機(jī)器多很多。為了解決這個(gè)問題,需要引入虛擬服務(wù)器節(jié)點(diǎn)的機(jī)制。如我們一共有只有三臺(tái)機(jī)器,1、2、3。但是實(shí)際又不可能有這么多機(jī) 器怎么解決呢?把 這些機(jī)器各自虛擬化出來3臺(tái)機(jī)器,也就是 1a 1b 1c 2a 2b 2c 3a 3b 3c,這樣就變成了9臺(tái)機(jī)器。實(shí)際 1a 1b 1c 還是對(duì)應(yīng)1。但是實(shí)際分布到環(huán)形節(jié)點(diǎn)就變成了9臺(tái)機(jī)器。數(shù)據(jù)分布也就能夠更分散一點(diǎn)。如圖:
寫了這么多一致性hash,這個(gè)和分布式搜索有什么半點(diǎn)關(guān)系?我們現(xiàn)在使用solr4搭建了分布式搜索,測(cè)試了基于solrcloud的分布式平臺(tái) 提交20條數(shù)據(jù)居然需要幾十秒,所以就廢棄了solrcloud。采用自己hack solr平臺(tái),不用zookeeper做分布式一致性管理平臺(tái),自己管理數(shù)據(jù)的分發(fā)機(jī)制。既然需要自己管理數(shù)據(jù)的分發(fā),就需要考慮到索引的創(chuàng)建,索引的更 新。這樣我們的一致性hash也就用上了。整體架構(gòu)如下圖:
建立和更新需要維持機(jī)器的位置,能夠根據(jù)數(shù)據(jù)的key找到對(duì)應(yīng)的數(shù)據(jù)分發(fā)并更新。這里需要考慮的是如何高效、可靠的把數(shù)據(jù)建立、更新到索引里。
備份服務(wù)器防止建立服務(wù)器掛掉,可以根據(jù)備份服務(wù)器快速恢復(fù)。
讀服務(wù)器主要做讀寫分離使用,防止寫索引影響查詢數(shù)據(jù)。
集群管理服務(wù)器管理整個(gè)集群內(nèi)的服務(wù)器狀態(tài)、告警。
整個(gè)集群隨著業(yè)務(wù)增多還可以按照數(shù)據(jù)的類型劃分,比如用戶、微博等。每個(gè)類型按照上圖架構(gòu)搭建,就可以滿足一般性能的分布式搜索。對(duì)于solr和分布式搜索的話題后續(xù)再聊。
擴(kuò)展閱讀:
java的hashmap隨著數(shù)據(jù)量的增加也會(huì)出現(xiàn)map調(diào)整的問題,必要的時(shí)候就初始化足夠大的size以防止容量不足對(duì)已有數(shù)據(jù)進(jìn)行重新hash計(jì)算。
疫苗:Java HashMap的死循環(huán) http://coolshell.cn/articles/9606.html
一致性哈希算法的優(yōu)化—-關(guān)于如何保正在環(huán)中增加新節(jié)點(diǎn)時(shí),命中率不受影響 (原拍拍同事scott)http://scottina.iteye.com/blog/650380
語言實(shí)現(xiàn):
http://weblogs.java.net/blog/2007/11/27/consistent-hashing java 版本的例子
http://blog.csdn.net/mayongzhan/archive/2009/06/25/4298834.aspx PHP 版的例子
http://www.codeproject.com/KB/recipes/lib-conhash.aspx C語言版本例子
總結(jié)
以上是生活随笔為你收集整理的一致性哈希算法 应用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JVM初探:内存分配、GC原理与垃圾收集
- 下一篇: 单个节点的缓存容量达到上限 Hash算法