SolrCloud 分散式請求

當 Solr 節點收到搜尋請求時,該請求會自動路由到正在搜尋的集合中分片的副本。

選定的副本會作為彙總器:它會建立對集合中每個分片隨機選取的副本的內部請求、協調回應、根據需要發出任何後續內部請求(例如,為了細化分面值,或請求額外的儲存欄位),並為用戶端建構最終回應。

查詢容錯

在 SolrCloud 叢集中,每個個別節點會在集合中的所有副本之間負載平衡讀取請求。您可能仍然需要在與叢集交談的「外部」負載平衡器。或者,您需要一個瞭解如何讀取和與 ZooKeeper 中的 Solr 中繼資料互動的用戶端,並且僅請求 ZooKeeper 集群的位址以探索應該接收請求的節點。Solr 提供一個名為 CloudSolrClient 的智慧型 Java SolrJ 用戶端,它能夠做到這一點。

即使叢集中的某些節點離線或無法連線,只要 Solr 節點可以與每個分片的至少一個副本通訊,或者如果使用者透過 shards_route_ 參數限制搜尋,則可以與每個相關分片的至少一個副本通訊,就可以正確回應搜尋請求。每個分片的副本越多,Solr 叢集就越有可能在節點故障時處理搜尋結果。

zkConnected 參數

只要 Solr 節點可以與它知道的每個分片的至少一個副本通訊,即使它在收到請求時無法與 ZooKeeper 通訊,它也會傳回搜尋請求的結果。從容錯的角度來看,這通常是較佳的行為,但是如果節點尚未透過 ZooKeeper 獲知對集合結構的重大變更(即,可能已新增或移除分片,或分割成分片),可能會導致陳舊或不正確的結果。

每個搜尋回應都會包含一個 zkConnected 標頭,指出處理請求的節點在當時是否已連線至 ZooKeeper。

包含 zkConnected 的 Solr 回應
{
  "responseHeader": {
    "status": 0,
    "zkConnected": true,
    "QTime": 20,
    "params": {
      "q": "*:*"
    }
  },
  "response": {
    "numFound": 107,
    "start": 0,
    "docs": [ "..." ]
  }
}

為了避免在提供請求的節點無法與 ZooKeeper 通訊時產生過時或不正確的結果,請將 shards.tolerant 參數設定為 requireZkConnected。這樣做會導致請求失敗,而不是將 zkConnected 標頭設定為 false

shards.tolerant 參數

如果一個或多個查詢的分片不可用,Solr 的預設行為是讓請求失敗。但是,在許多情況下,部分結果是可以接受的,因此 Solr 提供了一個布林值 shards.tolerant 參數(預設為 false)。除了 truefalse 之外,shards.tolerant 也可以設定為 requireZkConnected - 請參閱下文。

如果 shards.tolerant=true,則可能會返回部分結果。如果返回的回應不包含來自所有適當分片的結果,則回應標頭會包含一個名為 partialResults 的特殊標記。

如果 shards.tolerant=requireZkConnected,並且提供搜尋請求的節點無法與 ZooKeeper 通訊,則請求將會失敗,而不是返回可能過時或不正確的結果。當一個或多個查詢的分片完全不可用時,這也會導致請求失敗,就像 shards.tolerant=false 時一樣。

客戶端可以指定 shards.info 以及 shards.tolerant 參數來檢索更詳細的資訊。

範例回應,其中 partialResults 標記設定為 true

包含 partialResults 的 Solr 回應
{
  "responseHeader": {
    "status": 0,
    "zkConnected": true,
    "partialResults": true,
    "QTime": 20,
    "params": {
      "q": "*:*"
    }
  },
  "response": {
    "numFound": 77,
    "start": 0,
    "docs": [ "..." ]
  }
}

distrib.singlePass 參數

如果設定為 truedistrib.singlePass 參數會變更分散式搜尋演算法,以便在第一階段本身從每個分片提取所有請求的儲存欄位。這消除了第二次請求提取儲存欄位的需要。

當請求的欄位數量非常少且包含小數值時,這可能會更快。但是,如果請求的欄位很大或請求的欄位很多,那麼從所有分片透過網路提取這些欄位的額外負擔可能會使請求比正常分散式搜尋路徑慢。

請注意,此最佳化僅適用於分散式搜尋。某些功能(如 Faceting)可能會為改進等項目發出額外的網路請求。

路由查詢

有多種方式可以控制查詢的路由方式。

限制查詢的分片

雖然使用 SolrCloud 的優勢之一是能夠查詢分佈在各個分片上的非常大的集合,但在某些情況下,您可能已使用特定的 文件路由 設定 Solr。您可以選擇搜尋所有資料或僅搜尋部分資料。

由於 SolrCloud 會自動執行查詢負載平衡,因此對集合的所有分片的查詢只是一個沒有定義 shards 參數的查詢。

https://127.0.0.1:8983/solr/gettingstarted/select?q=*:*

這與使用者管理的叢集相反,在使用者管理的叢集中,需要 shards 參數才能分配查詢。

若要將查詢限制為僅一個分片,請使用 shards 參數按其邏輯 ID 指定分片,如下所示:

https://127.0.0.1:8983/solr/gettingstarted/select?q=*:*&shards=shard1

如果要搜尋一組分片,您可以在一個請求中指定每個分片,並用逗號分隔

https://127.0.0.1:8983/solr/gettingstarted/select?q=*:*&shards=shard1,shard2

在上述兩個範例中,雖然僅查詢特定的分片,但分片的任何隨機副本都會收到請求。

您可以改為指定要使用的副本清單,而不是分片 ID,方法是以逗號分隔副本 ID

https://127.0.0.1:8983/solr/gettingstarted/select?q=*:*&shards=localhost:7574/solr/gettingstarted,localhost:8983/solr/gettingstarted

或者,您可以指定要從單一分片中選擇的副本清單(用於負載平衡),方法是在不同的副本 ID 之間使用管道符號 (|)

https://127.0.0.1:8983/solr/gettingstarted/select?q=*:*&shards=localhost:7574/solr/gettingstarted|localhost:7500/solr/gettingstarted

最後,您可以指定分片清單(以逗號分隔),每個分片由副本清單(以管道分隔)定義。

在以下範例中,會查詢 2 個分片,第一個是來自 shard1 的隨機副本,第二個是來自明確管道分隔清單的隨機副本

https://127.0.0.1:8983/solr/gettingstarted/select?q=*:*&shards=shard1,localhost:7574/solr/gettingstarted|localhost:7500/solr/gettingstarted

shards.preference 參數

Solr 允許您傳遞一個名為 shards.preference 的可選字串參數,以指示分散式查詢應在每個分片內按給定的優先順序對可用副本進行排序。

語法為:shards.preference=property:value。屬性和值的順序很重要:第一個是主要排序,第二個是次要排序,依此類推。

shards.preference 僅在使用 SolrJ 用戶端時才支援單一分片情境。不使用 SolrJ 用戶端的查詢無法在單一分片集合中使用 shards.preference

可以指定的屬性如下

replica.type

一個或多個優先的副本類型。允許使用 PULLTLOGNRT 的任意組合。

replica.location

一個或多個優先的副本位置。

位置以 http://hostname:port 開頭。會將給定的字串當作前置詞進行比對,因此可以例如省略連接埠。

特殊值 local 可以用來表示任何與處理查詢的 Solr 執行個體在同一個執行個體上執行的本機副本。當查詢請求每個文件返回許多欄位或大型欄位時,這很有用,因為它可以避免在本機可用時透過網路移動大量資料。此外,此功能可用於最小化效能降低的問題副本的影響,因為它降低了有問題的副本被其他健全副本擊中的可能性。

當集合中沒有本機可用副本的分片數量增加時,replica.location:local 的值會減少,因為查詢控制器必須將查詢導向到大多數分片的非本機副本。

換句話說,此功能主要用於最佳化導向到分片數量少且副本多的集合的查詢。

此外,此選項僅應在您跨所有主機集合副本的節點執行負載平衡請求時使用,因為 Solr 的 CloudSolrClient 會這樣做。如果不進行負載平衡,此功能可能會在叢集中引入熱點,因為查詢不會均勻地分佈在整個叢集中。

replica.base

在按固有副本屬性排序後套用,此屬性定義優先順序相等的副本集之間的後備排序;如果指定,則此屬性只能指定一個值,並且必須最後指定。

random 是預設值,會隨機為每個請求重新排序副本。這會平均分發請求,但可能會導致複寫係數 > 1 的分片出現次佳的快取使用。

stable:dividend:_paramName_ 從與給定參數名稱關聯的值中剖析整數;此整數用作除數(mod 相等副本計數),以決定(透過清單旋轉)相等副本之間的優先順序。

stable[:hash[:_paramName_]] 與給定參數名稱關聯的字串值會雜湊為除數,該除數用於決定副本優先順序(類似於上面的明確 dividend 屬性);如果未指定,paramName 預設為 q,提供以「主要查詢」字串值為鍵的穩定路由。請注意,這可能不適用於某些使用案例(例如,利用參數替代的靜態主要查詢)

replica.leader

根據副本的領導者狀態設定為 truefalse,優先選擇副本。

考量一個具有兩個 TLOG 副本和四個 PULL 副本(總共六個副本,其中一個是領導者)的分片。使用 shards.preference=replica.leader:false,將優先選擇 6 個副本中的 5 個。將此與 shards.preference=replica.type:PULL 進行比較,後者只會優先選擇 6 個副本中的 4 個。

請注意,從搜尋角度來看,非領導者 TLOG 副本的行為類似於 PULL 副本;它像 PULL 副本一樣從領導者提取索引更新,並且不執行軟提交。差異在於非領導者 TLOG 副本也會在其 TLOG 中擷取更新,因此如果目前的領導者遺失,它會成為取代目前的領導者的候選項。

node.sysprop

查詢將路由到與目前查詢具有相同定義的系統屬性的節點。例如,如果您在不同的機架上啟動 Solr 節點,您會想使用 系統屬性(例如 -Drack=rack1)來識別這些節點。然後,查詢可以包含 shards.preference=node.sysprop:sysprop.rack,以確保您始終命中 rack 值相同的分片。

範例:

  • 在其他等效副本之間偏好穩定路由(以用戶端「sessionId」參數為鍵)

    shards.preference=replica.base:stable:hash:sessionId&sessionId=abc123
  • 偏好 PULL 副本

    shards.preference=replica.type:PULL
  • 偏好 PULL 副本,如果 PULL 副本不可用,則偏好 TLOG 副本

    shards.preference=replica.type:PULL,replica.type:TLOG
  • 偏好任何本機副本

    shards.preference=replica.location:local
  • 偏好主機名為「server1」上的任何副本,並將「server2」作為次要選項

    shards.preference=replica.location:http://server1,replica.location:http://server2
  • 如果可用,則偏好 PULL 副本,否則偏好 TLOG 副本,以及其中的本機副本

    shards.preference=replica.type:PULL,replica.type:TLOG,replica.location:local
  • 偏好本機副本,以及其中的 PULL 副本(如果可用),否則偏好 TLOG 副本

    shards.preference=replica.location:local,replica.type:PULL,replica.type:TLOG
  • 偏好任何不是領導者的副本

    shards.preference=replica.leader:false

請注意,如果您在查詢字串中提供這些參數,則需要正確進行 URL 編碼。

collection 參數

collection 參數允許您指定應執行查詢的集合或多個集合。這讓您可以一次查詢多個集合,並且 Solr 以分散式方式運作的功能將跨集合運作。

https://127.0.0.1:8983/solr/collection1/select?collection=collection1,collection2,collection3

_route_ 參數

_route_ 參數可用於指定路由鍵,該路由鍵用於確定對應的分片。例如,如果您的文件具有唯一的鍵 "user1!123",則指定路由鍵為 "route=user1!"(請注意結尾的 '!' 字元)會將請求路由到託管該使用者的分片。您可以指定多個以逗號分隔的路由鍵。當我們按使用者劃分分片資料時,可以使用此參數。有關更多資訊,請參閱文件路由

https://127.0.0.1:8983/solr/collection1/select?q=*:*&_route_=user1!
https://127.0.0.1:8983/solr/collection1/select?q=*:*&_route_=user1!,user2!

近即時 (NRT) 使用案例

近即時 (NRT) 搜尋表示文件在索引後不久即可用於搜尋。NRT 搜尋是 SolrCloud 的主要功能之一,在使用者管理的叢集或單節點安裝中很少嘗試。

文件的持久性和可搜尋性由 commits 控制。「近即時」中的「近」是可配置的,以滿足您的應用程式的需求。Commit 可以是「硬性」或「軟性」的,並且可以由客戶端(例如 SolrJ)通過 REST 呼叫發出,或者配置為在 solrconfig.xml 中自動發生。通常建議在 solrconfig.xml 中配置您的 commit 策略(如下所示),並避免從外部發出 commit。

通常在 NRT 應用程式中,硬性 commit 會配置 openSearcher=false,而軟性 commit 則會配置為使文件可見以進行搜尋。

當發生 commit 時,會啟動各種背景任務,例如段合併。這些背景任務不會阻止對索引的額外更新,也不會延遲文件可用於搜尋的時間。

在配置 NRT 時,請特別注意快取和自動預熱設定,因為它們可能會對 NRT 效能產生重大影響。對於極短的 autoCommit 間隔,請考慮完全停用快取和自動預熱。

配置 ShardHandlerFactory

為了更精細的控制,您可以直接配置和調整 Solr 中分散式搜尋內使用的並行性和執行緒池的各個方面。預設配置傾向於吞吐量而不是延遲。

這是透過在搜尋處理程式的配置中定義 shardHandlerFactory 來完成的。

若要將 shardHandlerFactory 新增到標準搜尋處理程式,請在 solrconfig.xml 中提供配置,如此範例所示

<requestHandler name="/select" class="solr.SearchHandler">
  <!-- other params go here -->
  <shardHandlerFactory class="HttpShardHandlerFactory">
    <int name="socketTimeout">1000</int>
    <int name="connTimeout">5000</int>
  </shardHandlerFactory>
</requestHandler>

HttpShardHandlerFactory 是 Solr 隨附的唯一 ShardHandlerFactory 實作。

注意

shardHandlerFactory 依賴於 solr.xml 中配置的 allowUrls 參數,該參數控制允許哪些節點彼此通訊。這表示主機的配置是全域性的,而不是每個核心或每個集合。有關詳細資訊,請參閱allowUrls章節。

HttpShardHandlerFactory 接受以下參數

socketTimeout

選填

預設值:0

允許 socket 等待的時間,以毫秒為單位。預設值為 0,將使用作業系統的預設值。

connTimeout

選填

預設值:0

連接或綁定 socket 可接受的時間,以毫秒為單位。預設值為 0,將使用作業系統的預設值。

maxConnectionsPerHost

選填

預設值:100000

分散式搜尋中與每個個別分片建立的最大並行連線數。

corePoolSize

選填

預設值:0

用於協調分散式搜尋的執行緒數的保留最低限制。

maximumPoolSize

選填

預設值:Integer.MAX_VALUE

用於協調分散式搜尋的最大執行緒數。

maxThreadIdleTime

選填

預設值:5

在因負載減少而縮減執行緒之前等待的時間,以秒為單位。

sizeOfQueue

選填

預設值:-1

如果指定,執行緒池將使用後端佇列而不是直接交接緩衝區。高吞吐量系統會希望將此設定為直接交接 (使用 -1)。希望獲得更好延遲的系統會希望配置合理大小的佇列以處理請求的變化。

fairnessPolicy

選填

預設值:false

選擇處理公平策略佇列的 JVM 特定設定。如果啟用,分散式搜尋將以先進先出的方式處理,但會犧牲吞吐量。如果停用,則會優先考慮吞吐量而不是延遲。

分散式反向文件頻率 (IDF)

為了計算相關性,需要文件和詞彙統計資料。在分散式系統中,這些統計資料可能因節點而異,從而在評分計算中引入偏差或不準確性。

Solr 將文件和詞彙統計資料儲存在名為 statsCache 的快取中。在文件統計資料計算方面,有四種現成的實作:

  • LocalStatsCache:這只使用本機詞彙和文件統計資料來計算相關性。在跨分片具有一致詞彙分佈的情況下,這效果相當不錯。如果未配置任何 <statsCache>,則此選項為預設選項。

  • ExactStatsCache:此實作使用文件頻率的全域值(跨集合)。如果跨節點的精確評分對您的實作非常重要,建議選擇此選項。

  • ExactSharedStatsCache:其功能與 ExactStatsCache 類似,但全域統計資料會重複用於具有相同詞彙的後續請求。

  • LRUStatsCache:此實作使用最近最少使用的快取來保存全域統計資料,這些統計資料在請求之間共用。

可以透過在 solrconfig.xml 中設定 <statsCache> 來選擇實作。例如,以下行使 Solr 使用 ExactStatsCache 實作

<statsCache class="org.apache.solr.search.stats.ExactStatsCache"/>

distrib.statsCache 參數

查詢參數 distrib.statsCache 預設為 true。如果設定為 false,則會關閉此查詢的分散式呼叫以擷取全域詞彙統計資料。這可以減少不使用分散式 IDF 進行分數計算的查詢的額外負荷。

https://127.0.0.1:8987/solr/collection1/select?q=*%3A*&wt=json&fq={!terms f=id}id1,id2&distrib.statsCache=false

避免分散式死鎖

每個分片都處理最上層的查詢請求,然後向所有其他分片發出子請求。應注意確保為 HTTP 請求提供服務的最大執行緒數大於來自最上層客戶端和其他分片的可能請求數。如果情況並非如此,則配置可能會導致分散式死鎖。

例如,在兩個分片的情況下,每個分片只有一個執行緒為 HTTP 請求提供服務,可能會發生死鎖。兩個執行緒可能會同時接收到最上層的請求,並互相發出子請求。由於沒有剩餘的執行緒為請求提供服務,因此傳入的請求將被封鎖,直到其他擱置的請求完成,但由於它們正在等待子請求,因此它們不會完成。通過確保將 Solr 配置為處理足夠數量的執行緒,您可以避免這種死鎖情況。

分散式追蹤和除錯

debug 參數的值為 track,可用於追蹤請求,以及尋找分散式請求的每個階段的計時資訊。