12.SolrCloud原理
轉載自http://blog.csdn.net/u011026968/article/details/50336709
內容涉及:SolrCloud的基礎知識、架構、索引創建和更新、查詢、故障恢復、負載均衡、leader選舉等的原理。
一、SolrCloud與Solr,lucene關系
1、 solr與luence的關系
網上有這樣的比喻:
(1) lucene是數據庫的話,solr就是jdbc。
(2) lucene是jar,solr就是一個引用這些jar來寫的搜索客戶端。Solr是一個可以直接用的應用,而lucene只是一些編程用的庫。
2、 Solr與SolrCloud
SolrCloud是Solr4.0版本開發出的具有開創意義的基於Solr和Zookeeper的分布式搜索方案,或者可以說,SolrCloud是Solr的一種部署方式。Solr可以以多種方式部署,例如單機方式,多機Master-Slaver方式,這些方式部署的Solr不具有SolrCloud的特色功能。
二、SolrCloud配置
有兩種方式:
(1)把solr作為web應用部署到Tomcat容器,然後Tomcat與zookeeper關聯
(2)從solr 5開始,solr自身有jetty容器,不必部署到Tomcat,這樣會容易一些。
可以參考如下教程:
http://blog.csdn.net/wanghui2008123/article/details/37813525
三、SolrCloud基礎知識
1.概念
· Collection:在SolrCloud集群中邏輯意義上的完整的索引。它常常被劃分為一個或多個Shard,它們使用相同的Config Set。如果Shard數超過一個,它就是分布式索引,SolrCloud讓你通過Collection名稱引用它,而不需要關心分布式檢索時需要使用的和Shard相關參數。
· ConfigSet: Solr Core提供服務必須的一組配置文件。每個config set有一個名字。最小需要包括solrconfig.xml(SolrConfigXml)和schema.xml (SchemaXml),除此之外,依據這兩個文件的配置內容,可能還需要包含其它文件。它存儲在Zookeeper中。Config sets可以重新上傳或者使用upconfig命令更新,使用Solr的啟動參數bootstrap_confdir指定可以初始化或更新它。
· Core: 也就是Solr Core,一個Solr中包含一個或者多個Solr Core,每個Solr Core可以獨立提供索引和查詢功能,每個Solr Core對應一個索引或者Collection的Shard,Solr Core的提出是為了增加管理靈活性和共用資源。在SolrCloud中有個不同點是它使用的配置是在Zookeeper中的,傳統的Solr core的配置文件是在磁盤上的配置目錄中。
· Leader: 贏得選舉的Shard replicas。每個Shard有多個Replicas,這幾個Replicas需要選舉來確定一個Leader。選舉可以發生在任何時間,但是通常他們僅在某個Solr實例發生故障時才會觸發。當索引documents時,SolrCloud會傳遞它們到此Shard對應的leader,leader再分發它們到全部Shard的replicas。
· Replica: Shard的一個拷貝。每個Replica存在於Solr的一個Core中。一個命名為“test”的collection以numShards=1創建,並且指定replicationFactor設置為2,這會產生2個replicas,也就是對應會有2個Core,每個在不同的機器或者Solr實例。一個會被命名為test_shard1_replica1,另一個命名為test_shard1_replica2。它們中的一個會被選舉為Leader。
· Shard: Collection的邏輯分片。每個Shard被化成一個或者多個replicas,通過選舉確定哪個是Leader。
· Zookeeper: Zookeeper提供分布式鎖功能,對SolrCloud是必須的。它處理Leader選舉。Solr可以以內嵌的Zookeeper運行,但是建議用獨立的,並且最好有3個以上的主機。
· SolrCore: 單機運行時,單獨的索引叫做SolrCore,如果創建多個索引,可以創建的多個SolrCore。
· 索引:一個索引可以在不同的Solr服務上,也就是一個索引可以由不同機器上的SolrCore組成。 不同機器上的SolrCore組成邏輯上的索引,這樣的一個索引叫做Collection,組成Collection的SolrCore包括數據索引和備份。
· SolrCloud collection shard關系:一個SolrCloud包含多個collection,collection可以被分為多個shards, 每個shard可以有多個備份(replicas),這些備份通過選舉產生一個leader,
· Optimization: 是一個進程,壓縮索引和歸並segment,Optimization只會在master node運行,
· Leader 和 replica
(1)leader負責保證replica和leader是一樣的最新的信息
(2)replica 被分到 shard 按照這樣的順序: 在集群中他們第一次啟動的次序輪詢加入,除非新的結點被人工地使用shardId參數分派到shard。人工指定replica屬於哪個shard的方法:-DshardId=1
以後重啟的時候,每個node加入之前它第一次被指派的shard。Node如果以前是replica,當以前的leader不存在的時候,會成為leader。
2.架構
· 索引(collection)的邏輯圖
· 索引和Solr實體對照圖
一個經典的例子:
SolrCloud是基於Solr和Zookeeper的分布式搜索方案,是正在開發中的Solr4.0的核心組件之一,它的主要思想是使用Zookeeper作為集群的配置信息中心。它有幾個特色功能:1)集中式的配置信息 2)自動容錯 3)近實時搜索 4)查詢時自動負載均衡
基本可以用上面這幅圖來概述,這是一個擁有4個Solr節點的集群,索引分布在兩個Shard裏面,每個Shard包含兩個Solr節點,一個是Leader節點,一個是Replica節點,此外集群中有一個負責維護集群狀態信息的Overseer節點,它是一個總控制器。集群的所有狀態信息都放在Zookeeper集群中統一維護。從圖中還可以看到,任何一個節點都可以接收索引更新的請求,然後再將這個請求轉發到文檔所應該屬於的那個Shard的Leader節點,Leader節點更新結束完成,最後將版本號和文檔轉發給同屬於一個Shard的replicas節點。
3.幾種角色
(1)zookeeper:下面的信息是zookeeper上存儲的,zookeeper目錄稱為znode
solr在zookeeper中的結點
2、clusterstate.json 重要信息文件。包含了colletion ,shard ,replica的具體描述信息。 3、live_nodes 下面都是瞬時的zk結點,代表當前存活的solrcloud中的節點。 4、overseer solrcloud中的重要角色。下面存有三個重要的分布式隊列,代表待執行solrcloud相關的zookeeper操作的任務隊列。 4.1 collection-queue-work是存放與collection相關的特辦操作,如createcollection ,reloadcollection,createalias,deletealias ,splitshard 等。 4.2 queue則存放了所有與collection無關的操作,例如deletecore,removecollection,removeshard,leader,createshard,updateshardstate,還有包括節點的狀態(down、active、recovering)的變化。 4.3 queue-work是一個臨時隊列,指正在處理中的消息。操作會先保存到/overseer/queue,在overseser進行處理時,被移到/overseer/queue-work中,處理完後消息之後在從/overseer/queue-work中刪除。如果overseer中途掛了,新選舉的overseer會選將/overseer/queue-work中的操作執行完,再去處理/overseer/queue中的操作。 註意:以上隊列中存放的所有子結點,都是PERSISTENT_SEQUENTIAL類型的。 5、overseer_elect ,用於overseer的選舉工作 6、colletcion,存放當前collection一些簡單信息(主要信息都在clusterstate.json中)。 下面的leader_elect自然是用於collection中shard中副本集的leader選舉的。 |
(2)overseer: overseer是經常被忽略的角色,實際上,我測試過,每次加入一臺新的機器的時候,一方面,SolrCloud會多一個Solr,另一方面,會多一個oveseer(當然可能不會起到作用)。 整個SolrCloud只有一個overseer會起到作用,所有的overseer經過選舉產生overseer。 Overseer和shard的leader選舉方式一樣,詳見後面leader選舉部分。
Overseer 的zk寫流程 在看solrcloud的官方文檔的時候,幾乎也很少有overseer的這個角色的說明介紹。相信不少成功配置solrcloud的開發者,也沒有意識到這個角色的存在。 Overseer,顧名思義,是一個照看全局的角色,做總控工作。體現在代碼與zk的相關操作中,就是zookeeper中大多的寫操作,是由overseer去處理的,並且維護好clusterstate.josn與aliases.json這兩個zk結點的內容。與我們“誰創建,誰修改”做法不同。由各個solr node發起的操作,都會publish到/overseer結點下面相應的queue中去,再由overseer到分布式隊列中去取這些操作信息,做相應的zk修改,並將整個solrcloud中相關的具體狀態信息,更新到cluseterstate.json中去,最終會將這個操作,從queue中刪除,表示完成操作。 以一個solr node將自身狀態標記為down為例。該node會將這種“state”operation的相關信息,publish到/overseer/queue中。由Overseer去從中取得這個操作,然後將node state為down的信息寫入clusterstate.json。最後刪除queue中的這個結點。 當然overseer這個角色,是利用zookeeper在solrcloud中內部選舉出來的。 一般的zk讀操作 Solr將最重要且信息最全面的內容都放在了cluseterstate.json中。這樣做減少了,普通solr node需要關註的zk 結點數。除了clusterstate.json,普通的solr node在需要當前collection整體狀態的時候,還會獲取zk的/live_nodes中的信息,根據live_nodes中的信息,得知collection存活的node, 再從clusterstate.json獲得這些node的信息。 這種處理,其實也好理解。假如一個solr node非正常下線,clusterstate.json中不一定會有變化,但/live_nodes中這個node對應的zk結點就消失了(因為是瞬時的)。 |
四、創建索引的過程(索引更新)
1、細節問題:
(1)下面所說的SolrJ是客戶端,CloudSolrServcer是SolrCloud的機器。
(2)文檔的ID
根據我看源碼,文檔ID生成,一是可以自己配置,二是可以使用默認配置,這時候文檔ID是使用java的UUID生成器(這個ID生成器可以生成全球唯一的ID)
(3)watch
客戶端(watcher)在zookeeper的數據上設置watch, watch是一次性的trigger,當數據改變的時候的時候會觸發,watch發送信息到設置這個Watch的客戶端。
(4)lucene index是一個目錄,索引的insert或者刪除保持不變,文檔總是被插入新創建的file,被刪除的文檔不會真的從file中刪除,而是只是打上tag,直到index被優化。update就是增加和刪除組合。
(5)文檔路由
Solr4.1添加了文檔聚類(譯註:此處翻譯準確性需要權衡,意思是將文檔歸類在一起的意思)的功能來提升查詢性能。
Solr4.5添加了通過一個router.name參數來指定一個特定的路由器實現的功能。如果你使用“compositeId”路由器,你可以在要發送到Solr進行索引的文檔的ID前面添加一個前綴,這個前綴將會用來計算一個hash值,Solr使用這個hash值來確定文檔發送到哪個shard來進行索引。這個前綴的值沒有任何限制(比如沒有必要是shard的名稱),但是它必須總是保持一致來保證Solr的執行結果一致。例如,你需要為不同的顧客聚類文檔,你可能會使用顧客的名字或者是ID作為一個前綴。比如你的顧客是“IBM”,如果你有一個文檔的ID是“12345”,把前綴插入到文檔的id字段中變成:“IBM!12345”,在這裏感嘆號是一個分割符號,這裏的“IBM”定義了這個文檔會指向一個特定的shard。
然後在查詢的時候,你需要把這個前綴包含到你的_route_參數裏面(比如:q=solr&_route_=IBM!)使查詢指向指定的shard。在某些情況下,這樣操作能提升查詢的性能,因為它省掉了需要在所有shard上查詢耗費的網絡傳輸用時。使用_route_代替shard.keys參數。shard.keys參數已經過時了,在Solr的未來版本中這個參數會被移除掉。如果你不想變動文檔的存儲過程,那就不需要在文檔的ID前面添加前綴。如果你創建了collection並且在創建的時候指定了一個“implicit”路由器,你可以另外定義一個router.field參數,這個參數定義了通過使用文檔中的一個字段來確定文檔是屬於哪個shard的。但是,如果在一個文檔中你指定的字段沒有值得話,這個文檔Solr會拒絕處理。同時你也可以使用_route_參數來指定一個特定的shard。
我的理解:添加了這樣聚類的好處:查詢的時候,聲明了route=IBM,那麽就可以減少訪問的shard。
router.name的值可以是 implicit 或者compositeId。 ‘implicit‘ 不自動路由文檔到不同shard,而是會按照你在indexingrequest中暗示的那樣。也就是建索引的時候,如果是implicit是需要自己指定文檔到哪個shard的。比如:
curl "http://10.1.30.220:8081/solr/admin/collections?action=CREATE&name=paper&collection.configName=paper_conf&router.name=implicit&shards=shard1,shard2&createNodeSet=10.1.30.220:8081_solr,10.1.30.220:8084_solr" |
2、具體過程
添加文檔的過程:
(1)當SolrJ發送update請求給CloudSolrServer ,CloudSolrServer會連接至Zookeeper獲取當前SolrCloud的集群狀態,並會在/clusterstate.json 和/live_nodes 註冊watcher,便於監視Zookeeper和SolrCloud,這樣做的好處有以下幾點:
CloudSolrServer獲取到SolrCloud的狀態後,它能直接將document發往SolrCloud的leader,降低網絡轉發消耗。
註冊watcher有利於建索引時候的負載均衡,比如如果有個節點leader下線了,那麽CloudSolrServer會立馬得知,那它就會停止往leader發送document。
(2)路由document至正確的shard。CloudSolrServer 在發送document時候需要知道發往哪個shard,但是這裏需要註意,單個document的路由非常簡單,但是SolrCloud支持批量add,也就是說正常情況下N個document同時進行路由。這個時候SolrCloud就會根據document路由的去向分開存放document即進行分類,然後進行並發發送至相應的shard,這就需要較高的並發能力。
(3)Leader接受到update請求後,先將update信息存放到本地的update log,同時Leader還會給documrnt分配新的version,對於已存在的document,Leader就會驗證分配的新version與已有的version,如果新的版本高就會拋棄舊版本,最後發送至replica。
(4)當只有一個Replica的時候,replica會進入recovering狀態並持續一段時間等待leader重新上線,如果在這段時間內,leader沒有上線,replica會轉成leader並有一些文檔損失。
(5)最後的步驟就是commit了,commit有兩種,一種是softcommit,即在內存中生成segment,document是可見的(可查詢到)但是沒有寫入磁盤,斷電後數據丟失。另一種是hardcommit,直接將數據寫入磁盤且數據可見。前一種消耗較少,後一種消耗較大。
每commit一次,就會重新生成一個ulog更新日誌,當服務器掛掉,內存數據丟失,就可以從ulog中恢復
五、查詢
NRT 近實時搜索
SolrCloud支持近實時搜索,所謂的近實時搜索即在較短的時間內使得add的document可見可查,這主要基於softcommit機制(Lucene是沒有softcommit的,只有hardcommit)。
當進行SoftCommit時候,Solr會打開新的Searcher從而使得新的document可見,同時Solr還會進行預熱緩存以及預熱查詢以使得緩存的數據也是可見的。所以必須保證預熱緩存以及預熱查詢的執行時間必須短於commit的頻率,否則就會由於打開太多的searcher而造成commit失敗。
最後說說在工作中近實時搜索的感受吧,近實時搜索是相對的,對於有些客戶1分鐘就是近實時了,有些3分鐘就是近實時了。而對於Solr來說,softcommit越頻繁實時性更高,而softcommit越頻繁則Solr的負荷越大(commit越頻率越會生成小且多的segment,於是merge出現的更頻繁)。目前我們公司的softcommit頻率是3分鐘,之前設置過1分鐘而使得Solr在Index所占資源過多大大影響了查詢。所以近實時蠻困擾著我們的,因為客戶會不停的要求你更加實時,目前公司采用加入緩存機制來彌補這個實時性。
六、ShardSplit
有以下幾個配置參數:
· path,path是指core0索引最後切分好後存放的路徑,它支持多個,比如cores?action=SPLIT&core=core0&path=path1&path=path2。
· targetCore,就是將core0索引切分好後放入targetCore中(targetCore必須已經建立),它同樣支持多個,請註意path和targetCore兩個參數必須至少存在一個。
· split.key, 根據該key進行切分,默認為unique_id.
· ranges, 哈希區間,默認按切分個數進行均分。
· 由此可見Core的Split api是較底層的接口,它可以實現將一個core分成任意數量的索引(或者core)
七、負載均衡
查詢的負載均衡還是要自己做的。至於文檔放到哪個shard,就是按照id做的,如果是配置route.name=implicit,那麽自己指定去哪個shard。
八、故障恢復
1、故障恢復的情況
有幾種情況下會進行recovering :
(1)有下線的replica
當索引更新的時候,不會顧及下線的replica,當上線的時候會有recovery進程對他們進行回復,如果轉發的replica出於recovering狀態,那麽這個replica會把update放入update transaction日誌。
(2)如果shard(我覺得)只有一個replica
當只有一個Replica的時候,replica會進入recoveing狀態並持續一段時間等待leader重新上線,如果在這段時間內,leader沒有上線,replica會轉成leader並有一些文檔損失。
(3)SolrCloud在進行update時候,由於某種原因leader轉發update至replica沒有成功,會迫使replica進行recoverying進行數據同步。
2、Recovery策略
就上面的第三種,講講Recovery的策略:
(1)Peer sync, 如果中斷的時間較短,recovering node只是丟失少量update請求,那麽它可以從leader的update log中獲取。這個臨界值是100個update請求,如果大於100,就會從leader進行完整的索引快照恢復。
(2)Snapshot replication, 如果節點下線太久以至於不能從leader那進行同步,它就會使用solr的基於http進行索引的快照恢復。當你加入新的replica到shard中,它就會進行一個完整的index Snapshot。
3、兩種策略的具體過程
(1)整體的過程
solr 向所有的Replica發送getVersion的請求,獲取最新的nupdate個version(默認100個),並排序。獲取本分片的100個version。
對比replica和replica的version,看是不是有交集:
a)有交集,就部分更新Peer sync (按document為單位)
b)沒有交集,說明差距太大,那麽就replication (以文件為最小單位)
(2)replication的具體過程
(a)開始Replication的時候,首先進行一次commitOnLeader操作,即發送commit命令到leader。它的作用就是將leader的update中的數據刷入到索引文件中,使得快照snap完整。
(b)各種判斷之後,下載索引數據,進行replication
(c)replication的時候,shard狀態時recoverying,分片可以建索引但是不能查詢,同步的時候,新來的數據會進入ulog,但是這些數據從源碼看不會進入索引文件。當同步replication結束後,會進行replay過程,該過程就是將ulog中的請求重新進行一遍。這樣就可以把之前錯過的都再寫入。
4、容錯的其他方面
(1)讀
每個搜索的請求都被一個collection的所有的shards執行,如果有些shard沒有返回結果,那麽查詢是失敗的。這時候根據配置 shards.tolerant 參數,如果是true, 那麽部分結果會被返回。
(2)寫
每個節點的組織和內容的改變都會寫入Transaction log,日誌被用來決定節點中的哪些內容應該被包含在replica,當一個新的replica被創建的時候,通過leader和Transaction log去判斷哪些內容應該被包含。同時,這個log也可以用來恢復。TransactionLog由一個保存了一系列的更新操作的記錄構成,它能增加索引操作的健壯性,因為只要某個節點在索引操作過程中意外中斷了,它可以重做所有未提交的更新操作。
假如一個leader節點宕機了,可能它已經把請求發送到了一些replica節點但是卻另一些卻沒有發送,所以在一個新的leader節點在被選舉出來之前,它會依靠其他replica節點來運行一個同步處理操作。如果這個操作成功了的話,所有節點的數據就都保持一致了,然後leader節點把自己註冊為活動節點,普通的操作就會被處理。如果一個replica節點的數據脫離整體同步太多了的話,系統會請求執行一個全量的基於普通的replication同步恢復。
集群的overseer會監測各個shard的leader節點,如果leader節點掛了,則會啟動自動的容錯機制,會從同一個shard中的其他replica節點集中重新選舉出一個leader節點,甚至如果overseer節點自己也掛了,同樣會自動在其他節點上啟用新的overseer節點,這樣就確保了集群的高可用性。
九、選舉的策略
SolrCloud沒有master或slave. Leader被自動選舉,最初按照first-come-first-serve
然後按照zk的選舉方式。
http://zookeeper.apache.org/doc/trunk/recipes.html#sc_leaderElection
zk的選舉方式:zk給每個服務器一個id,新來的機器的id大於之前的。 如果leader宕機,所有的應用看著當前最小的編號,然後看每一個 follower 對 follower 集群中對應的比自己節點序號小一號的節點(也就是所有序號比自己小的節點中的序號最大的節點)設置一個 watch 。只有當follower 所設置的 watch 被觸發的時候,它才進行 Leader 選舉操作,一般情況下它將成為集群中的下一個 Leader。很明顯,此 Leader 選舉操作的速度是很快的。因為,每一次 Leader 選舉幾乎只涉及單個 follower 的操作。
12.SolrCloud原理