斷路器

Solr 的斷路器基礎架構允許防止導致節點超出其容量或當機的動作。斷路器的前提是確保更高的服務品質,並且僅接受目前資源設定中可服務的請求負載。

何時使用斷路器

當使用者希望犧牲請求輸送量以換取更高的 Solr 穩定性時,應使用斷路器。如果啟用斷路器,則在節點高度承壓的情況下,可能會拒絕請求,並顯示 HTTP 錯誤代碼 429「請求過多」。用戶端需要處理此錯誤,並可能建立重試邏輯,因為這應該是暫時的情況。

也可以在「僅警告」模式下啟用個別斷路器。已超出臨界值的「僅警告」斷路器會被記錄下來,但不會用於封鎖或短路請求。這可以用作調整斷路器臨界值而不影響流量的一種方式。

在向分片集合發出的請求中,斷路器僅在處理初始請求的節點上檢查,而不檢查節點間的請求。因此,建議跨 Solr 節點對用戶端請求進行負載平衡,以避免熱點。

斷路器設定

斷路器可以針對整個節點全域設定,或針對每個集合個別設定,或兩者組合。每個集合的斷路器會在全域斷路器之前檢查,如果發生衝突,則以每個集合的斷路器為優先。通常,任何每個集合的斷路器臨界值都設定得低於全域臨界值。

斷路器可以註冊本身以檢查查詢請求和/或更新請求。使用者可以為每個請求類型註冊具有不同臨界值的相同類型的斷路器。

全域斷路器

可以使用環境變數(例如,在 solr.in.sh 中)或系統屬性,全域設定斷路器。可用的變數如下:

名稱 環境變數名稱 系統屬性名稱

JVM 堆積使用率

SOLR_CIRCUITBREAKER_QUERY_MEMSOLR_CIRCUITBREAKER_UPDATE_MEM

solr.circuitbreaker.query.memsolr.circuitbreaker.update.mem

系統 CPU 使用率

SOLR_CIRCUITBREAKER_QUERY_CPUSOLR_CIRCUITBREAKER_UPDATE_CPU

solr.circuitbreaker.query.cpusolr.circuitbreaker.update.cpu

系統負載平均

SOLR_CIRCUITBREAKER_QUERY_LOADAVGSOLR_CIRCUITBREAKER_UPDATE_LOADAVG

solr.circuitbreaker.query.loadavgsolr.circuitbreaker.update.loadavg

可以透過新增帶有布林值的「warnonly」後綴環境變數或系統屬性,在「僅警告」模式下設定斷路器。

例如,您可以透過設定以下環境變數:SOLR_CIRCUITBREAKER_UPDATE_CPU=95,來啟用全域 CPU 斷路器,該斷路器會在 CPU 負載高於 95% 時拒絕更新請求。如果希望此斷路器採用「僅警告」模式,則可以設定 SOLR_CIRCUITBREAKER_UPDATE_CPU_WARNONLY=true 環境變數或 solr.circuitbreaker.update.cpu.warnonly=true 系統屬性。

每個集合的斷路器

斷路器會在 solrconfig.xml 中設定為獨立的 <circuitBreaker> 項目,如下面的範例所示。預設情況下,僅影響搜尋請求。可用設定選項的語法和語意會根據設定的斷路器類型而略有不同。但是,所有斷路器都支援布林值「warnOnly」設定,可用於將斷路器設定為「僅警告」模式(例如,<bool name="warnOnly">true</bool>)。

目前支援的斷路器

使用 CircuitBreakerManager 的傳統組態語法已在 Solr 9.4 版本中棄用,但仍會繼續運作。當設定 cpuThreshold 時,此傳統外掛程式使用的「CPU」斷路器實際上是以下描述的 LoadAverageCircuitBreaker。此外,CircuitBreakerManager 將會回傳 HTTP 503 錯誤碼,而非新斷路器使用的 HTTP 429 錯誤碼。

JVM 堆積使用率

此斷路器追蹤 JVM 堆積記憶體使用率,如果堆積使用率超過為 JVM 配置的最大堆積 (-Xmx) 的設定百分比,則會拒絕帶有 429 錯誤碼的傳入請求。此斷路器的主要組態是控制斷路器跳脫的閾值百分比。

若要啟用並組態基於 JVM 堆積使用率的斷路器,請新增以下內容

solrconfig.xml 中針對每個集合設定
<circuitBreaker class="org.apache.solr.util.circuitbreaker.MemoryCircuitBreaker">
 <double name="threshold">75</double>
</circuitBreaker>
solr.in.sh 中全域設定
SOLR_CIRCUITBREAKER_QUERY_MEM=75

threshold 定義為分配給 JVM 的最大堆積的百分比。

對於斷路器組態,值「0」對應於 0% 使用率,而值「100」對應於 100% 使用率。

將閾值設定為低於 JVM 配置的最大堆積的 50% 或高於 95%,在邏輯上沒有意義。因此,此參數的有效值範圍為 [50, 95],包括兩個端點。

請考慮以下範例

JVM 已分配最大堆積 5GB (-Xmx),且 threshold 設定為 75。在這種情況下,斷路器跳脫時的堆積使用率為 3.75GB。

系統 CPU 使用率斷路器

此斷路器追蹤系統 CPU 使用率,如果最近的 CPU 使用率超過可設定的閾值,則會觸發。

這是透過 JMX 指標 OperatingSystemMXBean.getSystemCpuLoad() 追蹤的。該指標測量整個系統最近的 CPU 使用率。此指標由 com.sun.management 套件提供,該套件並非在所有 JVM 上都實作。如果指標不可用,則斷路器將會停用並記錄錯誤訊息。另一種選擇是使用系統負載平均斷路器

若要啟用並組態基於 CPU 使用率的斷路器

solrconfig.xml 中針對每個集合設定
<circuitBreaker class="org.apache.solr.util.circuitbreaker.CPUCircuitBreaker">
 <double  name="threshold">75</double>
</circuitBreaker>
solr.in.sh 中全域設定
SOLR_CIRCUITBREAKER_QUERY_CPU=75

觸發閾值定義為 CPU 使用率的百分比。值「0」對應於 0% 使用率,而值「100」對應於 100% 使用率。以上範例會在 CPU 使用率等於或大於 75% 時觸發。

系統負載平均斷路器

此斷路器追蹤系統負載平均值,如果最近的負載平均值超過可設定的閾值,則會觸發。

這是透過 JMX 指標 OperatingSystemMXBean.getSystemLoadAverage() 追蹤的。該指標測量整個系統最近的負載平均值。「負載平均值」是使用 CPU 或等待 CPU 的處理程序數量,通常平均為一分鐘。某些系統將等待 IO 的處理程序包含在負載平均值中。請查看您的系統和 JVM 的文件以了解此指標。如需更多資訊,請參閱維基百科的負載頁面

若要啟用並組態負載平均斷路器

solrconfig.xml 中針對每個集合設定
<circuitBreaker class="org.apache.solr.util.circuitbreaker.LoadAverageCircuitBreaker">
 <double  name="threshold">8.0</double>
</circuitBreaker>
solr.in.sh 中全域設定
SOLR_CIRCUITBREAKER_QUERY_LOADAVG=8.0

觸發閾值是一個與負載平均值相符的浮點數。以上範例斷路器會在負載平均值等於或大於 8.0 時觸發。

系統負載平均斷路器的行為取決於作業系統,可能無法在某些作業系統(如 Microsoft Windows)上運作。如需更多資訊,請參閱JavaDoc

進階範例

在此範例中,我們將阻止 CPU 負載超過 80% 的更新請求,並阻止 CPU 負載超過 95% 的查詢請求。支援的請求類型為 queryupdate。這可以防止昂貴的批次更新影響搜尋。請注意,也支援簡短的類別名稱。

solrconfig.xml 中針對每個集合設定
<config>
  <circuitBreaker class="solr.CPUCircuitBreaker">
   <double  name="threshold">80</double>
   <arr name="requestTypes">
     <str>update</str>
   </arr>
  </circuitBreaker>

  <circuitBreaker class="solr.CPUCircuitBreaker">
   <double  name="threshold">95</double>
   <arr name="requestTypes">
     <str>query</str>
   </arr>
  </circuitBreaker>
</config>
solr.in.sh 中全域設定
SOLR_CIRCUITBREAKER_UPDATE_CPU=80
SOLR_CIRCUITBREAKER_QUERY_CPU=95

效能考量

雖然 JVM 或 CPU 斷路器不會為每個請求增加任何明顯的額外負擔,但為單個請求檢查過多的斷路器可能會導致效能開銷。

此外,在繁忙節點上重試請求時,採用指數退避 (exponential backoff) 是一種良好的做法。請參閱維基百科關於指數退避的頁面