ES是一个非常完善的搜索引擎,可以用于业务搜索、数据分析,其周边生态产品也十分丰富;
正是由于ES的完善与通用性,用户使用ES的场景越来越多样化,通用的配置已经无法达到用户的稳定性需求,并且难以给出通用的最佳实践,需要专门的为某些场景进行调优。
例如,update频繁的场景下的性能调优。
ES的使用场景
1.在线搜索(垂直搜索+全文检索)
2.数据分析与日志
ES最初设计的就是一个搜索引擎,对全文检索更是“擅长”,准确且简单;后面由于性能的不断提升,集群规则的扩大,使得ES在OLAP(数据分析)场景也有很大的发挥空间;
无论是在线搜索还是数据分析,其使用场景依然是一个“上层”,并不作为一个最底层的数据源,数据链路依然是从DB数据源--->ES,这也是比较推荐的使用方式。
ES不是数据库,没有事务、不保证任何情况下都不会丢失数据(数据先写lucene再写translog),以及近实时的特性,ES并不非常适合极其频繁的update场景。尽管如此,ES依然允许被这样使用,只是需要进行一些调优;
问题是什么?
有用户提出,update接口偶尔(一天3-4次)会出现请求耗时很高(1s+)的情况;
监控观察下来并没有在异常请求的时间点出现不正常的现象。
请求链路:用户service->gateway->ES集群实例
从日志看下来,时间主要用在从gateway发送请求到gateway得到ES的响应;由于是update请求,不会存在大量的网络IO,所以问题大概率出现在ES处理请求上。
分析
1.由于是频繁的update请求,很容易发现有大量的is_deleted文件,该现象主要影响查询性能,可通过forcemerge处理,实验下来对update毛刺没有任何影响,符合预期。(补充:segment过多也会影响查询性能,由于每个分片单独merge,出现的segment在某些分片上过多的情况也会造成查询的毛刺)
2.用户根据我们提供的“最佳实践”文档,计算出了主副分片的设置,由于数据量不大,最终算出来是primary=1,replica=4,于是update场景下副本数过多,更容易造成长尾效应。
可以看到update的耗时等于node1上主分片update的耗时加上node2,node3,node4,node5中耗时的最大值。这样副本越多也就越容易出现长尾效应。
这里再提一点:wait_for_active_shards参数经常被误认为是控制写入请求同步分片的数量(认为在wait_for_active_shards=2的时候只需要等待1主+任意一个副本返回成功,即可响应给客户端)。实际上该参数表示需要写入成功wait_for_active_shards个分片才算写入成功。可以看到该参数默认是1,也就是说只要写入主分片成功就算此次请求成功,但是依然需要等待所有副本都响应了,才能返回客户端。
该参数是用来保证数据不丢失的,例如wait_for_active_shards=2,需要至少写入1主1副才算此次请求成功,这样一致性会更高,但相应的写入性能会更差。
3.translog同步顺序写,在translog清空、翻滚的时候会有writeLock,也可能造成等待,导致update请求出现毛刺。可以将translog设置成异步,相应的异步丢数据的可能性就会增加。
4.官方推荐使用SSD,且esrally测试结果普通SSD在大多场景下都表现比HDD好(成本问题没有考虑Nvme)。目前该用户集群使用HDD,调整成SSD。
5.之前有看到文章描述当使用BulkShardRequest时,ES的定期refresh的过程中可能出现write线程帮助refresh线程进行refresh的情况,从而导致write线程堵塞。该场景本文没有实际验证过。
问题解决
通过观察毛刺出现的频率,大概是每小时出现一波;
发现translog是同步的,且软删除保留的是1h得到translog
"soft_deletes":{
"retention_lease":{
"period": "1h"
}
}
修改后问题解决:
# 1.改成异步
"translog": {
"sync_interval": "60s",
"durability": "async"
}
# 2.soft_deletes配置删除(即使用默认的,也就是12h)
修改完成后:
最后
如有描述不准确的地方欢迎指正~
有其他思路欢迎补充~