Elasticsearch 集群调优建议

生产环境集群搭建建议

1.ES设置尽量简洁
elasticsearch.yml中尽量只写必备的参数,其他可以通过api动态设置的参数都通过api来设定
动态设定的参数有transientpersistent两种设置,前者在集群重启后会丢失,后者不会,但两种设定都会覆盖elasticsearch.yml中的配置。

PUT /_cluster/settings
{
  "persistent": {
    "discovery.zen.minimum_master_nodes":2
  },
  "transient": {
    "indices.store.throttle.max_bytes_per_sec":"50mb" 
  }
}       

2.脑裂问题
解决方案:仅在可选举master-eligible节点数大于等于quorum时才可以进行master选举

quorum=master-eligible节点数/2 +1,
例如3个master-eligible节点时,quorum为2
设定discovery.zen.minimum_master_nodes为quorum即可避免脑裂

3.关于JVM内存设定

  • 不要超过31GB
  • 预留一半内存给操作系,用来做文件缓存

具体大小根据该node要存储的数据量来估算,为了保证性能,在内存和数据量间有一个建议的比例:

  • 搜索类项目的比例建议在1:16以内
  • 日志类项目的比例建议在1:48~1:96

假设总数据量大小为1TB,3个node,1个副本,那么每个node要存储的数据量为2TB/3=666GB,即700GB左右,做20%的预留空间,每个node要存储大约850GB的数据。

  • 如果是搜索类项目,每个node内存大小为850GB/16=53GB,大于31GB。31*16=496,即每个node最多存储496GB数据,所以需要至少5个node
  • 如果是日志类型项目,每个node内存大小为850GB/48=18GB,因此3个节点足够

写性能优化

目标是增大写吞吐量-EPS(Event Per Second)越高越好
优化方案:

  • 客户端:多线程写,批量写
  • ES:在高质量数据建模的前提下,主要是在refresh、translog和flush之前做文章。

ES写数据分为三个过程:

  • refresh
  • translog
  • flush

refresh

segment写入磁盘的过程很耗时,可以借助文件系统缓存的特性,先将segment在缓存中创建并开放查询来查询来进一步提升实时性,该过程在es中被称为refresh

在refresh之前文档会先存储在一个buffer中,refresh时将buffer中的所有文档清空并生成segment。

es默认每1秒执行一次refresh,因此文档的实时性被提高到1秒,这也是es被称为近实时(Near Real Time)的原因。

Lucene构建的单个倒排索引称为segment,合在一起称为Index,与ES中的Index概念不同,ES中的一个shard对应一个Lucene Index。

优化: 目标为降低refresh的频率

  • 增大refresh_interval,降低实时性,以增大一次refresh处理的文档数,默认是1s,设置为-1直接禁止自动refresh
  • 增大index buffer size,参数为indices.memory.index_buffer_size(静态参数,需要设定在elasticsearch.yml中)默认为10%。

translog

如果在内存中的segment还没有写入磁盘前发生宕机,那么其中的文档就无法恢复了,如何解决这个问题?
es引入translog机制。写入文档到buffer时,同时将该操作写入translog。

translog文件会即时写入磁盘(fsync),6.x默认每个请求都会落盘,可以修改为每5秒写一次,这样风险便是丢失5秒内的数据,相关配置为index.translog.*

es启动时会检查translog文件,并从中恢复数据

优化: 目标是降低translog写磁盘频率,从而提高写效率,但会降低容灾能力

  • index.translog.durability设置为async,index.translog.sync_interval设置需要的大小,比如120s,那么translog会改为每120s写一次磁盘
  • index.translog.flush_threshold_size默认为512mb。即translog超过该大小时会触发一次flush,那么调大该大小可以避免flush的发生

flush

flush负责将内存中的segment写入磁盘,主要做如下工作:

  • 将translog写入磁盘
  • 将index buffer清空,其中的文档生成一个新的segment,相当于一个refresh操作
  • 更新commit point并写入磁盘
  • 执行fsync操作,将内存中的segment写入磁盘
  • 删除旧的translog文件

Lucene有一个专门的文件来记录所有的segment信息,称为commit point

优化: 目标为降低flush的次数,在6.x可优化的点不多,多为es自动完成

其他优化

  1. 副本设置为0,写入完毕再增加
  2. 合理设计shard数,并保证shard均匀地分配在所有node上,充分利用所有node的资源

index.routing.allocation.total_shards_per_node限定每个索引在每个node上可分配的总主副分片数

例如:5个node,某索引有10个主分片,1个副本,上述值应该设置为多少?

(10+10)/5=4
实际要设置为5个,防止在某个node下线时,分片迁移失败的问题。

主要为index级别的设置优化,以日志场景举例,一般会有如下索引的设定:
这里写图片描述

读性能优化

读性能主要受以下几方面影响:

  • 数据模型是否符合业务模型?
  • 数据规模是否过大?
  • 索引陪孩子是否优化?
  • 查询语句是否优化?

高质量的数据建模是优化的基础:

  • 将需要通过script脚本动态计算的值提前算好作为字段存储到文档中
  • 尽量使得数据模型贴近业务模型

根据不同的数据规模设定不同的SLA

  • 上万条数据与上千万条数据性能肯定存在差异

索引配置调优:

  • 根据数据规模设置合理的主分片数,可以通过测试得到最合适的分片数
  • 设置合理的副本数目,不是越多越好

查询语句调优:
查询语句调优主要有以下几种常见手段:

  • 尽量使用filter上下文,减少算分的场景,由于filter有缓存机制,可以极大提升查询性能
  • 尽量不使用script进行字段计算或者算分排序等
  • 结合profile、explain API分析慢查询语句的症结所在,然后再去优化数据模型

如何设定shard数?

分片问题?
在一个有三个节点组成的es集群中创建一个有三个分片的test_index索引。

1.此时增加节点是否能够提高test_index的数据容量?
    不能。因为只有三个分片,已经分布在3台节点上,新增的节点无法利用。
2.此时增加副本数是否能提高test_index的读取吞吐量?
    不能。因为新增的副本也是分布在这三个节点上,还是利用了同样的资源。如果要新增吞吐量,还要新增节点。

分片数的设定很重要,需要提前规划好

  • 过小会导致后续无法通过增加节点实现水平扩容
  • 过大会导致一个节点上分布过多分片,造成资源浪费,同时会影响查询性能

es的性能基本是线性扩展的,因此我们只要测出1个shard的性能指标,然后根据实际性能需求就能算出需要的shard数。比如单shard写入eps是1000,而线上eps需求时5000,那么你需要5个shard。(实际还要考虑副本的情况)

测试一个shard的流程如下:

  • 搭建与生产环境相同配置的单节点集群
  • 设定一个单分片零副本的索引
  • 写入实际生产数据进行测试,获取写性能指标
  • 针对数据进行查询请求,获取读性能指标

压测工具可以采用esrally参考链接

压测的流程还是比较复杂的,如果是搜索引擎场景,单个shard大小不要超过15GB,如果是日志场景,单shard大小不要超过50GB(shard越大,查询性能越低)
此时只要估算出你索引的总数据大小,然后在除以上面单shard大小也可以得到分片数

猜你喜欢

转载自blog.csdn.net/wfs1994/article/details/80836570