Error messagehtml
{ "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\" }" }
此時 kibana
已經沒法訪問,因此必須登錄服務器排查問題。下面先給出解決方法,後介紹問題緣由。node
查看服務狀態json
# supervisorctl status elasticSearch RUNNING pid 1838, uptime 6:03:37 jaeger-collector RUNNING pid 2572, uptime 6:03:10 jaeger-query RUNNING pid 2571, uptime 6:03:10 kibana RUNNING pid 5048, uptime 5:42:22
發現ES及其它服務運行狀態都正常。api
查看節點狀態 (略)緩存
curl -XGET '[http://localhost:9200/\_nodes/stats?pretty](http://localhost:9200/_nodes/stats?pretty)' |less
清理fileddata cache安全
curl -XPOST '[http://localhost:9200/\_all/\_cache/clear?fielddata=true](http://localhost:9200/_all/_cache/clear?fielddata=true)'
嘗試清理fileddata cache後,發現服務仍然沒法正常訪問。服務器
查看全部indexsapp
curl -X GET '[http://127.0.0.1:9200/\_cat/indices?v](http://127.0.0.1:9200/_cat/indices?v)'
刪除全部 jaeger開頭 的index
若是你的數據是日誌或非重要的數據,能夠把相關的index先刪除。less
curl -X DELETE "localhost:9200/jaeger\*?pretty"
修改fielddata配置curl
curl -H "Content-Type: application/json" -XPUT '[http://localhost:9200/\_cluster/settings](http://localhost:9200/_cluster/settings)' -d '{ "persistent" : { "indices.breaker.fielddata.limit":"40%" } }'
這個限制是按對內存的百分比設置的。fielddata
斷路器默認設置堆的 60% 做爲 fielddata 大小的上限。
解決問題的關鍵點在這,修改 indices.breaker.fielddata.limit 的默認配置。修改後重啓服務器就OK了。
重啓服務
supervisorctl restart elasticSearch && supervisorctl restart jaeger-collector && supervisorctl restart jaeger-query && supervisorctl restart kibana
經排查,原來是ES默認的緩存設置讓緩存區只進不出引發的,具體分析一下。
上圖是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%
https://www.codetd.com/en/article/8070413
https://elasticsearch.cn/question/6642
Doc Values and Fielddata限制內存使用
https://discuss.elastic.co/t/unable-to-start-kibana-and-circuit-breaking-exception/191860
https://www.cnblogs.com/sanduzxcvbnm/p/11982476.html
https://www.elastic.co/guide/en/elasticsearch/reference/6.5/indices-clearcache.html