ElasticSearch最佳实践!
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 | indices.memory.index_buffer_size: 10% |
这些参数都是node级别的,每个节点默认拿出10%的heap做为buffer加速写入。
可以上当调大配置,在内存中尽量cache数据并build index,提高吞吐量。
另外要重新设置refresh/flush的时间,对于日志型集群,吞吐量的优先级更高。
而业务集群更需要近似实时的查询能力,场景差异性较大。
1 | index.translog.flush_threshold_ops: 800000 |
高写入集群一定要重新设置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 | curl -XPUT "http://es.example.com:9200/your_index/_settings" -d ' |
导入数据,推荐用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 崩溃。