关注公众号

关注公众号

手机扫码查看

手机查看

喜欢作者

打赏方式

微信支付微信支付
支付宝支付支付宝支付
×

Elasticsearch性能优化指南(五)

2020.9.28

将静态相关性信号纳入评分

许多域具有已知的与相关性相关的静态信号。例如,PageRank和URL长度是Web搜索的两个常用功能,以便独立于查询来调整网页的分数。

有两个主要查询,可以将静态分数贡献与文本相关性结合起来,例如。用BM25计算得出: - script_score query - rank_feature query、

例如,假设您有一个希望与BM25得分结合使用的pagerank字段,以使最终得分等于score = bm25_score + pagerank /(10 + pagerank)。

使用script_score查询,查询将如下所示:

curl -X GET "localhost:9200/index/_search?pretty" -H 'Content-Type: application/json' -d'{"query": {"script_score": {"query": {"match": { "body": "elasticsearch" }      },"script": {"source": "_score * saturation(doc[u0027pageranku0027].value, 10)"      }    }  }}'

尽管这两个选项都将返回相似的分数,但需要权衡取舍:script_score提供了很大的灵活性,使您可以根据需要将文本相关性分数与静态信号结合起来。另一方面,rank_feature查询仅提供了几种将静态信号混合到评分中的方法。但是,它依赖于rank_feature和rank_features字段,它们以一种特殊的方式索引值,从而使rank_feature查询可以跳过非竞争性文档并更快地获得查询的顶部匹配项。

写入优化

加大translog flush间隔,目的是降低iops、writeblock。

从ES 2.x开始,在默认设置下,translog的持久化策略为:每个请求都“flush”。对应配置项如下:index.translog.durability: request

这是影响 ES 写入速度的最大因素。但是只有这样,写操作才有可能是可靠的。如果系统可以接受一定概率的数据丢失(例如,数据写入主分片成功,尚未复制到副分片时,主机断电。由于数据既没有刷到Lucene,translog也没有刷盘,恢复时translog中没有这个数据,数据丢失),则调整translog持久化策略为周期性和一定大小的时候“flush”,例如:index.translog.durability: async

设置为async表示translog的刷盘策略按sync_interval配置指定的时间周期进行。

index.translog.sync_interval: 120s

加大index refresh间隔,除了降低I/O,更重要的是降低了segment merge频率。

每次索引的refresh会产生一个新的Lucene段,这会导致频繁的segment merge行为使更改对搜索可见的操作(称为刷新)非常昂贵,并且在正在进行索引活动的情况下经常进行调用会损害索引速度。

默认情况下,Elasticsearch会定期每秒刷新一次索引,但仅在最近30秒内已收到一个或多个搜索请求的索引上刷新。

如果您没有或只有很少的搜索流量(例如,每5分钟少于一个搜索请求)并且想要优化索引速度,则这是最佳配置。此行为旨在在不执行搜索时在默认情况下自动优化批量索引。为了选择退出此行为,请显式设置刷新间隔。

另一方面,如果您的索引遇到常规搜索请求,则此默认行为表示Elasticsearch将每1秒刷新一次索引。如果您有能力增加从索引到文档可见之间的时间,则可以将index.refresh_interval增加到更大的值,例如30s,可能有助于提高索引速度。

调整bulk请求。

批量请求将比单文档索引请求产生更好的性能。为了知道批量请求的最佳大小,您应该在具有单个分片的单节点上运行基准测试。首先尝试一次索引100个文档,然后索引200个,再索引400个,依此类推。在每次基准测试运行中,批量请求中的文档数量加倍。当索引速度开始趋于平稳时,您便知道已达到批量请求数据的最佳大小。如果得分相同,宁可少也不要多。当大量请求同时发送时,请注意太大的批量请求可能会使集群处于内存压力下,因此,建议即使每个请求看起来执行得更好,也要避免每个请求超过几十兆字节。

如果 CPU 没有压满,则应该提高写入端的并发数量。但是要注意 bulk线程池队列的reject情况,出现reject代表ES的bulk队列已满,客户端请求被拒绝,此时客户端会收到429错误(TOO_MANY_REQUESTS),客户端对此的处理策略应该是延迟重试。不可忽略这个异常,否则写入系统的数据会少于预期。即使客户端正确处理了429错误,我们仍然应该尽量避免产生reject。因此,在评估极限的写入能力时,客户端的极限写入并发量应该控制在不产生reject前提下的最大值为宜。

bulk线程池和队列

建立索引的过程属于计算密集型任务,应该使用固定大小的线程池配置,来不及处理的任务放入队列。线程池最大线程数量应配置为CPU核心数+1,这也是bulk线程池的默认设置,可以避免过多的上下文切换。队列大小可以适当增加,但一定要严格控制大小,过大的队列导致较高的GC压力,并可能导致FGC频繁发生。


推荐
关闭