Elasticsearch性能优化实战指南

0、背景
在当今世界,各行各业天天都有海量数据产生,为了从这些海量数据中获取想要的分析结果,须要对数据进行提取、转换,存储,维护,管理和分析。 这已然远远超出了普通处理工具、数据库等的实现能力,只有基于的分布式架构和并行处理机制的大数据工具所才能实现这些功能。 Elasticsearch是响应如前所述大多数用例的最热门的开源数据存储引擎之一。html

Elasticsearch是一种分布式数据存储和搜索引擎,具备容错和高可用性特色。为了充分利用其搜索功能,须要正确配置Elasticsearch。node

简单的默认配置不适合每一个实际业务场景。实战开发运维中,个性化实现贴合本身业务场景的集群配置是优化集群性能的必经之路。本文集合实战业务场景,重点介绍搜索密集型Elasticsearch集群的提高性能的干货配置。算法

一、索引层面优化配置
默认状况下,6.x及以前的版本中Elasticsearch索引有5个主分片和1个副本,7.X及以后版本1主1副。 这种配置并不适用于全部业务场景。 须要正确设置分片配置,以便维持索引的稳定性和有效性。数据库

1.一、分片大小
分片大小对于搜索查询很是重要。bootstrap

一方面, 若是分配给索引的分片太多,则Lucene分段会很小,从而致使开销增长。当同时进行多个查询时,许多小分片也会下降查询吞吐量。缓存

另外一方面,太大的分片会致使搜索性能降低和故障恢复时间更长。性能优化

Elasticsearch官方建议一个分片的大小应该在20到40 GB左右。架构

例如,若是您计算出索引将存储300 GB的数据,则能够为该索引分配9到15个主分片。 并发

根据集群大小,假设群集中有10个节点,您能够选择为此索引分配10个主分片,以便在集群节点之间均匀分配分片。app

深刻原理推荐:

Elasticsearch之如何合理分配索引分片?

https://www.elastic.co/cn/blog/how-many-shards-should-i-have-in-my-elasticsearch-cluster

Elasticsearch究竟要设置多少分片数?

https://qbox.io/blog/optimizing-elasticsearch-how-many-shards-per-index

1.二、数据动态持续写入场景
若是存在连续写入到Elasticsearch集群的数据流,如:实时爬虫互联网数据写入ES集群。则应使用基于时间的索引以便更轻松地维护索引。

若是写入数据流的吞吐量随时间而变化,则须要适当地改变下一个索引的配置才能实现数据的动态扩展。

那么,如何查询分散到不一样的基于时间索引的全部文档?答案是别名。能够将多个索引放入别名中,而且对该别名进行搜索会使查询就像在单个索引上同样。

固然,须要保持好平衡。注意思考:将多少数据写入别名?别名上写入太多小索引会对性能产生负面影响。

例如,是以周仍是以月为单位为单位创建索引是须要结合业务场景平衡考虑的问题?

若是以月为单位建议索引性能最优,那么相同数据以周为单位创建索引势必会由于索引太多致使负面的性能问题。

深刻原理推荐:Elasticsearch索引管理利器——Curator深刻详解

1.三、Index Sorting
注意:索引排序机制是6.X版本才有的特性。

在Elasticsearch中建立新索引时,能够配置每一个分片中的分段的排序方式。 默认状况下,Lucene不会应用任何排序。 index.sort.* 定义应使用哪些字段对每一个Segment内的文档进行排序。

使用举例:

1PUT /twitter
2{
3 "settings" : {
4 "index" : {
5 "sort.field" : "date",
6 "sort.order" : "desc"
7 }
8 },
9 "mappings": {
10 "properties": {
11 "date": {
12 "type": "date"
13 }
14 }
15 }
16}

目的:index sorting是优化Elasticsearch检索性能的很是重要的方式之一。

大白话:index sorting机制经过写入的时候指定了某一个或者多个字段的排序方式,会极大提高检索的性能。

更深原理:推荐阅读:

https://www.elastic.co/cn/blog/index-sorting-elasticsearch-6-0

二、分片层面优化配置
分片是底层基本的读写单元,分片的目的是分割巨大索引,让读写并行执行。写入过程先写入主分片,主分片写入成功后再写入副本分片。

副本分片的出现,提高了集群的高可用性和读取吞吐率。

在优化分片时,分片的大小、节点中有多少分片是主要考虑因素。副本分片对于扩展搜索吞吐量很重要,若是硬件条件容许,则能够当心增长副本分片的数量。

容量规划的一个很好的启动点是分配分片,“《深刻理解Elasticsearch》强调:最理想的分片数量应该依赖于节点的数量。”其数量是节点数量的1.5到3倍。

分配副本分片数的公式:max(max_failures,ceil(num_nodes /) num_primaries) - 1)。

原理:若是您的群集具备num_nodes节点,总共有num_primaries主分片,若是您但愿最多可以同时处理max_failures节点故障,那么适合您的副本数量为如上公式值。

公式来源:

https://www.elastic.co/guide/en/elasticsearch/reference/master/tune-for-search-speed.html

总的来讲:节点数和分片数、副本数的简单计算公式以下:
所需作大节点数=分片数*(副本数+1)。

三、Elasticsearch总体层面配置
配置Elasticsearch集群时,最主要的考虑因素之一是确保至少有一半的可用内存进入文件系统缓存,以便Elasticsearch能够将索引的hot regions保留在物理内存中。

在设计集群时还应考虑物理可用堆空间。 Elasticsearch建议基于可用堆空间的分片分配最多应为20个分片/ GB,这是一个很好的经验法则。

例如,具备30 GB堆的节点最多应有600个分片,以保持集群的良好状态。

一个节点上的存储能够表述以下:节点能够支持的磁盘空间= 20 (堆大小单位:GB)(以GB为单位的分片大小),因为在高效集群中一般会看到大小在20到40 GB之间的分片,所以最大存储空间能够支持16 GB可用堆空间的节点,最多可达12 TB的磁盘空间(201640=12.8TB)。

边界意识有助于为更好的设计和将来的扩展操做作好准备。

能够在运行时以及初始阶段进行许多配置设置。

在构建Elasticsearch索引和集群自己以得到更好的搜索性能时,了解在运行时哪些配置能够修改以及哪些配不能够修改是相当重要的。

3.1 动态设置
一、设置历史数据索引为只读状态。
基于时间的动态索引的执行阶段,若是存放历史数据的索引没有写操做,能够将月度索引设置为只读模式,以提升对这些索引的搜索性能。
6.X以后的只读索引实战设置方式:

1PUT /twitter/_settings
2{
3 "index.blocks.read_only_allow_delete": null
4}

二、对只读状态索引,进行段合并。
当索引设置为只读时,能够经过强制段合并操做以减小段的数量。

优化段合并将致使更好的搜索性能,由于每一个分片的开销取决于段的计数和大小。

注意1:不要将段合并用于读写索引,由于它将致使产生很是大的段(每段> 5Gb)。

注意2:此操做应在非高峰时间进行,由于这是一项很是耗资源的操做。

段合并操做实战方式:

1curl -X POST "localhost:9200/kimchy/_forcemerge?only_expunge_deletes=false&max_num_segments=100&flush=true"

三、使用preference优化缓存利用率
有多个缓存能够帮助提升搜索性能,例如文件系统缓存,请求缓存或查询缓存。

然而,全部这些缓存都维护在节点级别,这意味着若是您在拥有1个或更多副本且基于默认路由算法集群上连续两次运行相同的请求,这两个请求将转到不一样的分片副本上 ,阻止节点级缓存帮助。

因为搜索应用程序的用户一个接一个地运行相似的请求是常见的,例如为了检索分析索引的部分较窄子集,使用preference标识当前用户或会话的偏好值能够帮助优化高速缓存的使用。

preference实战举例:

1GET /_search?preference=xyzabc123
2{
3 "query": {
4 "match": {
5 "title": "elasticsearch"
6 }
7 }

四、禁止交换
能够在每一个节点上禁用交换以确保稳定性,而且应该不惜一切代价避免交换。它可能致使垃圾收集持续数分钟而不是毫秒,而且可能致使节点响应缓慢甚至断开与集群的链接。

在Elasticsearch分布式系统中,让操做系统终止节点更有效。能够经过将bootstrap.memory_lock设置为True来禁用它。

Linux系统级配置:

1sudo swapoff -a

Elasticsearch配置文件elasticsearch.yml配置:

1bootstrap.memory_lock: true

五、增长刷新间隔 refresh_interval
默认刷新间隔为1秒。这迫使Elasticsearch每秒建立一个分段。实际业务中,应该根据使用状况增长刷新间隔,举例:增长到30秒。

这样以后,30s产生一个大的段,较每秒刷新大大减小将来的段合并压力。最终会提高写入性能并使搜索查询更加稳定。

更新刷新间隔实战:

1PUT /twitter/_settings
2{
3 "index" : {
4 "refresh_interval" : "1s"
5 }
6}

六、设置max_thread_count
index.merge.scheduler.max_thread_count默认设置为

Math.max(1, Math.min(4, Runtime.getRuntime().availableProcessors() / 2))

但这适用于SSD配置。对于HDD,应将其设置为1。

实战:

1curl -XPUT 'localhost:9200/_settings' -d '{
2 "index.merge.scheduler.max_thread_count" : 1
3}
4

七、禁止动态分配分片
有时,Elasticsearch将从新平衡集群中的分片。此操做可能会下降检索的性能。

在生产模式下,须要时,能够经过cluster.routing.rebalance.enable设置将从新平衡设置为none。

1PUT /_cluster/settings
2{
3 "transient" : {
4 "cluster.routing.allocation.enable" : "none"
5 }
6}

其中典型的应用场景之包括:

集群中临时重启、剔除一个节点;

集群逐个升级节点;当您关闭节点时,分配过程将当即尝试将该节点上的分片复制到集群中的其余节点,从而致使大量浪费的IO. 在关闭节点以前禁用分配能够避免这种状况。

更多实践,推荐阅读:

https://www.elastic.co/guide/en/elasticsearch/reference/5.5/restart-upgrade.html

八、充分利用近似日期缓存效果
如今使用的日期字段上的查询一般不可缓存,由于匹配的范围一直在变化。

然而,就用户体验而言,切换到近似日期一般是可接受的,而且能更好地使用查询高速缓存带来的益处。

实战以下:

1GET index/_search
2{
3 "query": {
4 "constant_score": {
5 "filter": {
6 "range": {
7 "my_date": {
8 "gte": "now-1h/m",
9 "lte": "now/m"
10 }
11 }
12 }
13 }
14 }
15}

这里可能不大好理解,推荐深刻阅读:

https://www.elastic.co/guide/en/elasticsearch/reference/current/tune-for-search-speed.html

3.2 初始设置
一、合并多字段提高检索性能
query_string或multi_match查询所针对的字段越多,检索越慢。

提升多个字段的搜索速度的经常使用技术是在索引时将其值复制到单个字段中。

对于常常查询的某些字段,请使用Elasticsearch的copy-to功能。

例如,汽车的品牌名称,发动机版本,型号名称和颜色字段能够与复制到指令合并。它将改善在这些字段上进行的搜索查询性能。

1PUT movies
2{
3 "mappings": {
4 "properties": {
5 "cars_infos": {
6 "type": "text"
7 },
8 "brand_name": {
9 "type": "text",
10 "copy_to": "cars_infos"
11 },
12 "engine_version": {
13 "type": "text",
14 "copy_to": "cars_infos"
15 },
16 "model ": {
17 "type": "text",
18 "copy_to": "cars_infos"
19 },
20 "color": {
21 "type": "text",
22 "copy_to": "cars_infos"
23 }
24 }
25 }
26}

二、设置分片分配到指定节点
实战业务中常常遇到的业务场景问题:如何将分片设置非均衡分配,有新节点配置极高,可否多分片点过去?

某个 shard 分配在哪一个节点上,通常来讲,是由 ES 自动决定的。如下几种状况会触发分配动做:

1)新索引生成

2)索引的删除

3)新增副本分片

4)节点增减引起的数据均衡

ES 提供了一系列参数详细控制这部分逻辑,其中之一是:在异构集群的情为具备更好硬件的节点的分片分配分配权重。

为了分配权重,

须要设置cluster.routing.allocation.balance.shard值,默认值为0.45f。

数值越大越倾向于在节点层面均衡分片。

实战:

1PUT _cluster/settings
2{
3“transient” : {
4“cluster.routing.allocation.balance.shard” : 0.60
5}
6}

三、调整熔断内存比例大小
查询自己也会对响应的延迟产生重大影响。为了在查询时不触发熔断并致使Elasticsearch集群处于不稳定状态,

能够根据查询的复杂性将indices.breaker.total.limit设置为适合您的JVM堆大小。此设置的默认值是JVM堆的70%。

1PUT /_cluster/settings
2{
3 "persistent" : {
4 "indices.breaker.fielddata.limit" : "60%"
5 }
6}

最好为断路器设置一个相对保守点的值。更深原理推荐阅读:

https://www.elastic.co/guide/cn/elasticsearch/guide/current/_limiting_memory_usage.html

《Elastic源码分析》做者张超指出:“Elasticsearch 7.0 增长了 indices.breaker.total.use_real_memory 配置项,能够更加精准的分析当前的内存状况,及时防止 OOM 出现。虽然该配置会增长一点性能损耗,可是能够提升 JVM 的内存使用率,加强了节点的保护机制。”

四、特定搜索场景,增长搜索线程池配置
默认状况下,Elasticsearch将主要用例是搜索。在须要增长检索并发性的状况下,能够增长用于搜索设置的线程池,与此同时,能够根据节点上的CPU中的核心数量多少斟酌减小用于索引的线程池。

举例:更改配置文件elasticsearch.yml增长以下内容:

1thread_pool.search.queue_size: 500
2#queue_size容许控制没有线程执行它们的挂起请求队列的初始大小。

官方:

https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-threadpool.html

五、打开自适应副本选择
应打开自适应副本选择。该请求将被重定向到响应最快的节点。

当存在多个数据副本时,elasticsearch可使用一组称为自适应副本选择的标准,根据包含每一个分片副本的节点的响应时间,服务时间和队列大小来选择数据的最佳副本。

这样能够提升查询吞吐量并减小搜索量大的应用程序的延迟。

这个配置默认是关闭的,实战打开方法:

1PUT /_cluster/settings
2{
3 "transient": {
4 "cluster.routing.use_adaptive_replica_selection": true
5 }
6}

四、小结
Elasticsearch集群有许多配置设置能够减小响应延迟,提高检索性能。 以上只是冰山一角。更多实践配置推荐阅读官方文档之鼻祖级优化指南:

https://www.elastic.co/guide/en/elasticsearch/reference/6.7/tune-for-search-speed.html

本文受权翻译至国外Burak Altaş的博文,结合实战并仔细核对官网最新7.2版本的配置,进行了细节的调整和改动,实操性更强。但愿对你有帮助。

欢迎留言分享交流你在性能优化上的经验和教训。

相关文章
相关标签/搜索