ElasticSearch最佳实践!

Coordinator节点

当集群规模下,读写压力不大时可以考虑Master/Data混部。

Master和Data节点分离的好处是降低了Master的压力,避免被读写影响。

独立Coordinator节点进一步提高读写性能,相当于把Query和Fetch两个节点的压力分流。

节点JVM堆内存

ES 堆内存不要超过 32G,31G 最好(压缩普通对象指针问题)

机器内存富余可以多加节点:

  • 如果查询多聚合少可以减少节点(把内存分给 Lucence,增大索引缓存)
  • 如果聚合多查询少可以增加节点(把内存分给多个 Node,增加聚合内存)

ES的服务器,一半的内存都给到ES使用

内存对于Elasticsearch来说绝对是重要的,用于更多的内存数据提供更快的操作

而且还有一个内存消耗大户Lucene,Lucene的性能取决于和OS的交互。

如果把所有的内存都分配给ElasticSearch,不留一点给Lucene,那全文检索性能会很差。

建议是把50%的内存给ElasticSearch。

高写集群

增加 refresh_interval

  • 对于数据实时性要求不高的场景,适当增加 refresh_interval 时间。
  • ES默认的 refresh_interval 是1s,即 doc 写入1s后即可被搜索到。
  • 如果业务对数据实时性要求不高的话,如日志场景,可将索引模版的 refresh_interval 设置成30s。
  • 这能够避免过多的小 segment 文件的生成及段合并的操作。

Bulk 批量写入:

  • 使用 Bulk 接口批量写入数据,每次 bulk 数据量大小控制在 10M 左右,可以提高写入吞吐。

集群参数调整

对于写入远远大于查询的集群(多半也可以理解成是离线集群,大部分时间都在同步数据):

  • 适当调整index buffer大小会提高吞吐量。
1
2
3
indices.memory.index_buffer_size: 10%
indices.memory.min_shard_index_buffer_size: 8mb
indices.memory.min_index_buffer_size: 48mb

这些参数都是node级别的,每个节点默认拿出10%的heap做为buffer加速写入。

可以上当调大配置,在内存中尽量cache数据并build index,提高吞吐量。

另外要重新设置refresh/flush的时间,对于日志型集群,吞吐量的优先级更高。

而业务集群更需要近似实时的查询能力,场景差异性较大。

1
2
3
4
5
6
index.translog.flush_threshold_ops: 800000
index.translog.flush_threshold_size: 512mb
index.translog.flush_threshold_period: 30m
index.translog.interval: 30s
index.translog.sync_interval: 5s
index.refresh_interval: 20s

高写入集群一定要重新设置translog相关的配置,默认的translog策略容易导致恢复时间过长的问题。

建议根据监控指标设置index.translog.flush_threshold_ops,尽快将已经存储到磁盘上的数据从translog中移除。

负面效果就是磁盘的IO会提高(与索引不同,translog是必须fsync到磁盘上的)。

同时,index.refresh_interval也是关注的重点,增加index.refresh_interval时间可以降低IO/提高吞吐量。

但是负面影响就是数据写入后在refresh之前没有办法查询。

refresh/flush时间:

  • 假设index.refresh_interval=A,则index.translog.interval=[A, 2A]

批处理集群:

定时导数/补数的集群,都属于这一类,大部分时间用于查询,仅仅在某个时间段进行写入操作,短时间内写入大量数据。

这一类集群需要遵循以下几步操作:

  • 更新待写入索引的settings,index.refresh_interval设置为-1。
1
2
3
4
5
6
curl -XPUT "http://es.example.com:9200/your_index/_settings" -d '
{
"index" : {
"refresh_interval" : -1
}
}'

导入数据,推荐用bulk API。

调用_refresh API刷新buffer。

1
curl -XPOST "http://es.example.com:9200/your_index/_refresh"

调用_flush API同步到磁盘。

1
curl -XPOST "http://es.example.com:9200/your_index/_flush"

默认情况下Elasticsearch会通过定时refresh去build倒排索引,但是在执行批量导数任务的场景中并不需要这种近似实时的能力。

强制关闭refresh会提高吞吐量,待全部数据导入完毕后,手工refresh。

然后再利用flush将数据刷新到磁盘上,并清空translog(会加快恢复)。

索引配置评估准则

单个分片大小控制在 30-50GB

集群总分片数量控制在 3w 以内

1GB 的内存空间支持 20-30 个分片为佳

一个节点建议不超过 1000 个分片

索引分片数量建议和节点数量保持一致

集群规模较大时建议设置专用主节点

专用主节点配置建议在 8C16G 以上

如果是时序数据,建议结合冷热分离+ILM 索引生命周期管理

合理的Index Mapping

特殊字段:如Boolean、IP、时间等

字符串:尽量使用keyword,默认的text会被analyze。

  • keyword最大32766字节。
  • 在仅查询的情况下,如果有 range 查询需求,使用 numeric,否则使用 keyword。

调整refresh间隔:

  • refresh_interval: 30s,默认的1秒会导致大量segment产生,影响性能。

调整translog刷新机制为异步

创建新索引时,可以配置每个分片中的Segment的排序方式,index sorting是优化检索性能的非常重要的方式之一

查询

尽量使用filter而不是query。

  • 使用filter不会计算评分score,只计算匹配。

如果不关心文档返回的顺序,则按_doc排序。

避免通配符查询。

不要获取太大的结果数据集,如果需要大量数据使用Scroll API。

关于数据聚合去重:

  • Terms 指定字段聚合 + TopN:
    • 合理设置聚合的TopN,聚合结果是不精确的,是取每个分片的Top Size元素后综合排序后的值。
  • ES5以后的新特性Collapse:按某个字段进行折叠,这个Collapse只针对query出来的结果。
    • 只能用在keyword或者numeric类型。
  • ES6以后支持分页的聚合:Composite Aggregation,可以获取全量的聚合数据。
    • 只能用于Terms、Histogram、Date histogram、GeoTile grid。

field data cache

indices.fielddata.cache.size(node级别):

节点用于 fielddata 的最大内存,如果 fielddata 达到该阈值,就会把旧数据交换出去。

该参数可以设置百分比或者绝对值。默认设置是不限制。

  • 所以强烈建议设置该值,比如 30%。

之前遇到的问题是fielddata内存占满导致node oom 崩溃。