如何防止 Elasticsearch 使用如此多的内存?

How can I prevent Elasticsearch from using so much memory?

我正在尝试使用 Kibana 来可视化我已经摄取到 Elasticsearch 中的一些 Bro 记录。我加载了约 1 个月的记录(总共约 30 亿条记录,约 4TB)。数据被毫无问题地摄取和索引。我可以在 Kibana 中构建一些简单的可视化效果,但是当我尝试加载我创建的仪表板(其中包括 12 种不同的可视化效果,并启动至少那么多的 Elasticsearch 查询)时,我开始遇到错误。

我是 运行 具有 5 个数据节点的 7 节点 Elasticsearch 集群:

host001 192.168.1.1 18  8  0.00 - * Feron  
host002 192.168.1.2 15  8  0.00 - - Dark Phoenix    
host003 192.168.1.3 58 21  0.25 d - Starbolt          
host004 192.168.1.4 37 23  0.07 d - Niles Van Roekel  
host005 192.168.1.5 47 29  0.10 d - Angel Salvadore    
host006 192.168.1.6 68 29 16.37 d - Candra            
host007 192.168.1.7 56 29 14.36 d - Algrim the Strong

elasticsearch.log错误重点如下:

不同字段的这些行的集合(当为字段数据使用过多内存时会出现中断,我认为这是我问题的核心):

[2015-10-06 08:24:00,265][WARN ][indices.breaker ] [Eric Slaughter] [FIELDDATA] New used memory 3752926600 [3.4gb] from field [AA] would be larger than configured breaker: 3745107148 [3.4gb], breaking

这些的集合(似乎即使有断路器,Elasticsearch 还是会耗尽内存):

[2015-10-06 08:32:06,279][WARN ][netty.channel.socket.nio.AbstractNioSelector] Unexpected exception in the selector loop. org.elasticsearch.index.engine.CreateFailedEngineException: [bro-2015-10-06][2] Create failed for [dns#AVA9HeN5uS-hcepf0HbN] at org.elasticsearch.index.engine.InternalEngine.create(InternalEngine.java:262) at org.elasticsearch.index.shard.IndexShard.create(IndexShard.java:470) at org.elasticsearch.action.bulk.TransportShardBulkAction.shardIndexOperation(TransportShardBulkAction.java:437) at org.elasticsearch.action.bulk.TransportShardBulkAction.shardOperationOnPrimary(TransportShardBulkAction.java:149) at org.elasticsearch.action.support.replication.TransportShardReplicationOperationAction$AsyncShardOperationAction.performOnPrimary(TransportShardReplicationOperationAction.java:515) at org.elasticsearch.action.support.replication.TransportShardReplicationOperationAction$AsyncShardOperationAction.run(TransportShardReplicationOperationAction.java:422) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:744) Caused by: org.apache.lucene.store.AlreadyClosedException: refusing to delete any files: this IndexWriter hit an unrecoverable exception at org.apache.lucene.index.IndexFileDeleter.ensureOpen(IndexFileDeleter.java:354) at org.apache.lucene.index.IndexFileDeleter.deleteFile(IndexFileDeleter.java:719) at org.apache.lucene.index.IndexFileDeleter.deleteNewFiles(IndexFileDeleter.java:712) at org.apache.lucene.index.IndexWriter.deleteNewFiles(IndexWriter.java:4821) at org.apache.lucene.index.DocumentsWriter$DeleteNewFilesEvent.process(DocumentsWriter.java:749) at org.apache.lucene.index.IndexWriter.processEvents(IndexWriter.java:4875) at org.apache.lucene.index.IndexWriter.processEvents(IndexWriter.java:4867) at org.apache.lucene.index.IndexWriter.updateDocument(IndexWriter.java:1527) at org.apache.lucene.index.IndexWriter.addDocument(IndexWriter.java:1252) at org.elasticsearch.index.engine.InternalEngine.innerCreateNoLock(InternalEngine.java:343) at org.elasticsearch.index.engine.InternalEngine.innerCreate(InternalEngine.java:285) at org.elasticsearch.index.engine.InternalEngine.create(InternalEngine.java:256) ... 8 more Caused by: java.lang.OutOfMemoryError: Java heap space

然后是下面的一堆,我认为这是在另一个节点上启动副本分片的尝试(这将导致该节点失败,并开始连锁反应......我已经得到通过消除副本碎片来消除这个错误,但我更喜欢更好的解决方案)

[2015-10-06 08:38:35,707][WARN ][action.bulk ] [Eric Slaughter] Failed to perform indices:data/write/bulk[s] on remote replica [Tower][KxzEXAXKTCazjLzgOJE_aA][host005][inet[/192.168.1.5:9300]]{master=false}[bro-2015-10-06][8] org.elasticsearch.transport.NodeDisconnectedException: [Tower][inet[/192.168.1.5:9300]][indices:data/write/bulk[s][r]] disconnected

我知道解决这个问题的一种方法是水平扩展,但我没有这种奢侈,我更希望能够正确利用我拥有的集群(尤其是因为我只是使用 0.5TB 数据,还有更多可用数据)。

我还研究了一些可以在下面的映射中看到的其他选项。 "doc_values" 格式的数据应该可以将字段数据加载到磁盘上,但并不能完全消除该问题。有可能是其他东西占用了所有内存,或者元字段(_type、_id 等)是罪魁祸首(因为我还没有找到使用 "doc_values" 配置这些字段的方法)。我还在字符串字段中使用全局序数。

如果有人需要有关我的集群或配置的更多信息,请告诉我!我真的很难过,所以在此先感谢你们提供的任何帮助。

这是我使用的映射模板:http://pastebin.com/S8UVKRxZ

这是我的 elasticsearch.yml 配置:http://pastebin.com/PaG0pBC5

每个索引有多少条记录?如果每个索引的记录量以十亿计,您可能需要将索引分解。

^^ 我希望这是一条评论,但由于我的声誉不高,我无法对您的问题发表评论。

来自 ElasticSearch 的文档: limiting_memory_usage

It may surprise you to find that Elasticsearch does not load into fielddata just the values for the documents that match your query. It loads the values for all documents in your index, even documents with a different _type!