ElasticSearch 429 Too Many Requests circuit_breaking_exception


  • 錯誤提示
{
  "statusCode": 429,
  "error": "Too Many Requests",
  "message": "[circuit_breaking_exception] 
  [parent] Data too large, data for [<http_request>] would be [2087772160/1.9gb], 
  which is larger than the limit of [1503238553/1.3gb], 
  real usage: [2087772160/1.9gb],
  new bytes reserved: [0/0b], 
  usages [request=0/0b, fielddata=1219/1.1kb, in_flight_requests=0/0b, accounting=605971/591.7kb], 
  with { bytes_wanted=2087772160 & bytes_limit=1503238553 & durability=\"PERMANENT\" }"
}

重要解決辦法
關閉circuit檢查:

indices.breaker.type: none

集群config/jvm.options設置如下

-Xms2g
-Xmx2g

#-XX:+UseConcMarkSweepGC
-XX:+UseG1GC
-XX:CMSInitiatingOccupancyFraction=75
-XX:+UseCMSInitiatingOccupancyOnly

以下這些都不用看了

再嘗試其他查詢也是如此。經排查,原來是ES默認的緩存設置讓緩存區只進不出引起的,具體分析一下。

  • ES緩存區概述
    ES在查詢時,會將索引數據緩存在內存(JVM)中:

上圖是ES的JVM Heap中的狀況,可以看到有兩條界限:驅逐線 和 斷路器。當緩存數據到達驅逐線時,會自動驅逐掉部分數據,把緩存保持在安全的范圍內。
當用戶准備執行某個查詢操作時,斷路器就起作用了,緩存數據+當前查詢需要緩存的數據量到達斷路器限制時,會返回Data too large錯誤,阻止用戶進行這個查詢操作。

ES把緩存數據分成兩類,FieldData和其他數據,我們接下來詳細看FieldData,它是造成我們這次異常的“元凶”。

  • FieldData
    ES配置中提到的FieldData指的是字段數據。當排序(sort),統計(aggs)時,ES把涉及到的字段數據全部讀取到內存(JVM Heap)中進行操作。相當於進行了數據緩存,提升查詢效率。

  • 監控FieldData
    仔細監控fielddata使用了多少內存以及是否有數據被驅逐是非常重要的。
    ielddata緩存使用可以通過下面的方式來監控


# 對於單個索引使用 {ref}indices-stats.html[indices-stats API]

GET /_stats/fielddata?fields=*

# 對於單個節點使用 {ref}cluster-nodes-stats.html[nodes-stats API]

GET /_nodes/stats/indices/fielddata?fields=*

#或者甚至單個節點單個索引

GET /_nodes/stats/indices/fielddata?level=indices&fields=*

# 通過設置 ?fields=* 內存使用按照每個字段分解了

fielddata中的memory_size_in_bytes表示已使用的內存總數,而evictions(驅逐)為0。且經過一段時間觀察,字段所占內存大小都沒有變化。由此推斷,當下的緩存處於無法有效驅逐的狀態。

  • Cache配置

indices.fielddata.cache.size 配置fieldData的Cache大小,可以配百分比也可以配一個准確的數值。cache到達約定的內存大小時會自動清理,驅逐一部分FieldData數據以便容納新數據。默認值為unbounded無限。
indices.fielddata.cache.expire用於約定多久沒有訪問到的數據會被驅逐,默認值為-1,即無限。expire配置不推薦使用,按時間驅逐數據會大量消耗性能。而且這個設置在不久之后的版本中將會廢棄。

看來,Data too large異常就是由於fielddata.cache的默認值為unbounded導致的了。

  • FieldData格式
    除了緩存取大小之外,我們還可以控制字段數據緩存到內存中的格式。

在mapping中,我們可以這樣設置:

{
    "tag": {
        "type":      "string",
        "fielddata": {
            "format": "fst"
        }
    }
}

對於String類型,format有以下幾種:
paged_bytes (默認):使用大量的內存來存儲這個字段的terms和索引。
fst:用FST的形式來存儲terms。這在terms有較多共同前綴的情況下可以節約使用的內存,但訪問速度上比paged_bytes 要慢。
doc_values:fieldData始終存放在disk中,不加載進內存。訪問速度最慢且只有在index:no/not_analyzed的情況適用。

對於數字和地理數據也有可選的format,但相對String更為簡單,具體可在api中查看。
從上面我們可以得知一個信息:我們除了配置緩存區大小以外,還可以對不是特別重要卻量很大的String類型字段選擇使用fst緩存類型來壓縮大小。

  • 斷路器
    fieldData的緩存配置中,有一個點會引起我們的疑問:fielddata的大小是在數據被加載之后才校驗的。假如下一個查詢准備加載進來的fieldData讓緩存區超過可用堆大小會發生什么?很遺憾的是,它將產生一個OOM異常。
    斷路器就是用來控制cache加載的,它預估當前查詢申請使用內存的量,並加以限制。斷路器的配置如下:

indices.breaker.fielddata.limit:這個 fielddata 斷路器限制fielddata的大小,默認情況下為堆大小的60%。
indices.breaker.request.limit:這個 request 斷路器估算完成查詢的其他部分要求的結構的大小, 默認情況下限制它們到堆大小的40%。
indices.breaker.total.limit:這個 total 斷路器封裝了 request 和 fielddata 斷路器去確保默認情況下這2個部分使用的總內存不超過堆大小的70%。

查詢

/_cluster/settings

設置

PUT /_cluster/settings
{
  "persistent": {
    "indices.breaker.fielddata.limit": "60%"
  }
} 


PUT /_cluster/settings
{
  "persistent": {
    "indices.breaker.request.limit": "40%"
  }
} 


PUT /_cluster/settings
{
  "persistent": {
    "indices.breaker.total.limit": "70%"
  }
} 

斷路器限制可以通過文件 config/elasticsearch.yml 指定,也可以在集群上動態更新:

PUT /_cluster/settings
{
  "persistent" : {
    "indices.breaker.fielddata.limit" : 40% 
  }
}

當緩存區大小到達斷路器所配置的大小時會發生什么事呢?答案是:會返回開頭我們說的Data too large異常。這個設定是希望引起用戶對ES服務的反思,我們的配置有問題嗎?是不是查詢語句的形式不對,一條查詢語句需要使用這么多緩存嗎?

在文件 config/elasticsearch.yml 文件中設置緩存使用回收

indices.fielddata.cache.size:  40%
  • 總結

1.這次Data too large異常是ES默認配置的一個坑,我們沒有配置indices.fielddata.cache.size,它就不回收緩存了。緩存到達限制大小,無法往里插入數據。個人感覺這個默認配置不友好,不知ES是否在未來版本有所改進。
2. 當前fieldData緩存區大小 < indices.fielddata.cache.size
當前fieldData緩存區大小+下一個查詢加載進來的fieldData < indices.breaker.fielddata.limit
fielddata.limit的配置需要比fielddata.cache.size稍大。而fieldData緩存到達fielddata.cache.size的時候就會啟動自動清理機制。expire配置不建議使用。
3.indices.breaker.request.limit限制查詢的其他部分需要用的內存大小。indices.breaker.total.limit限制總(fieldData+其他部分)大小。
4.創建mapping時,可以設置fieldData format控制緩存數據格式。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM