天天看点

Elasticsearch性能调优(1):写优化

作者:贵哥说Java创业

对于写索引负责很高但是对搜索性能要求不是很高的场景,入日志搜索,采用优秀的写索引策略就显得非常重要了。可以尝试以下几种方法来提升写索引的性能。

批量提交

当有大量的写任务时,使用批量提交是种不错的方案。但是每次提交的数据量为多大时能达到最优的性能,受文件大小、数据类型、网络情况、集群状态等因素的影响。通用的策略如下。

  1. 批量提交的数据条数一般是根据文档的大小和服务器性能而定的,但是一次批处理的数据大小应从5MB~15MB开始,逐渐增加,直到性能没有提升时才结束。
  2. 在通过增加一次提交的数量而效果没有显著提升时,则需要逐渐增加并发数,并且需要使用监控工具如Marvel来监控服务器的CPU、I/O、网络、内存等资源的使用情况。
  3. 若抛出EsRejectedExcecutionException错误,则表明集群已经没有处理能力了,说明至少有一种资源已经到达瓶颈,这时需要升级已经达到瓶颈的资源或增加集群的节点。

优化存储设备

在现代服务器上,相对于CPU和内存,磁盘是限制服务器性能的最大瓶颈,并且Elasticsearch是一种密集使用磁盘的应用,特别是在段合并的时候对磁盘要求较高,所以磁盘速度提升之后,集群的整体性能会大幅提高。这里对磁盘的选择提供几点建议。

  1. 条件允许的话,强烈建议使用固态硬盘(Solid State Disk)。SSD相比于机械磁盘具有超高的读写速度和稳定性。
  2. 使用raid0。raid0可以提升磁盘写入的速度,因为我们集群中的副本分片已经提供数据备份的功能,所以没有必要再使用镜像或者奇偶校验的raid。
  3. 在elasticsearch的服务器上挂载多块硬盘。并且在elasticsearch的配置文件elasticsearch.yml中设置多个存储路径,例如:path.data: /path/to/datas1,/path/to/data2。这样可以在多块硬盘上同时进行读写操作。
  4. 不要使用类似于NFS(Network File System)的远程存储设备,因为这些设备的延迟对性能的影响是很大的。

合理使用段合并

lucene是以段的形式存储数据的,每当有新的数据写入索引时,就会自动创建一个新的段,所以在一个索引文件中包含了多个段。随着数据量的不断增加,段的数量会越来越多,需要消耗的文件句柄数及CPU就越多,查询时的负担就越重。

lucene后台会定期进行段合并,但是段合并的计算量庞大,会消耗大量的I/O,所以elasticsearch默认采用较保守的策略,如下所述。

  1. 当段合并的速度落后于索引写入的速度时,为了避免出现堆积的段数量爆发,elasticsearch会把写索引的线程数量减少到1,并打印出“now throttling indexing”这样的INFO级别的“警告”信息。
  2. 为了防止因段合并影响了搜索的性能,elasticsearch默认对段合并的速度进行限制,默认是20m/s。但是,如果使用的是SSD,就可以通过下面的命令将这个限制增加到100m/s:
PUT /_cluster/settings
{
 "persistent": {
    "indices.store.throttle.max_bytes_per_sec": "100mb"
  }
}           

如果只考虑写的性能而完全不考虑查询的性能,则可以通过下面的命令关闭限制:

PUT /_cluster/settings
{
  "transient": {
    "indices.store.throttle.type": "none"
   }
}           

在设置限流类型为none时将彻底关闭合并限流。但当导入完成时,则一定要把none再改回merge,重新打开限流。

减少refresh的次数

lucene在新增数据时,为了提高写的性能,采用的是延迟写入的策略,即将要写入的数据先写到内存中,当延时超过1秒(默认)时,会触发一次refresh,refresh会把内存中的数据以段的形式刷新到操作系统的文件缓存系统中。

在数据以段的形式刷新到文件缓存系统后才可以搜索,所以如果对搜索的时效性要求不高的,则可以增加延时时间,比如30秒,这样可以有效地减少段的数量,为后面的段合并减少压力。但这同时意味着需要消耗更多的Heap内存和搜索延时。可以通过配置 index.refresh_interval: 30s 来减少refresh的次数。也可以将其设置为-1,临时关闭refresh,但是在数据导入完成后一定要把该值再改回来。

减少flush的次数

当translog的数据量达到512MB或者30分钟时,会触发一次刷新。刷新的主要目的是把文件缓存系统中的段持久化到硬盘,因为持久化到硬盘是一个比较耗时的操作。可以通过修改index.translog.flush_threshold_size参数增加translog缓存的数据量,来减少刷新的次数,该参数的默认值是512MB,我们可以把它加大一倍,变成1GB。

但是这样的设置意味着在文件缓存系统中要存储更多的数据,所以要减少heap的内存空间,为操作系统的文件缓存系统留下更多的空间。

减少副本的数量

elasticsearch的副本虽然可以保证集群的可用性,同时可以增加搜索的并发数,却会严重降低写索引的效率。因为在写索引时需要把整个文档的内容都发给副本节点,而所有的副本节点都需要把索引的过程重复进行一遍。这意味着每个副本也会执行分析、索引及可能的合并过程。

如果是大批量的导入,则考虑先设置index.number_of_replicas: 0 关闭副本,在写入完成后再开启副本,恢复的过程本质上只是一个从字节到字节的网络传输。

继续阅读