1. 程式人生 > >(轉) SolrCloud之分布式索引及與Zookeeper的集成

(轉) SolrCloud之分布式索引及與Zookeeper的集成

閾值 leader選舉 較高的 配置 配置信息 tail ots 便是 recovery

http://blog.csdn.net/ebay/article/details/46549481

作者:Wang, Josh

一、概述

Lucene是一個Java語言編寫的利用倒排原理實現的文本檢索類庫,Solr是以Lucene為基礎實現的文本檢索應用服務,SolrCloud是Solr4.0版本開發出的具有開創意義的基於Solr和Zookeeper的分布式搜索方案,主要思想是使用Zookeeper作為集群的配置信息中心。也可以說,SolrCloud是Solr的一種部署方式,除SolrCloud之外,Solr還可以以單機方和多機Master-Slaver方式進行部署。分布式索引是指當索引越來越大,一個單一的系統無法滿足磁盤需求的時候,或者一次簡單的查詢實在要耗費很多時間的時候,我們就可以使用solr的分布式索引了。在分布式索引中,原來的大索引,將會分成多個小索引,solr可以將這些小索引返回的結果合並,然後返回給客戶端。

二、SolrCloud的基本概念

SolrCloud模式下有Cluster,Node,Collection,Shard,LeaderCore,ReplicationCore等重要概念。

1、Cluster集群:Cluster是一組Solr節點,邏輯上作為一個單元進行管理,整個集群必須使用同一套schema和SolrConfig。

2、Node節點:一個運行Solr的JVM實例。

3、Collection:在SolrCloud集群中邏輯意義上的完整的索引,常常被劃分為一個或多個Shard,這些Shard使用相同的Config Set,如果Shard數超過一個,那麽索引方案就是分布式索引。SolrCloud允許客戶端用戶通過Collection名稱引用它,這樣用戶不需要關心分布式檢索時需要使用的和Shard相關參數。

4、Core: 也就是Solr Core,一個Solr中包含一個或者多個Solr Core,每個Solr Core可以獨立提供索引和查詢功能,Solr Core的提出是為了增加管理靈活性和共用資源。SolrCloud中使用的配置是在Zookeeper中的,而傳統的Solr Core的配置文件是在磁盤上的配置目錄中。

5、Config Set: Solr Core提供服務必須的一組配置文件,每個Config Set有一個名字。最小需要包括solrconfig.xml和schema.xml,除此之外,依據這兩個文件的配置內容,可能還需要包含其它文件,如中文索引需要的詞庫文件。Config Set存儲在Zookeeper中,可以重新上傳或者使用upconfig命令進行更新,可使用Solr的啟動參數bootstrap_confdir進行初始化或更新。

6、Shard分片: Collection的邏輯分片。每個Shard被分成一個或者多個replicas,通過選舉確定哪個是Leader。

7、Replica: Shard的一個拷貝。每個Replica存在於Solr的一個Core中。換句話說一個SolrCore對應著一個Replica,如一個命名為“test”的collection以numShards=1創建,並且指定replicationFactor為2,這會產生2個replicas,也就是對應會有2個Core,分別存儲在不同的機器或者Solr實例上,其中一個會被命名為test_shard1_replica1,另一個命名為test_shard1_replica2,它們中的一個會被選舉為Leader。

8、 Leader: 贏得選舉的Shard replicas,每個Shard有多個Replicas,這幾個Replicas需要選舉來確定一個Leader。選舉可以發生在任何時間,但是通常他們僅在某個Solr實例發生故障時才會觸發。當進行索引操作時,SolrCloud會將索引操作請求傳到此Shard對應的leader,leader再分發它們到全部Shard的replicas。

9、Zookeeper: Zookeeper提供分布式鎖功能,這對SolrCloud是必須的,主要負責處理Leader的選舉。Solr可以以內嵌的Zookeeper運行,也可以使用獨立的Zookeeper,並且Solr官方建議最好有3個以上的主機。

三、SolrCloud中完整索引(Collection)的邏輯圖

技術分享

SolrCloud模式下Collection是訪問Cluster的入口,這個入口有什麽用呢?比如說集群裏面有好多臺機器,那麽訪問這個集群通過哪個地址呢,必須有一個接口地址,Collection就是這個接口地址。可見Collection是一個邏輯存在的東西,因此是可以跨Node的,在任意節點上都可以訪問Collection。Shard其實也是邏輯存在的,因此Shard也是可以跨Node的; 1個Shard下面可以包含0個或者多個Replication,但1個Shard下面能且只能包含一個Leader
如果Shard下面的Leader掛掉了,會從Replication裏面再選舉一個Leader。

此處需要註意的是在Solr4.0中,可以在Solr AdminGUI裏面增加和刪除Core,如果Shard裏最後一個Core被刪除了,Shard是不會自動刪除的,這會導致集群出錯, 而且如果Shard裏面所有的Core宕機了,會導致不能繼續插入新的記錄,從而導致查詢會受到影響,其實如果一個Shard下的所有Core宕機了,SolrCloud應該允許插入到其它存活的Shard裏面,這在後期版本中的Solr中應該會被支持。

四、SolrCloud索引操作的基本架構圖

技術分享

圖中所示為擁有4個Solr節點的集群,索引分布在兩個Shard裏面,每個Shard包含兩個Solr節點,一個是Leader節點,一個是Replica節點,此外集群中有一個負責維護集群狀態信息的Overseer節點,它是一個總控制器。

集群的所有狀態信息都放在Zookeeper集群中統一維護。從圖中還可以看到,任何一個節點都可以接收索引創建或者更新的請求,然後再將這個請求轉發到索引文檔所應該屬於的那個Shard的Leader節點,Leader節點更新結束完成後,最後將版本號和文檔轉發給同屬於一個Shard的replicas節點。

五、SolrCloud的工作模式

首先來看下索引和Solr實體對照圖

技術分享

SolrCloud中包含有多個Solr Instance,而每個Solr Instance中包含有多個Solr Core,Solr Core對應著一個可訪問的Solr索引資源,每個Solr Core對應著一個Replica或者Leader,這樣,當Solr Client通過Collection訪問Solr集群的時候,便可通過Shard分片找到對應的Replica即SolrCore,從而就可以訪問索引文檔了。

技術分享

在SolrCloud模式下,同一個集群裏所有Core的配置是統一的,Core有leader和replication兩種角色,每個Core一定屬於一個Shard,Core在Shard中扮演Leader還是replication由Solr內部Zookeeper自動協調。

訪問SolrCloud的過程:Solr Client向Zookeeper咨詢Collection的地址,Zookeeper返回存活的節點地址供訪問,插入數據的時候由SolrCloud內部協調數據分發(內部使用一致性哈希)。

六、SolrCloud創建索引和更新索引

<一>、不得不知道的索引存儲細節

當Solr客戶端發送add/update請求給CloudSolrServer,CloudSolrServer會連接至Zookeeper獲取當前SolrCloud的集群狀態,並會在/clusterstate.json 和/live_nodes中註冊watcher,便於監視Zookeeper和SolrCloud,這樣做的好處有以下兩點:

1、CloudSolrServer獲取到SolrCloud的狀態後,它可直接將document發往SolrCloud的leader,從而降低網絡轉發消耗。

2、註冊watcher有利於建索引時候的負載均衡,比如如果有個節點leader下線了,那麽CloudSolrServer會立馬得知,那它就會停止往已下線的leader發送document。

此外,CloudSolrServer 在發送document時候需要知道發往哪個shard?對於建好的SolrCloud集群,每一個shard都會有一個Hash區間,當Document進行update的時候,SolrCloud就會計算這個Document的Hash值,然後根據該值和shard的hash區間來判斷這個document應該發往哪個shard,Solr使用documentroute組件來進行document的分發。目前Solr有兩個DocRouter類的子類CompositeIdRouter(Solr默認采用的)類和ImplicitDocRouter類,當然我們也可以通過繼承DocRouter來定制化我們的document route組件。

舉例來說當Solr Shard建立時候,Solr會給每一個shard分配32bit的hash值的區間,比如SolrCloud有兩個shard分別為A,B,那麽A的hash值區間就為80000000-ffffffff,B的hash值區間為0-7fffffff。默認的CompositeIdRouter hash策略會根據document ID計算出唯一的Hash值,並判斷該值在哪個shard的hash區間內。

SolrCloud對於Hash值的獲取提出了以下兩個要求:

1、hash計算速度必須快,因為hash計算是分布式建索引的第一步。

2、 hash值必須能均勻的分布於每一個shard,如果有一個shard的document數量大於另一個shard,那麽在查詢的時候前一個shard所花的時間就會大於後一個,SolrCloud的查詢是先分後匯總的過程,也就是說最後每一個shard查詢完畢才算完畢,所以SolrCloud的查詢速度是由最慢的shard的查詢速度決定的。

基於以上兩點,SolrCloud采用了MurmurHash 算法以提高hash計算速度和hash值的均勻分布。

<二>、Solr創建索引可以分為5個步驟(如下圖所示):

1、用戶可以把新建文檔提交給任意一個Replica(Solr Core)。

2、如果它不是leader,它會把請求轉給和自己同Shard的Leader。

3、Leader把文檔路由給本Shard的每個Replica。

III、如果文檔基於路由規則(如取hash值)並不屬於當前的Shard,leader會把它轉交給對應Shard的Leader。

VI、對應Leader會把文檔路由給本Shard的每個Replica。

需要註意的是,添加索引時,單個document的路由非常簡單,但是SolrCloud支持批量添加索引,也就是說正常情況下可對N個document同時進行路由。這時SolrCloud會根據document路由的去向分開存放document,即對document進行分類,然後進行並發發送至相應的shard,這就需要較高的並發能力。

技術分享

<三>、更新索引的關鍵點:

1、 Leader接受到update請求後,先將update信息存放到本地的update log,同時Leader還會給document分配新的version,對於已存在的document,如果新的版本高就會拋棄舊版本,最後發送至replica。

2、一旦document經過驗證以及加入version後,就會並行的被轉發至所有上線的replica。SolrCloud並不會關註那些已經下線的replica,因為當他們上線時候會有recovery進程對他們進行恢復。如果轉發的replica處於recovering狀態,那麽這個replica就會把update放入updatetransaction 日誌。

3、當leader接受到所有的replica的反饋成功後,它才會反饋客戶端成功。只要shard中有一個replica是active的,Solr就會繼續接受update請求。這一策略其實是犧牲了一致性換取了寫入的有效性。這其中有一個重要參數:leaderVoteWait參數,它表示當只有一個replica時候,這個replica會進入recovering狀態並持續一段時間等待leader的重新上線。如果在這段時間內leader沒有上線,那麽他就會轉成leader,其中可能會有一些document丟失。當然可以使用majority quorum來避免這個情況,這跟Zookeeper的leader選舉策略一樣,比如當多數的replica下線了,那麽客戶端的write就會失敗。

4、索引的commit有兩種,一種是softcommit,即在內存中生成segment,document是可見的(可查詢到)但是沒寫入磁盤,斷電後數據會丟失。另一種是hardcommit,直接將數據寫入磁盤且數據可見。

<四>、對Solr更新索引和創建索引的幾點總結:

1、leader轉發的規則

1)請求來自leader轉發:那麽就只需要寫到本地ulog,不需要轉發給leader,也不需要轉發給其它replicas。如果replica處於非active狀態,就會將update請求接受並寫入ulog,但不會寫入索引。如果發現重復的更新就會丟棄舊版本的更新。

2)請求不是來自leader,但自己就是leader,那麽就需要將請求寫到本地,順便分發給其他的replicas。

3)請求不是來自leader,但自己又不是leader,也就是該更新請求是最原始的更新請求,那麽需要將請求寫到本地ulog,順便轉發給leader,再由leader分發。每commit一次,就會重新生成一個ulog更新日誌,當服務器掛掉,內存數據丟失的時候,數據就可以從ulog中恢復。

2、建索引的時候最好使用CloudSolrServer,因為CloudSolrServer直接向leader發送update請求,從而避免網絡開銷。

3、批量添加索引的時候,建議在客戶端提前做好document的路由,在SolrCloud內進行文檔路由,開銷較大。

七、SolrCloud索引的檢索

技術分享

在創建好索引的基礎上,SolrCloud檢索索引相對就比較簡單了:

1、用戶的一個查詢,可以發送到含有該Collection的任意Solr的Server,Solr內部處理的邏輯會轉到一個Replica。

2、此Replica會基於查詢索引的方式,啟動分布式查詢,基於索引的Shard的個數,把查詢轉為多個子查詢,並把每個子查詢定位到對應Shard的任意一個Replica。

3、每個子查詢返回查詢結果。

4、最初的Replica合並子查詢,並把最終結果返回給用戶。

SolrCloud中提供NRT近實時搜索:

SolrCloud支持近實時搜索,所謂的近實時搜索即在較短的時間內使得新添加的document可見可查,這主要基於softcommit機制(註意:Lucene是沒有softcommit的,只有hardcommit)。上面提到Solr建索引時的數據是在提交時寫入磁盤的,這是硬提交,硬提交確保了即便是停電也不會丟失數據;為了提供更實時的檢索能力,Solr提供了一種軟提交方式。軟提交(soft commit)指的是僅把數據提交到內存,index可見,此時沒有寫入到磁盤索引文件中。在設計中一個通常的做法是:每1-10分鐘自動觸發硬提交,每秒鐘自動觸發軟提交,當進行softcommit時候,Solr會打開新的Searcher從而使得新的document可見,同時Solr還會進行預熱緩存及查詢以使得緩存的數據也是可見的,這就必須保證預熱緩存以及預熱查詢的執行時間必須短於commit的頻率,否則就會由於打開太多的searcher而造成commit失敗。

最後說說在項目中近實時搜索的感受吧,近實時搜索是相對的,對於有客戶需求,1分鐘就是近實時了,而有些需求3分鐘就是近實時了。對於Solr來說,softcommit越頻繁實時性更高,而softcommit越頻繁則Solr的負荷越大(commit越頻繁越會生成小且多的segment,於是Solr merge出現的更頻繁)。目前我們項目中的softcommit頻率是3分鐘,之前設置過1分鐘而使得Solr在Index所占資源過多,從而大大影響了查詢。所以近實時蠻困擾著我們的,因為客戶會不停的要求你更加實時,目前項目中我們采用加入緩存機制來彌補這個實時性。

八、SolrShard Splitting的具體過程

一般情況下,增加Shard和Replica的數量能提升SolrCloud的查詢性能和容災能力,但是我們仍然得根據實際的document的數量,document的大小,以及建索引的並發,查詢復雜度,以及索引的增長率來統籌考慮Shard和Replica的數量。Solr依賴Zookeeper實現集群的管理,在Zookeeper中有一個Znode 是/clusterstate.json ,它存儲了當前時刻下整個集群的狀態。同時在一個集群中有且只會存在一個overseer,如果當前的overseer fail了那麽SolrCloud就會選出新的一個overseer,就跟shard leader選取類似。

技術分享

Shard分割的具體過程(old shard split為newShard1和newShard2)可以描述為:

a、在一個Shard的文檔到達閾值,或者接收到用戶的API命令,Solr將啟動Shard的分裂過程。

b、此時,原有的Shard仍然會提供服務,Solr將會提取原有Shard並按路由規則,轉到新的Shard做索引。同時,新加入的文檔:

1.2.用戶可以把文檔提交給任意一個Replica,並轉交給Leader。

3.Leader把文檔路由給原有Shard的每個Replica,各自做索引。

III.V. 同時,會把文檔路由給新的Shard的Leader

IV.VI.新Shard的Leader會路由文檔到自己的Replica,各自做索引,在原有文檔重新索引完成,系統會把分發文檔路由切到對應的新的Leader上,原有Shard關閉。Shard只是一個邏輯概念,所以Shard的Splitting只是將原有Shard的Replica均勻的分不到更多的Shard的更多的Solr節點上去。

九、Zookeeper:

<一>、SolrCloud中使用ZooKeeper主要實現以下三點功能:

技術分享

1、集中配置存儲以及管理。

2、集群狀態改變時進行監控以及通知。

3、shard leader的選舉。

<二>、 Znode與短鏈接

Zookeeper的組織結構類似於文件系統,每一層是一個Znode,每一個Znode存儲了一些元數據例如創建時間,修改時間以及一些小量的數據。需要主要的是,Zookeeper並不支持存放大數據,它只支持小於1M大小的數據,因為性能原因,Zookeeper將數據存放在內存中。

Zookeeper另一個重要的概念是短鏈接,當Zookeeper客戶端與Zookeeper建立一個短連接後會在Zookeeper新建一個Znode,客戶端會一直與Zookeeper進行通信並保證這個Znode一直存在。如果當客戶端與Zookeeper的短連接斷開,這個Znode就會消失。在SolrCloud中,/live_nodes下存儲了了所有客戶端的短連接,表示有哪些Solr組成SolrCloud,具體來說就是當Solr跟Zookeeper保持短連接時,這些Solr主機就組成了SolrCloud,如果其中一個Solr的短連接斷掉了,那麽Live_nodes下就少了一個Znode,SolrCloud也就少了一個主機,於是Zookeeper就會告訴其他剩余的Solr有一個Solr掛掉了,那麽在今後進行查詢以及leader數據分發的時候就不用再經過剛才那個Solr了。Zookeeper是通過watch知道有Solr掛了的,而Zookeeper維護的集群狀態數據是存放在solr/zoo_data目錄下的。

<三>、SolrCloud配置Zookeeper集群的基本過程

事例1、單節點的Zookeeper,包含2個簡單的Shard集群:把一個collection的索引數據分布到兩個shard上去,並假定兩個shard分別存儲在兩臺Solr服務器上。

技術分享

集群構建的基本流程:

先從第一臺solr服務器說起:

1、啟動一個嵌入式的Zookeeper服務器,作為集群狀態信息的管理者。

2、將自己這個節點註冊到/node_states/目錄。

3、同時將自己註冊到/live_nodes/目錄下。

4、創建/overseer_elect/leader,為後續Overseer節點的選舉做準備,新建一個Overseer。

5、更新/clusterstate.json目錄下json格式的集群狀態信息

6、本機從Zookeeper中更新集群狀態信息,維持與Zookeeper上的集群信息一致。

7、上傳本地配置文件到Zookeeper中,供集群中其他solr節點使用。

8、啟動本地的Solr服務器,

9、Solr啟動完成後,Overseer會得知shard中有第一個節點進來,更新shard狀態信息,並將本機所在節點設置為shard1的leader節點,並向整個集群發布最新的集群狀態信息。

10、本機從Zookeeper中再次更新集群狀態信息,第一臺solr服務器啟動完畢。

然後來看第二臺solr服務器的啟動過程:

1、本機連接到集群所在的Zookeeper。

2、將自己這個節點註冊到/node_states/目錄下。

3、同時將自己註冊到/live_nodes/目錄下。

4、本機從Zookeeper中更新集群狀態信息,維持與Zookeeper上的集群信息一致。

5、從集群中保存的配置文件加載Solr所需要的配置信息。

6、啟動本地solr服務器。

7、solr啟動完成後,將本節點註冊為集群中的shard,並將本機設置為shard2的Leader節點。

8、本機從Zookeeper中再次更新集群狀態信息,第二臺solr服務器啟動完畢。

示例2、單節點的Zookeeper,包含2個shard的集群,每個shard中有replica節點。

技術分享

如圖所示,集群包含2個shard,每個shard中有兩個solr節點,一個是leader,一個是replica節點, 但Zookeeper只有一個。

因為Replica節點,使得這個集群現在具備容錯性了,背後的實質是集群的overseer會監測各個shard的leader節點,如果leader節點掛了,則會啟動自動的容錯機制,會從同一個shard中的其他replica節點集中重新選舉出一個leader節點,甚至如果overseer節點自己也掛了,同樣會自動在其他節點上啟用新的overseer節點,這樣就確保了集群的高可用性。

示例3、包含2個shard的集群,帶shard備份和zookeeper集群機制


技術分享

示例2中存在的問題是:盡管solr服務器具有容錯機制,但集群中只有一個Zookeeper服務器來維護集群的狀態信息,單點的存在即是不穩定的根源。如果這個Zookeeper服務器掛了,那麽分布式查詢還是可以工作的,因為每個solr服務器都會在內存中維護最近一次由Zookeeper維護的集群狀態信息,但新的節點無法加入集群,集群的狀態變化也不可知了。

因此,為了解決這個問題,需要對Zookeeper服務器也設置一個集群,讓其也具備高可用性和容錯性。有兩種方式可選,一種是提供一個外部獨立的Zookeeper集群,另一種是每個solr服務器都啟動一個內嵌的Zookeeper服務器,再將這些Zookeeper服務器組成一個集群。

總結: 通過以上的介紹,可看出SolrCloud相比Solr而言,有了很多的新特性,保證了整個Solr應用的High Availability。

1、集中式的配置信息

使用ZK進行集中配置。啟動時可以指定把Solr的相關配置文件上傳Zookeeper,多機器共用。這些ZK中的配置不會再拿到本地緩存,Solr直接讀取ZK中的配置信息。另外配置文件的變動,所有機器都可以感知到, Solr的一些任務也是通過ZK作為媒介發布的,目的是為了容錯,這使得Solr接收到任務,但在執行任務時崩潰的機器,在重啟後,或者集群選出候選者時,可以再次執行這個未完成的任務。

2、SolrCloud對索引分片,並對每個分片創建多個Replication。每個Replication都可以對外提供服務。一個Replication掛掉不會影響索引服務,更強大的是,SolrCloud還能自動的在其它機器上幫你把失敗機器上的索引Replication重建並投入使用。

3、近實時搜索:立即推送式的replication(也支持慢推送),可以在秒內檢索到新加入索引。

4、查詢時自動負載均衡:SolrCloud索引的多個Replication可以分布在多臺機器上,均衡查詢壓力,如果查詢壓力大,可以通過擴展機器,增加Replication來減緩。

5、自動分發的索引和索引分片:發送文檔到任何節點,SolrCloud都會轉發到正確節點。

6、事務日誌:事務日誌確保更新無丟失,即使文檔沒有索引到磁盤。

除此之外,SolrCloud中還提供了其它一些特色功能:

1、可將索引存儲在HDFS上

2、通過MR批量創建索引

3、強大的RESTful API

優秀的管理界面:主要信息一目了然,可以清晰的以圖形化方式看到SolrCloud的部署分布,當然還有不可或缺的Debug功能。

參考資料:

http://lucene.apache.org/solr/resources.html#documentation

http://www.cnblogs.com/phinecos/archive/2012/02/10/2345634.html

http://tech.uc.cn/?p=2387

(轉) SolrCloud之分布式索引及與Zookeeper的集成