【干货】Elasticsearch的索引性能优化(3)

作者:Adam Vanderbush

译者:小辉

本文是Elasticsearch索引优化系列的第三篇,此前已发布第一篇和第二篇。本系列教程主要目的是通过对Elasticsearch配置进行调优来提升索引性能,并降低监控和管理压力。本文翻译自QBox官方博客,版权归原作者Adam Vanderbush所有。

Elasticsearch推荐使用分片和备份机制以扩展并增加索引的高可用性。副本数稍微多一点有好处,但分片数过多则会影响性能。通常很难判断是否包含了过多的分片,因为这取决于分片大小和如何被使用。如果有大量的分片,但是使用频次很低可能性能并不会太差,相反即使只有两个分片但是如果使用非常频繁则性能会很糟糕。监控节点以确保有多余的空闲资源来处理突发状况。

横向扩展应该做到以下部分。首先应该为下个阶段的扩展预留足够的资源。一旦进入下一阶段,就有足够的时间去考虑需要做出哪些改变以达到之后的阶段。也可以从发送到Elasticsearch 的请求中获取很多优化的方式,比如需要为每个文档发送一个单独的请求吗?或者可以缓存多文档以便于利用bulk API通过单个请求对多个文档进行索引吗?

我们之前主要关注索引的性能比如更新,刷新,段合并和自动限流。本文将会列举一些关于分片、副本、请求、客户端以及存储方面的策略来提高Elasticsearch的吞吐量。

1

扩展Elasticsearch集群

Elasticsearch自带扩展特性。它无论是在个人电脑还是包含数百节点的集群上都可以运行良好,并且这种经验是可复制的。从一个小集群逐渐扩容到大集群几乎是完全自动的,并且很容易做到,从一个大集群到更大的集群可能需要一点计划和设计,但仍然是相对容易的。

Elasticsearch的默认设置已经足够适用很多场景,但是如果想获得更好的性能,就需要考虑数据如何在系统中流转。它可能是时间序列数据(比如日志时间或者社交网络流等与最近的时间相关的)或者基于用户的数据(比如通过对用户或者客户细分来收集的大量文档)。

创建索引的API允许实例化一个索引。Elasticsearch能够为多个索引,包括跨索引的操作提供支持。每个创建的索引都有与其关联的单独配置。一个索引的分片数量必须在索引创建过程中设置好,并且之后不能修改。如果不知道具体会有多少数据,可以考虑稍微多分配一点分片(但是不要太多,有一定的成本)以留出可用的多余扩展。副本的数量则可以在索引库创建之后改变。

curl -XPUT 'localhost:9200/my_index -d '{
    "settings" : {
        "index" : {
            "number_of_shards" : 3, 
            "number_of_replicas" : 2 
        }
    }
}'

索引别名在某种程度上提供了一种在创建索引之后的某些时间段扩展此索引的方法。索引别名API允许为一个索引起一个别名,并且所有的API会自动将别名转换为对应的索引。一个别名也可以同时映射到多个索引,当指定别名时,它会自动扩展到所有的对应的索引。在搜索或者指定路由时,别名也支持利用与之关联的过滤器进行自动映射。别名不能和索引同名。

以下是为索引test1分配索引名为alias1的例子:

curl -XPOST 'localhost:9200/_aliases' -d '{
    "actions" : [
        { "add" : { "index" : "test1", "alias" : "alias1" } }
    ]
}'

移除别名的例子:

curl -XPOST 'localhost:9200/_aliases' -d '{
    "actions" : [
        { "remove" : { "index" : "test1", "alias" : "alias1" } }
    ]
}'

重命名别名可以通过移除旧的后重新添加新别名来完成。这些操作是原子操作,无须担心在改变别名的极短过程中别名不能映射到索引。

curl -XPOST 'localhost:9200/_aliases' -d '{
    "actions" : [
        { "remove" : { "index" : "test1", "alias" : "alias1" } },
        { "add" : { "index" : "test2", "alias" : "alias1" } }
    ]
}'

2

副本

副本十分重要,原因有二:

1.在分片或者节点挂掉之后保障高可用。显然,为达成此目的,副本分片不能与原始/主分片放在同一个节点上。

2.副本可以扩展搜索的吞吐量,因为搜索可以在所有的副本上并行完成。

副本因为可以应对意外而变得十分重要,但是副本越多,建立索引时间就越长。因此,在建立索引的过程中,不设置副本效果最好。并且,相对于分片数量,副本数目可以在任何时候改变,这给了我们更多的选择。

对于特定的情形,比如初始化一个新的索引,或者将数据从一个索引迁移到另一个索引时,通常对时间要求比较严格,在创建过程不配置副本直到结束之后再增加副本是最好的选择。

副本数可以通过更新索引配置的API来完成

curl -XPUT 'localhost:9200/my_index/_settings' -d '{
    "index" : {
        "number_of_replicas" : 0
    }
}'

一旦创建索引操作完成,副本数就可以设置回相关的值。

3

启用专门的数据节点

数据节点包含了建立索引的文档所在的分片。数据节点处理与数据相关的操作比如GRUD、搜索、聚合。这些操作属于I/O、内存和CPU密集型。所以监控这些资源是否过载以增加更多的数据节点至关重要。

启用专门的数据节点的主要好处是区分了主节点和数据节点。

可以通过一下配置设置专门的数据节点:

node.master: false

node.data: true

node.ingest: false

当聚合器节点处理搜索请求时只会请求与之相关的部分数据节点。这会降低数据节点的整体负载以便于有足够的能力来处理索引请求。

如果所有的数据节点都存在磁盘空间不足的情况时,就有必要增加为集群增加更多的数据节点。同时需要确保索引库有足够的主分片来平衡这些节点上的数据。Elasticsearch基于分片分配是通过考虑当前节点磁盘的可用空间来完成。默认情况下,如果节点的磁盘使用量超过85%,就不再分配分片到该节点。

对于低磁盘空间有两种补救方案。一种是删除过期的数据,并将其存储在集群以外的地方。这种方案可以不是对所有的使用者适用,但是,如果是基于时间储存数据,可以存储一个旧索引的数据的快照放在集群以外的地方进行备份,并且通过索引配置取消这些索引的副本。

如果需要在当前的集群中存储所有的数据,那么第二种方案将是唯一的选择:进行垂直或者水平扩展。如果选择垂直扩展,这意味需要升级硬件。然而,为了避免再次越线之后的升级,最好考虑Elasticsearch天然的水平扩展的优势。为了更好地适应未来的发展,最好重新索引数据到新索引上,并在新索引上配置更多的主分片。

4

优化批量请求

Bulk API使得通过单个的API请求执行多个索引或者删除操作变为可能。这会极大地增加索引的速度。每个子请求都独立执行,所以任何一个子请求的失败都不会影响其他的子请求。如果任何一个子请求失败,顶层的错误标签都会置成true,并且会在相关的子请求下打印出错误详情。

允许批量请求的操作包括index,create,delete和update。index和create要求在下一行增加原始数据,并且要配置和标准的索引API一样的op_type。(例如index会增加或替换一个文档,而如果拥有相同的索引和类型的文档已经存在,create会失败),delete不需要在下一行增加源数据,但是也要和标准的删除API有相同的语法。update允许在下一行填充部分文档数据,插入或者指定具体操作的脚本。

整个批量请求都需要通过接受这些请求的节点载入内存,所以批量请求越大,对于其他的请求可用的内存就越少。所以需要对批量请求的大小设定一个合理的值。如果超过这个值,性能不增反减。这个合理值并不是个固定值。它完全取决于硬件,文档大小及复杂性,以及索引和搜索的负载。

幸运的是,找到这个合理值并不难:尝试批量增加典型的文档数来测试索引性能。如果性能下降,说明该批次太大了。比较合理的起始批次是1000,然后逐渐到5000篇文档。如果文档太大,可以设置更小的批次。批量请求的数目取决于文档,是否分析,以及集群的配置,但是单个批量的请求比较合理的大小是5-15MB。注意这是个物理值。利用文档的数目来对批量请求大小进行设置并不严格。例如,如果每次批量索引1000个文档,必须要清楚以下的计算方式:

如果1000个1KB的文档,则只有是1MB。

而1000个100KB的文档大小将会是100MB。

这些与批量大小截然不同。批量请求需要载入到与之对应的节点的内存,所以请求的物理大小比文档的数目更重要。

批量大小从5-15MB附近缓慢的增加,直到发现性能不再有提升。这时就可以考虑通过增加bulk的并发导入数据(多线程等)。

通过Marvel或者其它例如iostat,top,ps等指令可以监控节点资源是否已经到达瓶颈。如果已经开始接受到EsRejectedExecutionException,就说明集群性能已经饱和,至少其中的一个资源已经到达瓶颈。这时,要么降低并发,要么补充受限的资源(例如从普通磁盘切换到SSD)或者更加更多的节点。

当导入数据时,必须确保批量请求循环使用数据节点。不要把所有的请求都发送到单一的节点,因为该节点要在内存中存储所有的这些请求以便进行处理。

5

存储

一般来说,我们会在个人电脑和小规模的集群上部署测试环境;而将Elasticsearch部署到生产环境时,有一些建议值得参考:由于 Elasticsearch应用广泛且可以部署在各式各样的机器上,所以并没有一成不变的规则。但是以下基于我们在生产环境上的经验仍然可以提供一个比较合理的建议。

硬盘通常是现代服务器的瓶颈。Elasticsearch大量使用硬盘,磁盘的吞吐量越大,节点就越稳定。以下是优化磁盘I/O的小贴士:

如果可以负担得起SSD,它的性能优于任何的机械硬盘。基于SSD的节点无论是查询还是建立索引的性能都会有很大的提升。当然如果使用机械硬盘,也可以试试升级为更快的硬盘(高性能服务器硬盘,15k RPM)。

使用RAID 0。阵列磁盘将会增加硬盘I/O,一旦有磁盘损坏将会付出很重的代价。没有必要使用镜像或者奇偶校验的RAID,因为Elasticsearch内部通过副本机制保证了高可用性。使用RAID 0是一种有效的提高硬盘速度的途径,无论是对于机械磁盘还是SSD。

避免使用EFS作为提供持久性、共享存储以及扩容或者收缩的代价。由于文件系统可能导致索引出错,并且Elasticsearch提供了分布式和副本机制,所以并不需要EFS提供的优势。

不要使用远程挂载存储,比如NFS,SMB/CIFS,这种方式导致的延迟会直接影响到集群性能。

如果服务部署在EC2,关注一下EBS性能。即使是基于SSD的EBS选项仍然经常会比本地存储更慢。EBS在小集群(一到两个节点)运行良好,但是对于负担大量搜索和建立索引的底层设施的大集群,则性能很差。如果使用了EBS,利用预配置IOPS存储以保证性能。

最后,避免使用NAS。人们经常宣称他们的NAS解决方案比本地存储更快更稳定。尽管他们这么说,我们从未看到过NAS满足上述宣称的效果。NAS经常会更慢,更长的延时,并且平均延时波动很大,同时NAS也可能成为单点故障。

感谢杨振涛对翻译稿的审校。

英文原文:https://qbox.io/blog/maximize-guide-elasticsearch-indexing-performance-part-3

本文分享自微信公众号 - vivo互联网技术(vivoVMIC)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2017-11-03

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券