SolrCloud 分片與索引
當您的集合對於單一節點來說太大時,您可以透過建立多個分片來將其分割並儲存於各區段。
分片是集合的邏輯分割區,其中包含集合中文件的子集,因此集合中的每個文件都只包含在一個分片中。哪個分片包含集合中的每個文件取決於該集合的整體分片策略。
例如,您可能有一個集合,其中每個文件的「國家」欄位決定它屬於哪個分片,因此來自同一個國家的文件會位於相同位置。不同的集合可能只是使用每個文件 uniqueKey 的「雜湊」來決定其分片。
在 SolrCloud 之前,Solr 支援分散式搜尋,它允許在多個分片中執行一個查詢,因此查詢會針對整個 Solr 索引執行,且搜尋結果中不會遺漏任何文件。因此,跨分片分割索引並非 SolrCloud 獨有的概念。然而,分散式方法存在一些問題,需要透過 SolrCloud 進行改進
-
將索引分割成分片有些人工操作。
-
沒有支援分散式索引,這表示您需要明確地將文件傳送到特定的分片;Solr 無法自行判斷要將文件傳送到哪個分片。
-
沒有負載平衡或容錯移轉,因此如果您收到大量的查詢,您需要找出要將它們傳送到哪裡,並且如果一個分片失效,它就消失了。
SolrCloud 解決了這些限制。它支援自動分配索引程序和查詢,並且 ZooKeeper 提供容錯移轉和負載平衡。此外,每個分片可以有多個副本以增加可靠性。
領導者與副本
在 SolrCloud 中,沒有領導者或追隨者。相反地,每個分片都包含至少一個實體副本,其中恰好一個是領導者。領導者會自動選出,最初是先到先得,然後根據 https://zookeeper.dev.org.tw/doc/r3.9.2/recipes.html#sc_leaderElection 中描述的 ZooKeeper 程序選出。
如果領導者失效,其他副本之一會自動選為新的領導者。
當文件傳送到 Solr 節點進行索引時,系統會先判斷該文件屬於哪個分片,然後判斷哪個節點目前正在託管該分片的領導者。然後將文件轉送到目前的領導者進行索引,而領導者會將更新轉送到所有其他副本。
副本類型
預設情況下,如果領導者失效,所有副本都有資格成為領導者。但是,這是有代價的:如果所有副本都可以在任何時候成為領導者,則每個副本都必須隨時與其領導者同步。新增至領導者的新文件必須路由到副本,並且每個副本都必須執行提交。如果副本失效或暫時無法使用,然後重新加入叢集,如果它遺失了大量的更新,復原可能會很慢。
這些問題對於大多數使用者來說不是問題。但是,某些使用案例如果副本的行為更像以前的模型(例如,不即時同步或完全沒有資格成為領導者),則效能會更好。
Solr 允許您在建立新集合或新增副本時設定副本類型,藉此解決這個問題。可用的類型如下
-
NRT:這是預設值。NRT 副本 (NRT = 近即時) 會維護交易日誌,並將新的文件寫入其本機索引。任何此類型的副本都有資格成為領導者。傳統上,這是 Solr 唯一支援的類型。
-
TLOG:此類型的副本會維護交易日誌,但不會在本機為文件變更建立索引。此類型有助於加速索引建立,因為副本中不需要執行提交作業。當此類型的副本需要更新其索引時,它會從領導者複製索引。此類型的副本也有資格成為分片領導者;它會先處理其交易日誌來執行此操作。如果它確實成為領導者,其行為將與 NRT 類型的副本相同。
-
PULL:此類型的副本不會維護交易日誌,也不會在本地為文件變更建立索引。它只會從分片領導者複製索引。它沒有資格成為分片領導者,並且根本不參與分片領導者選舉。
如果您在建立副本時未指定副本類型,則會預設為 NRT 類型。
使用 PULL 副本進行復原
如果 PULL 副本當機或離開叢集,則需要考慮幾種情況。
如果 PULL 副本因為領導者當機而無法與領導者同步,則不會發生複製。但是,它會繼續提供查詢。一旦它可以再次連接到領導者,複製就會恢復。
如果 PULL 副本無法連接到 ZooKeeper,則會從叢集中移除,並且叢集不會將查詢路由到它。
如果 PULL 副本當機或因任何其他原因無法連線,則它將無法查詢。當它重新加入叢集時,它會從領導者複製,並且在完成後,它就可以再次提供查詢。
具有偏好副本類型的查詢
預設情況下,所有副本都會提供查詢。請參閱 shards.preference 參數一節,以了解如何指示查詢的偏好副本類型。
文件路由
Solr 允許在建立集合時指定 router.name
參數,來指定集合使用的路由器實作。
如果您使用 compositeId
路由器(預設值),則可以使用文件 ID 中的前綴來傳送文件,該前綴將用於計算 Solr 用來決定將文件傳送到哪個分片以進行索引的雜湊。前綴可以是您想要的任何內容(例如,它不一定是分片名稱),但它必須一致,以便 Solr 行為保持一致。
例如,如果您想要為客戶並置文件,則可以使用客戶名稱或 ID 作為前綴。例如,如果您的客戶是「IBM」,文件 ID 為「12345」,則您會在文件 ID 欄位中插入前綴:「IBM!12345」。驚嘆號 ('!') 在此處至關重要,因為它可以區分用於決定將文件導向哪個分片的前綴。
然後在查詢時,您可以使用 _route_
參數在查詢中包含前綴 (例如,q=solr&_route_=IBM!
),以將查詢導向特定分片。在某些情況下,這可能會提高查詢效能,因為它可以克服查詢所有分片時的網路延遲。
compositeId
路由器支援包含最多 2 個路由層級的前綴。例如:前綴首先按地區路由,然後按客戶路由:「USA!IBM!12345」
另一個用例可能是如果客戶「IBM」有很多文件,並且您想要將其分散到多個分片中。此類用例的語法將是:shard_key/num!document_id
,其中 /num
是要用於複合雜湊的分片金鑰位數。
因此,IBM/3!12345
將從分片金鑰中取出 3 位元,並從唯一的文檔 ID 中取出 29 位元,將租戶分散到集合中 1/8 的分片。同樣地,如果 num 值為 2,則會將文件分散到 1/4 的分片數。在查詢時,您可以使用 _route_
參數在查詢中包含前綴以及位數 (例如,q=solr&_route_=IBM/3!
),以將查詢導向特定分片。
如果您不想影響文件的儲存方式,則不需要在文件 ID 中指定前綴。
如果您在建立集合時定義了「implicit」路由器,則可以另外定義 router.field
參數,以使用每個文件中的欄位來識別文件所屬的分片。但是,如果文件中缺少指定的欄位,則會拒絕該文件。您也可以使用 _route_
參數來命名特定的分片。
分片分割
當您在 SolrCloud 中建立集合時,您會決定要使用的初始分片數量。但是,很難提前知道您需要的分片數量,特別是當組織需求可能會隨時變更時,以及稍後發現您選擇錯誤的成本可能很高,包括建立新的核心和重新索引您的所有資料。
分割分片的功能在 Collections API 中。它目前允許將一個分片分割成兩部分。現有的分片會保持原樣,因此分割動作實際上會將資料複製兩份作為新的分片。您可以在準備就緒後,稍後刪除舊的分片。
有關如何使用分片分割的更多詳細資訊,請參閱 Collection API 的 SPLITSHARD 命令一節。
在 SolrCloud 中忽略來自用戶端應用程式的提交
在大多數情況下,在 SolrCloud 模式下執行時,索引用戶端應用程式不應傳送明確的提交請求。相反地,您應該使用 openSearcher=false
和 autoSoftCommit
來設定自動提交,以便在搜尋請求中顯示最近的更新。這可確保自動提交會定期在叢集中發生。
使用 autoSoftCommit 或 commitWithin 需要用戶端應用程式接受「最終一致性」的事實。Solr 會在大約相同的時間在集合的副本中使文件可搜尋,但沒有明確的保證。因此,在極少數情況下,文件可能會在一次搜尋中顯示,但在稍後發生且路由到不同副本的第二次搜尋中沒有顯示。此外,當有分片時,以特定順序新增的文件(即使在同一批次中)可能會在提交順序之外變成可搜尋。在下一個 autoCommit 或 commitWithin 間隔到期後,文件將在分片的所有副本中可見。 |
若要強制執行用戶端應用程式不應傳送明確提交的原則,您應該更新所有將資料索引到 SolrCloud 的用戶端應用程式。但是,這並非總是可行的,因此 Solr 提供了 IgnoreCommitOptimizeUpdateProcessorFactory
,允許您忽略來自用戶端應用程式的明確提交和/或最佳化請求,而無需重構您的用戶端應用程式碼。
若要啟用此請求處理器,您需要在您的 solrconfig.xml
中新增以下內容
<updateRequestProcessorChain name="ignore-commit-from-client" default="true">
<processor class="solr.IgnoreCommitOptimizeUpdateProcessorFactory">
<int name="statusCode">200</int>
</processor>
<processor class="solr.LogUpdateProcessorFactory" />
<processor class="solr.DistributedUpdateProcessorFactory" />
<processor class="solr.RunUpdateProcessorFactory" />
</updateRequestProcessorChain>
如上例所示,處理器會向用戶端傳回 200,但會忽略提交或最佳化請求。請注意,您也需要接線 SolrCloud 所需的隱式處理器,因為此自訂鏈取代了預設鏈。
在以下範例中,處理器將會引發例外狀況,並傳回 403 代碼和自訂錯誤訊息
<updateRequestProcessorChain name="ignore-commit-from-client" default="true">
<processor class="solr.IgnoreCommitOptimizeUpdateProcessorFactory">
<int name="statusCode">403</int>
<str name="responseMessage">Thou shall not issue a commit!</str>
</processor>
<processor class="solr.LogUpdateProcessorFactory" />
<processor class="solr.DistributedUpdateProcessorFactory" />
<processor class="solr.RunUpdateProcessorFactory" />
</updateRequestProcessorChain>
最後,您也可以將其設定為僅忽略最佳化並讓提交通過,方法是執行以下操作
<updateRequestProcessorChain name="ignore-optimize-only-from-client-403">
<processor class="solr.IgnoreCommitOptimizeUpdateProcessorFactory">
<str name="responseMessage">Thou shall not issue an optimize, but commits are OK!</str>
<bool name="ignoreOptimizeOnly">true</bool>
</processor>
<processor class="solr.RunUpdateProcessorFactory" />
</updateRequestProcessorChain>