ElasticSearch学习笔记之四:ElasticSearch优化

4. ElasticSearch优化

4.1. 硬件选择

Elasticsearch的基础是Lucene,所有的索引和文档数据是存储在本地的磁盘中,具体的路径可在ES的配置文件…/config/elasticsearch.yml中配置,如下:

# Path to directory where to store the data (separate multiple locations by comma):
#
path.data: /path/to/data
#
# Path to log files:
#
path.logs: /path/to/logs

磁盘在现代服务器上通常都是瓶颈。Elasticsearch重度使用磁盘,你的磁盘能处理的吞吐量越大,你的节点就越稳定。这里有一些优化磁盘I/O的技巧:

  • 使用SSD就像其他地方提过的,他们比机械磁盘优秀多了。
  • 使用RAID0。条带化RAID会提高磁盘IO,代价显然就是当一块硬盘故障时整个就故障了。不要使用镜像或者奇偶校验RAID,因为副本已经提供了这个功能。
  • 另外,使用多块硬盘,并允许Elasticsearch 通过多个path data目录配置把数据条带化分配到它们上面。
  • 不要使用远程挂载的存储,比如NFS或者SMB/CIFS。这个引入的延迟对性能来说完全是背道而驰的。

4.2. 分片策略

4.2.1 合理设置分片数

分片和副本的设计为 ES 提供了支持分布式和故障转移的特性,但并不意味着分片和副本是可以无限分配的。而且索引的分片完成分配后由于索引的路由机制,我们是不能重新修改分片数的。

可能有人会说,我不知道这个索引将来会变得多大,并且过后我也不能更改索引的大小,所以为了保险起见,还是给它设为 1000 个分片吧。但是需要知道的是,一个分片并不是没有代价的。需要了解:

  • 一个分片的底层即为一个 Lucene 索引,会消耗一定文件句柄、内存、以及 CPU运转。
  • 每一个搜索请求都需要命中索引中的每一个分片,如果每一个分片都处于不同的节点还好, 但如果多个分片都需要在同一个节点上竞争使用相同的资源就有些糟糕了。
  • 用于计算相关度的词项统计信息是基于分片的。如果有许多分片,每一个都只有很少的数据会导致很低的相关度。

一个业务索引具体需要分配多少分片可能需要架构师和技术人员对业务的增长有个预先的判断,横向扩展应当分阶段进行。为下一阶段准备好足够的资源。 只有当你进入到下一个阶段,你才有时间思考需要作出哪些改变来达到这个阶段。一般来说,我们遵循一些原则:

  • 控制每个分片占用的硬盘容量不超过ES的最大JVM的堆空间设置(一般设置不超过32G,参考下文的JVM设置原则),因此,如果索引的总容量在500G左右,那分片大小在16个左右即可;当然,最好同时考虑原则2。
  • 考虑一下node数量,一般一个节点有时候就是一台物理机,如果分片数过多,大大超过了节点数,很可能会导致一个节点上存在多个分片,一旦该节点故障,即使保持了1个以上的副本,同样有可能会导致数据丢失,集群无法恢复。所以,一般都设置分片数不超过节点数的3倍。
  • 主分片,副本和节点最大数之间数量,我们分配的时候可以参考以下关系:
    节点数<=主分片数 *(副本数+1)

4.2.2 推迟分片分配

对于节点瞬时中断的问题,默认情况,集群会等待一分钟来查看节点是否会重新加入,如果这个节点在此期间重新加入,重新加入的节点会保持其现有的分片数据,不会触发新的分片分配。这样就可以减少ES在自动再平衡可用分片时所带来的极大开销。

通过修改参数delayed_timeout,可以延长再均衡的时间,可以全局设置也可以在索引级别进行修改:

#PUT /_all/_settings
{
	"settings": {
		"index.unassigned.node_left.delayed_timeout": "5m"
	}
}

4.3. 路由选择

当我们查询文档的时候, Elasticsearch如何知道一个文档应该存放到哪个分片中呢?它其实是通过下面这个公式来计算出来:

shard = hash(routing) % number_of_primary_shards

routing默认值是文档的id,也可以采用自定义值,比如用户id。

4.3.1 不带routing查询

在查询的时候因为不知道要查询的数据具体在哪个分片上,所以整个过程分为2个步骤

  • 分发:请求到达协调节点后,协调节点将查询请求分发到每个分片上。
  • 聚合:协调节点搜集到每个分片上查询结果,在将查询的结果进行排序,之后给用户返回结果。

4.3.2 带routing查询

查询的时候,可以直接根据routing 信息定位到某个分配查询,不需要查询所有的分配,经过协调节点排序。向上面自定义的用户查询,如果routing 设置为userid 的话,就可以直接查询出数据来,效率提升很多。

4.4. 写入速度优化

ES的默认配置,是综合了数据可靠性、写入速度、搜索实时性等因素。实际使用时,我们需要根据公司要求,进行偏向性的优化。

针对于搜索性能要求不高,但是对写入要求较高的场景,我们需要尽可能的选择恰当写优化策略。综合来说,可以考虑以下几个方面来提升写索引的性能:

  • 加大Translog Flush,目的是降低Iops、Writeblock。
  • 增加Index Refesh间隔,目的是减少Segment Merge的次数。
  • 调整Bulk 线程池和队列。
  • 优化节点间的任务分布。
  • 优化Lucene层的索引建立,目的是降低CPU及IO。

4.4.1 优化存储设备

ES是一种密集使用磁盘的应用,在段合并的时候会频繁操作磁盘,所以对磁盘要求较高,当磁盘速度提升之后,集群的整体性能会大幅度提高。

4.4.2 合理使用合并

Lucene以段的形式存储数据。当有新的数据写入索引时,Lucene就会自动创建一个新的段。
随着数据量的变化,段的数量会越来越多,消耗的多文件句柄数及CPU就越多,查询效率就会下降。
由于Lucene段合并的计算量庞大,会消耗大量的I/O,所以ES默认采用较保守的策略,让后台定期进行段合并。

4.4.3 减少Refresh的次数

Lucene在新增数据时,采用了延迟写入的策略,默认情况下索引的refresh_interval为1秒。
Lucene将待写入的数据先写到内存中,超过1秒(默认)时就会触发一次Refresh,然后Refresh会把内存中的的数据刷新到操作系统的文件缓存系统中。
如果我们对搜索的实效性要求不高,可以将Refresh周期延长,例如30秒。
这样还可以有效地减少段刷新次数,但这同时意味着需要消耗更多的Heap内存。

4.4.4 加大Flush设置

Flush的主要目的是把文件缓存系统中的段持久化到硬盘,当Translog的数据量达到512MB或者30分钟时,会触发一次Flush。

index.translog.flush_threshold_size 参数的默认值是 512MB,我们进行修改。

增加参数值意味着文件缓存系统中可能需要存储更多的数据,所以我们需要为操作系统的文件缓存系统留下足够的空间。

4.4.5 减少副本的数量

ES为了保证集群的可用性,提供了Replicas(副本)支持,然而每个副本也会执行分析、索引及可能的合并过程,所以Replicas的数量会严重影响写索引的效率。
当写索引时,需要把写入的数据都同步到副本节点,副本节点越多,写索引的效率就越慢。
如果我们需要大批量进行写入操作,可以先禁止Replica复制,设置index.number_of_replicas: 0关闭副本。在写入完成后,Replica修改回正常的状态。

4.5. 内存设置

ES默认安装后设置的内存是1GB,对于任何一个现实业务来说,这个设置都太小了。如果是通过解压安装的ES,则在ES安装文件中包含一个jvm.option文件,添加如下命令来设置ES的堆大小,Xms表示堆的初始大小,Xmx表示可分配的最大内存,都是1GB。
确保Xmx和Xms的大小是相同的,其目的是为了能够在Java垃圾回收机制清理完堆区后不需要重新分隔计算堆区的大小而浪费资源,可以减轻伸缩堆大小带来的压力。
假设你有一个64G内存的机器,按照正常思维思考,你可能会认为把64G内存都给ES比较好,但现实是这样吗,越大越好?虽然内存对ES来说是非常重要的,但是答案是否定的!

因为ES堆内存的分配需要满足以下两个原则:

  1. 不要超过物理内存的50%:Lucene的设计目的是把底层OS里的数据缓存到内存中。Lucene的段是分别存储到单个文件中的,这些文件都是不会变化的,所以很利于缓存,同时操作系统也会把这些段文件缓存起来,以便更快的访问。如果我们设置的堆内存过大,Lucene可用的内存将会减少,就会严重影响降低Lucene的全文本查询性能。
  2. 堆内存的大小最好不要超过32GB:在Java中,所有对象都分配在堆上,然后有一个KlassPointer指针指向它的类元数据。这个指针在64位的操作系统上为64位,64位的操作系统可以使用更多的内存(264)。在32位的系统上为32位,32位的操作系统的最大寻址空间为4GB(232)。但是64位的指针意味着更大的浪费,因为你的指针本身大了。浪费内存不算,更糟糕的是,更大的指针在主内存和缓存器(例如LLC,L1等)之间移动数据的时候,会占用更多的带宽。

最终我们都会采用31G设置

-Xms 31g
-Xmx 31g

假设你有个机器有128GB的内存,你可以创建两个节点,每个节点内存分配不超过32GB。也就是说不超过64GB内存给ES的堆内存,剩下的超过64GB的内存给Lucene。

4.6. 重要配置

参数名参数值说明
cluster.nameelasticsearch配置ES的集群名称,默认值是ES,建议改成与所存数据相关的名称,ES会自动发现在同一网段下的集群名称相同的节点。
node.namenode-1集群中的节点名,在同一个集群中不能重复。节点的名称一旦设置,就不能再改变了。当然,也可以设置成服务器的主机名称,例如node.name:${HOSTNAME}
node.mastertrue指定该节点是否有资格被选举成为Master节点,默认是True,如果被设置为True,则只是有资格成为Master节点,具体能否成为Master节点,需要通过选举产生。
node.datatrue指定该节点是否存储索引数据,默认为True。数据的增、删、改、查都是在Data节点完成的。
index.number_of_shards1设置都索引分片个数,默认是1片。也可以在创建索引时设置该值,具体设置为多大都值要根据数据量的大小来定。如果数据量不大,则设置成1时效率最高
index.number_of_replicas1设置默认的索引副本个数,默认为1个。副本数越多,集群的可用性越好,但是写索引时需要同步的数据越多。
transport.tcp.compresstrue设置在节点间传输数据时是否压缩,默认为False,不压缩
discovery.zen.minimum_master_nodes1设置在选举Master节点时需要参与的最少的候选主节点数,默认为1。如果使用默认值,则当网络不稳定时有可能会出现脑裂。合理的数值为(master_eligible_nodes/2)+1,其中master_eligible_nodes表示集群中的候选主节点数
discovery.zen.ping.timeout3s设置在集群中自动发现其他节点时Ping连接的超时时间,默认为3秒。在较差的网络环境下需要设置得大一点,防止因误判该节点的存活状态而导致分片的转移
  • 33
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

-风中叮铃-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值