说明
本文描述问题及解决方法适用于 腾讯云 Elasticsearch Service(ES)。
背景
随着互联网技术的蓬勃发展,我们面临着日益复杂的海量数据。在这种背景下,用于全文搜索和大数据分析的 Elasticsearch 成为了开发者们解决这一问题的首选。然而,面对如此强大的功能,很多用户会陷入误区,忽略了 Elasticsearch 本身也需要优化的现实。本篇博客将结合工作经验,详细介绍 Elasticsearch 优化的一些实用技巧,为您的 Elasticsearch 实战之旅提供有力支持。
一、单个分片大小控制在30GB左右
在不涉及高速缓存时,最小查询延迟取决于数据、查询类型、分片大小。查询大量小分片,虽然单个分片速度快,但是更多的查询任务排队处理,导致不一定比更大的分片快。 分片过大,会导致单个分片耗时过多。
不合理的后果:
- 单个节点磁盘占用过多,或单块磁盘占用过多,资源浪费。
- 影响集群查询性能
二、集群总分片数控制在3万以内
ES 每个分片的本质是一个Lucene索引,会消耗相应的文件句柄,内存和CPU资源。 分片少时,单个节点的分片数有限,同节点资源竞争的问题不大,Lucene本身的资源消耗也不大。 但当分片数过大时,单个节点资源竞争的情况会加剧,容易导致节点响应超时,影响整个集群的响应。 从ES实际运维经验来看,控制在3万以内较安全。
三、不要在单个index使用多个type
ES版本在5.x/6.x时,还支持单index多个type。 但从6.8.2版本开始,单个index只支持一个type,默认_doc。 从7.x开始,不建议使用type,如果集群日志会提示type废弃。 从8.x开始,完全禁用type的使用。 因此为了以后进行集群升级的方便,应该在ES早期 版本应规避多type的使用。
四、避免使用dynamic mapping
当启用dynamic mapping时,如果写入的记录中带有新的field,会触发mapping更新。 以tsf集群为例,由于业务中引入新field,导致集群不停更新mapping,集群压力大,导致mapping 更新超时,集群red,写入跌0 建议将dynamic设置为strict。
五、控制单shard的docs数不超过21亿
ES对于单个shard的docs数有21亿的限制,上线index前,提前预估好每个shard的分片数,建议控制在15亿以内。 Per_shard_docs = index_total_docs/number_of_shard
六、查询中提供明确的超时
几乎所有的elasticsearch api都允许用户指定超时。 提前终止耗时长的操作,避免正常请求受到牵连,对于节省系统资源,建立稳定的ES服务,有很大的帮助。 以tsf业务为例: 一条复杂查询请求,由于没有超时设计,导致ctsdb整个集群持续old gc,服务不可用,集群所有读写跌0。
七、不要长期使用单个index,必须定期滚动
使用index时,需要做好定期切换的计划。写入不大的情况下,建议按天、月滚动。 定期滚动的好处:
- 控制单个index的大小,提升读写性能。
- 防止单个index过大,影响故障恢复的时间。
- 避免热index过大,影响cos备份恢复时间。
八、合理设置bulk size大小
Bulk size的合适与否对集群写入性能影响较大。一般建议在1万上下浮动,单次请求控制在10~15MB左右。 单个集群短时间内能承受的最大写入并发数: num_of_node * bulk_queue_size
九、对于写少存多的业务,开启Best_compression压缩
ES作为一款大数据产品,存放的数据量都在几十~上百T以上,且为了满足近实时的查询性能,往往都需要SSD作为存储,因此存储成本较高。为了尽量节约存储成本的开销,建议开启best-compression压缩。
十、合理设置string类型
5.X之后,String被分成两种类型,text和keyword。 二者区别: text:适用分词全文检索场景 keyword:适用字符串的精准匹配场景 实战中,通常面临:
- 需不需要分词,不需要,则仅保留keyword即可。
- 需要用什么分词,英文分词还是中文分词。
- 分词后是否需要排序和聚合,即fielddata是否需要打开。
是否需要精准匹配,即是否保留keyword 默认:
代码语言:javascript复制{
"foo":{
"type":"text",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
}
}
十一、合理控制段合并
在Lucene中,文档存储在segment中,后台的ES通常在以下两种模式下连续维护Lucene段:
- 当删除或更新文档时,旧文档被标记为已删除,新文档被创建,ES会跟踪这些标记为delete的文档,适时对其进行合并。
- 新添加的文档可能会产生大小不平衡的段。ES可能出于优化目的而决定将它们合并为更大的段。 段合并是高度受磁盘IO和CPU约束的操作。 找到translog flush的最优配置。通过尝试调整index.translog.sync_interval和index.translog.flush_threshold_size的设置。 对于实时性要求不高的场景,可以调大刷新频率。(refresh_interval,官方默认1s,CES默认5s,可以适当调到30s甚 至更大)
十二、规避过度聚合查询
多层嵌套查询,会消耗比较大的CPU、内存,尤其是接收查询的协调节点,会有较高的CPU和内存压力,极端情况下,会导致节点old gc,请求超时,影响整个集群的响应。从目前线上的经验来看,单次聚合查询,一般100w分桶消耗在10GB内存左右。线上16C64G规格集群,建议控制聚合查询在3层嵌套100w分桶以下。
十三、正确理解模版order属性
ES的模版中,适用于相同index的模版,会按照order顺序,从低到高,逐级生效。高order模版会覆盖之前低order模版的相同设置。 假如有匹配logstash-*, 且order为1、2、3的三个template, number_of_shards设置依次为1、2、3,那么业务写入一个logstash@2020-8-19的index时,生成的index,将有3个主分片。 Ps:CES在每个集群中会有一个默认的order为0的 default@template模版,务必不要删除该模版,否则会影响一些OSS的管控操作。
十四、善用别名
善于使用别名的好处:
- 应用与索引名称的解藕。
- 方便的实现跨索引检索。
- 索引变换期间,零停服
十五、避免过度使用Pipeline
Pipeline提供了ES预处理的能力,类似于MySQL的SP,但是过多的pipeline使用,会增大es集群元数据管理的压力,消耗ES有限的计算资源。 建议将pipeline的要完成的工作,在程序端,或借助logstash等预处理工具,提前处理好,再写入ES,让ES专注于最核心的存储和搜索。类似于大家在使用MySQL时,要避免使用SP一样。 以TSF业务的为例: 业务在设计时,为每个用户自动创建一个pipeline,导致集群产生几千个pipeline任务,导致集群频繁的进行大规模元数据更新,且在升级6.8.x时,触发了pipeline遍历更新的bug。
我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!