一致性hash和solr千萬級數據分佈式搜索引擎中的應用

互聯網創業中大部分人都是草根創業,這個時候沒有強勁的服務器,也沒有錢去買很昂貴的海量數據庫。在這樣嚴峻的條件下,一批又一批的創業者從創業中 得到成功,這個和當前的開源技術、海量數據架構有着必不可分的關係。好比咱們使用mysql、nginx等開源軟件,經過架構和低成本服務器也能夠搭建千 萬級用戶訪問量的系統。新浪微博、淘寶網、騰訊等大型互聯網公司都使用了不少開源免費系統搭建了他們的平臺。因此,用什麼不要緊,只要可以在合理的狀況下 採用合理的解決方案。html

那怎麼搭建一個好的系統架構呢?這個話題太大,這裏主要說一下數據分流的方式。好比咱們的數據庫服務器只能存儲200個數據,忽然要搞一個活動預估達到600個數據。java

能夠採用兩種方式:橫向擴展或者縱向擴展。mysql

  • 縱向擴展是升級服務器的硬件資源。可是隨着機器的性能配置越高,價格越高,這個代價對於通常的小公司是承擔不起的。
  • 橫向擴展是採用多個廉價的機器提供服務。這樣一個機器只能處理200個數據、3個機器就能夠處理600個數據了,若是之後業務量增長還能夠快速配置增長。在大多數狀況都選擇橫向擴展的方式。以下圖:

如今有個問題了,這600個數據如何路由到對應的機器。須要考慮若是均衡分配,假設咱們600個數據都是統一的自增id數據,從1~600,分紅3 堆能夠採用 id mod 3的方式。其實在真實環境可能不是這種id是字符串。須要把字符串轉變爲hashcode再進行取模。nginx

目前看起來是否是解決咱們的問題了,全部數據都很好的分發而且沒有達到系統的負載。但若是咱們的數據須要存儲、須要讀取就沒有這麼容易了。業務增多 怎麼辦,你們按照上面的橫向擴展知道須要增長一臺服務器。可是就是由於增長這一臺服務器帶來了一些問題。看下面這個例子,一共9個數,須要放到2臺機器 (一、2)上。各個機器存放爲:1號機器存放一、三、五、七、9 ,2號機器存放 二、四、六、8。若是擴展一臺機器3如何,數據就要發生大遷移,1號機器存放一、四、7, 2號機器存放二、五、8, 3號機器存放三、六、9。如圖:web


從圖中能夠看出 1號機器的三、五、9遷移出去了、2好機器的四、6遷移出去了,按照新的秩序再從新分配了一遍。數據量小的話從新分配一遍代價並不大,但若是咱們擁有上 億、上T級的數據這個操做成本是至關的高,少則幾個小時多則數天。而且遷移的時候原數據庫機器負載比較高,那你們就有疑問了,是否是這種水平擴展的架構方 式不太合理?算法

—————————–華麗分割線—————————————sql

一致性hash就是在這種應用背景提出來的,如今被普遍應用於分佈式緩存,好比memcached。下面簡單介紹下一致性hash的基本原理。最先 的版本 http://dl.acm.org/citation.cfm?id=258660。國內網上有不少文章都寫的比較好。如: http://blog.csdn.net/x15594/article/details/6270242shell

下面簡單舉個例子來講明一致性hash。數據庫

準備:一、二、3 三臺機器
還有待分配的9個數 一、二、三、四、五、六、七、八、9
一致性hash算法架構緩存

步驟
1、構造出來 2的32次方 個虛擬節點出來,由於計算機裏面是01的世界,進行劃分時採用2的次方數據容易分配均衡。另 2的32次方是42億,咱們就算有超大量的服務器也不可能超過42億臺吧,擴展和均衡性都保證了。

2、將三臺機器分別取IP進行hashcode計算(這裏也能夠取hostname,只要可以惟一區別各個機器就能夠了),而後映射到2的32次方 上去。好比1號機器算出來的hashcode而且mod (2^32)爲 123(這個是虛構的),2號機器算出來的值爲 2300420,3號機器算出來爲 90203920。這樣三臺機器就映射到了這個虛擬的42億環形結構的節點上了。


3、將數據(1-9)也用一樣的方法算出hashcode並對42億取模將其配置到環形節點上。假設這幾個節點算出來的值爲 1:10,2:23564,3:57,4:6984,5:5689632,6:86546845,7:122,8:3300689,9:135468。可 以看出 一、三、7小於123, 二、四、9 小於 2300420 大於 123, 五、六、8 大於 2300420 小於90203920。從數據映射到的位置開始順時針查找,將數據保存到找到的第一個Cache節點上。若是超過2^32仍然找不到Cache節點,就會 保存到第一個Cache節點上。也就是一、三、7將分配到1號機器,二、四、9將分配到2號機器,五、六、8將分配到3號機器。

這個時候你們可能會問,我到如今沒有看見一致性hash帶來任何好處,比傳統的取模還增長了複雜度。如今立刻來作一些關鍵性的處理,好比咱們增長一 臺機器。按照原來咱們須要把全部的數據從新分配到四臺機器。一致性hash怎麼作呢?如今4號機器加進來,他的hash值算出來取模後是 12302012。 五、8 大於2300420 小於12302012 ,6 大於 12302012 小於90203920 。這樣調整的只是把五、8從3號機器刪除,4號機器中加入 五、6。


同理,刪除機器怎麼作呢,假設2號機器掛掉,受影響的也只是2號機器上的數據被遷移到離它節點,上圖爲4號機器。


你們應該明白一致性hash的基本原理了吧。不過這種算法仍是有缺陷,好比在機器節點比較少、數據量大的時候,數據的分佈可能不是很均衡,就會致使其中一 臺服務器的數據比其餘機器多不少。爲了解決這個問題,須要引入虛擬服務器節點的機制。如咱們一共有隻有三臺機器,一、二、3。可是實際又不可能有這麼多機 器怎麼解決呢?把 這些機器各自虛擬化出來3臺機器,也就是 1a 1b 1c 2a 2b 2c 3a 3b 3c,這樣就變成了9臺機器。實際 1a 1b 1c 仍是對應1。可是實際分佈到環形節點就變成了9臺機器。數據分佈也就可以更分散一點。如圖:

寫了這麼多一致性hash,這個和分佈式搜索有什麼半點關係?咱們如今使用solr4搭建了分佈式搜索,測試了基於solrcloud的分佈式平臺 提交20條數據竟然須要幾十秒,因此就廢棄了solrcloud。採用本身hack solr平臺,不用zookeeper作分佈式一致性管理平臺,本身管理數據的分發機制。既然須要本身管理數據的分發,就須要考慮到索引的建立,索引的更 新。這樣咱們的一致性hash也就用上了。總體架構以下圖:

  • 創建和更新須要維持機器的位置,可以根據數據的key找到對應的數據分發並更新。這裏須要考慮的是如何高效、可靠的把數據創建、更新到索引裏。
  • 備份服務器防止創建服務器掛掉,能夠根據備份服務器快速恢復。
  • 讀服務器主要作讀寫分離使用,防止寫索引影響查詢數據。
  • 集羣管理服務器管理整個集羣內的服務器狀態、告警。

整個集羣隨着業務增多還能夠按照數據的類型劃分,好比用戶、微博等。每一個類型按照上圖架構搭建,就能夠知足通常性能的分佈式搜索。對於solr和分佈式搜索的話題後續再聊。

擴展閱讀:
java的hashmap隨着數據量的增長也會出現map調整的問題,必要的時候就初始化足夠大的size以防止容量不足對已有數據進行從新hash計算。

疫苗:Java HashMap的死循環 http://coolshell.cn/articles/9606.html
一致性哈希算法的優化—-關於如何保正在環中增長新節點時,命中率不受影響 (原拍拍同事scott)http://scottina.iteye.com/blog/650380

語言實現: 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語言版本例子

相關文章
相關標籤/搜索