はじめに
Elasticsearchで突然クエリ実行が失敗し始める事象が発生したので、その時の対応をまとめます。
問題
エラー文
New used memory 933566461 [890.3mb] from field [xxx] would be larger than configured breaker: 933258854 [890mb], breaking
Failed to execute [org.elasticsearch.action.search.SearchRequest@35af27f6] lastShard [true]
org.elasticsearch.ElasticsearchException: org.elasticsearch.common.breaker.CircuitBreakingException: [FIELDDATA] Data too large, data for [xxx] would be larger than limit of [933258854/890mb]
原因
ElasticsearchにはOutOfMemoryErrorを防ぐために、CircuitBreakerという仕組みがあります。
CircuitBreakerは、設定値(indices.breaker.fielddata.limit)よりメモリを使用した時、その処理を中止します。(デフォルトはJVMヒープサイズの60%)
そして、Elasticsearchのクエリキャッシュの期限や最大サイズはデフォルトで無制限です。
よってキャッシュが無限に溜まっていき、CircuitBreakerの設定値を超えた時にエラーが出て、クエリが失敗するようになります。
解決方法
Elasticsearchのクエリキャッシュがメモリを圧迫していることが原因。
暫定対応
クエリキャッシュをクリアする。
$ curl -XPOST 'http://localhost:9200/_cache/clear' -d '{ "fielddata": "true" }'
恒久対応
キャッシュの制限と期限をelasticsearch.ymlに設定する。
indices.fielddata.cache.size: 30% #default 無制限
indices.fielddata.cache.expire: 5m #default -1
ただ、indices.fielddata.cache.expireについては、使わない方が良さそうです。
There is another setting that you may see online: indices.fielddata.cache.expire.
We beg that you never use this setting! It will likely be deprecated in the future.
This setting tells Elasticsearch to evict values from fielddata if they are older than expire, whether the values are being used or not.
This is terrible for performance. Evictions are costly, and this effectively schedules evictions on purpose, for no real gain.
There isn’t a good reason to use this setting; we literally cannot theory-craft a hypothetically useful situation. It exists only for backward compatibility at the moment. We mention the setting in this book only since, sadly, it has been recommended in various articles on the Internet as a good performance tip.
It is not. Never use it!
参考