0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

elasticsearch检索原理与优化案例

工程师邓生 来源:博客园 作者:mikevictor 2022-09-30 17:25 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

一、前言

数据平台已迭代三个版本,从头开始遇到很多常见的难题,终于有片段时间整理一些已完善的文档,在此分享以供所需朋友的

实现参考,少走些弯路,在此篇幅中偏重于ES的优化,关于HBase,Hadoop的设计优化估计有很多文章可以参考,不再赘述。

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

二、需求说明

项目背景:

在一业务系统中,部分表每天的数据量过亿,已按天分表,但业务上受限于按天查询,并且DB中只能保留3个月的数据(硬件高配),分库代价较高。

改进版本目标:

数据能跨月查询,并且支持1年以上的历史数据查询与导出。

按条件的数据查询秒级返回。

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

三、elasticsearch检索原理

3.1 关于ES和Lucene基础结构

谈到优化必须能了解组件的基本原理,才容易找到瓶颈所在,以免走多种弯路,先从ES的基础结构说起(如下图):

e89c4d76-3970-11ed-9e49-dac502259ad0.jpg

一些基本概念:

Cluster 包含多个Node的集群

Node 集群服务单元

Index 一个ES索引包含一个或多个物理分片,它只是这些分片的逻辑命名空间

Type 一个index的不同分类,6.x后只能配置一个type,以后将移除

Document 最基础的可被索引的数据单元,如一个JSON串

Shards 一个分片是一个底层的工作单元,它仅保存全部数据中的一部分,它是一个Lucence实例 (一个lucene索引最大包含2,147,483,519 (= Integer.MAX_VALUE - 128)个文档数量)

Replicas 分片备份,用于保障数据安全与分担检索压力

ES依赖一个重要的组件Lucene,关于数据结构的优化通常来说是对Lucene的优化,它是集群的一个存储于检索工作单元,结构如下图:

e8d7e336-3970-11ed-9e49-dac502259ad0.jpg

在Lucene中,分为索引(录入)与检索(查询)两部分,索引部分包含 分词器过滤器字符映射器 等,检索部分包含 查询解析器 等。

一个Lucene索引包含多个segments,一个segment包含多个文档,每个文档包含多个字段,每个字段经过分词后形成一个或多个term。

通过Luke工具查看ES的lucene文件如下,主要增加了_id和_source字段:

e91f2804-3970-11ed-9e49-dac502259ad0.jpg

3.2 Lucene索引实现

Lucene 索引文件结构主要的分为:词典、倒排表、正向文件、DocValues等,如下图:

e93e9a68-3970-11ed-9e49-dac502259ad0.jpge98bfaf6-3970-11ed-9e49-dac502259ad0.jpg

注:整理来源于lucene官方

Lucene 随机三次磁盘读取比较耗时。其中.fdt文件保存数据值损耗空间大,.tim和.doc则需要SSD存储提高随机读写性能。

另外一个比较消耗性能的是打分流程,不需要则可屏蔽。

关于DocValues:

倒排索引解决从词快速检索到相应文档ID, 但如果需要对结果进行排序、分组、聚合等操作的时候则需要根据文档ID快速找到对应的值。

通过倒排索引代价缺很高:需迭代索引里的每个词项并收集文档的列里面 token。这很慢而且难以扩展:随着词项和文档的数量增加,执行时间也会增加。Solr docs对此的解释如下:

For other features that we now commonly associate with search, such as sorting, faceting, and highlighting, this approach is not very efficient. The faceting engine,

for example, must look up each term that appears in each document that will make up the result set and pull the document IDs in order to build the facet list. In Solr, this is maintained in memory, and can be slow to load (depending on the number of documents, terms, etc.)

在lucene 4.0版本前通过FieldCache,原理是通过按列逆转倒排表将(field value ->doc)映射变成(doc -> field value)映射,问题为逐步构建时间长并且消耗大量内存,容易造成OOM。

DocValues是一种列存储结构,能快速通过文档ID找到相关需要排序的字段。在ES中,默认开启所有(除了标记需analyzed的字符串字段)字段的doc values,如果不需要对此字段做任何排序等工作,则可关闭以减少资源消耗。

3.3 关于ES索引与检索分片

ES中一个索引由一个或多个lucene索引构成,一个lucene索引由一个或多个segment构成,其中segment是最小的检索域。

数据具体被存储到哪个分片上:

shard=hash(routing)%number_of_primary_shards

默认情况下 routing参数是文档ID (murmurhash3),可通过 URL中的 _routing 参数指定数据分布在同一个分片中,index和search的时候都需要一致才能找到数据

如果能明确根据_routing进行数据分区,则可减少分片的检索工作,以提高性能。

四、优化案例

在我们的案例中,查询字段都是固定的,不提供全文检索功能,这也是几十亿数据能秒级返回的一个大前提:

ES仅提供字段的检索,仅存储HBase的Rowkey不存储实际数据。

实际数据存储在HBase中,通过Rowkey查询,如下图。

一些细节优化项官方与其他的一些文章都有描述,在此文章中仅提出一些本案例的重点优化项。

e9bcafde-3970-11ed-9e49-dac502259ad0.jpg

4.1 优化索引性能

1、批量写入 ,看每条数据量的大小,一般都是几百到几千。

2、多线程写入 ,写入线程数一般和机器数相当,可以配多种情况,在测试环境通过Kibana观察性能曲线。

3、增加segments的刷新时间 ,通过上面的原理知道,segment作为一个最小的检索单元,比如segment有50个,目的需要查10条数据,但需要从50个segment分别查询10条,共500条记录,再进行排序或者分数比较后,截取最前面的10条,丢弃490条。

在我们的案例中将此 "refresh_interval": "-1" ,程序批量写入完成后进行手工刷新(调用相应的API即可)。

4、内存分配方面 ,很多文章已经提到,给系统50%的内存给Lucene做文件缓存,它任务很繁重,所以ES节点的内存需要比较多(比如每个节点能配置64G以上最好)。

5、磁盘方面配置SSD机械盘做阵列RAID5 RAID10虽然看上去很快,但是随机IO还是SSD好。

6、 使用自动生成的ID ,在我们的案例中使用自定义的KEY,也就是与HBase的ROW KEY,是为了能根据rowkey删除和更新数据,性能下降不是很明显。

7、关于段合并 ,合并在后台定期执行,比较大的segment需要很长时间才能完成,为了减少对其他操作的影响(如检索),elasticsearch进行阈值限制,默认是20MB/s,

可配置的参数:"indices.store.throttle.max_bytes_per_sec" : "200mb" (根据磁盘性能调整)

合并线程数默认是:Math.max(1, Math.min(4, Runtime.getRuntime().availableProcessors() / 2)),

如果是机械磁盘,可以考虑设置为1:index.merge.scheduler.max_thread_count: 1,在我们的案例中使用SSD,配置了6个合并线程。

4.2 优化检索性能

1、关闭不需要字段的doc values。

2、尽量使用keyword替代一些long或者int之类,term查询总比range查询好 (参考lucene说明 )。

http://lucene.apache.org/core/7_4_0/core/org/apache/lucene/index/PointValues.html

3、关闭不需要查询字段的_source功能,不将此存储仅ES中,以节省磁盘空间。

4、评分消耗资源,如果不需要可使用filter过滤来达到关闭评分功能,score则为0,如果使用constantScoreQuery则score为1。

5、关于分页:

from + size: 每分片检索结果数最大为 from + size,假设from = 20, size = 20,则每个分片需要获取20 * 20 = 400条数据,多个分片的结果在协调节点合并(假设请求的分配数为5,则结果数最大为 400*5 = 2000条) 再在内存中排序后然后20条给用户。

这种机制导致越往后分页获取的代价越高,达到50000条将面临沉重的代价,默认from + size默认如下:index.max_result_window :10000

search_after: 使用前一个分页记录的最后一条来检索下一个分页记录

在我们的案例中,首先使用from+size,检索出结果后再使用search_after,在页面上我们限制了用户只能跳5页,不能跳到最后一页。

scroll: 用于大结果集查询,缺陷是需要维护scroll_id

6、关于排序:我们增加一个long字段,它用于存储时间和ID的组合(通过移位即可),正排与倒排性能相差不明显。

7、关于CPU消耗,检索时如果需要做排序则需要字段对比,消耗CPU比较大,如果有可能尽量分配16cores以上的CPU,具体看业务压力。

8、关于合并被标记删除的记录,我们设置为0表示在合并的时候一定删除被标记的记录,默认应该是大于10%才删除:"merge.policy.expunge_deletes_allowed": "0"。

{
"mappings":{
"data":{
"dynamic":"false",
"_source":{
"includes":["XXX"]--仅将查询结果所需的数据存储仅_source中
},
"properties":{
"state":{
"type":"keyword",--虽然state为int值,但如果不需要做范围查询,尽量使用keyword,因为int需要比keyword增加额外的消耗。
"doc_values":false--关闭不需要字段的doc values功能,仅对需要排序,汇聚功能的字段开启。
},
"b":{
"type":"long"--使用了范围查询字段,则需要用long或者int之类(构建类似KD-trees结构)
}
}
}
},
"settings":{......}
}

五、性能测试

优化效果评估基于基准测试,如果没有基准测试无法了解是否有性能提升,在这所有的变动前做一次测试会比较好。在我们的案例中:

单节点5千万到一亿的数据量测试,检查单点承受能力。

集群测试1亿-30亿的数量,磁盘IO/内存/CPU/网络IO消耗如何。

随机不同组合条件的检索,在各个数据量情况下表现如何。

另外SSD与机械盘在测试中性能差距如何。

性能的测试组合有很多,通常也很花时间,不过作为评测标准时间上的投入有必要,否则生产出现性能问题很难定位或不好改善。

对于ES的性能研究花了不少时间,最多的关注点就是lucene的优化,能深入了解lucene原理对优化有很大的帮助。

六、生产效果

目前平台稳定运行,几十亿的数据查询100条都在3秒内返回,前后翻页很快,如果后续有性能瓶颈,可通过扩展节点分担数据压力。


审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • SSD
    SSD
    +关注

    关注

    21

    文章

    3174

    浏览量

    122804
  • 过滤器
    +关注

    关注

    1

    文章

    444

    浏览量

    21119
  • RBAC
    +关注

    关注

    0

    文章

    44

    浏览量

    10457

原文标题:Elasticsearch 亿级数据检索性能优化案例实战

文章出处:【微信号:芋道源码,微信公众号:芋道源码】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    Elasticsearch7.x搜索实战

    紧跟技术前沿:ES 7.x 结合大模型打造智能检索系统 在数据呈指数级增长的今天,传统的关键词检索已难以满足用户对精准、智能、个性化检索结果的需求。Elasticsearch 7.x(
    发表于 05-22 10:52

    搜索引擎ElasticSearch8.X+SpringBoot3.X最佳实践elk/es,ES8搜索引擎从基础入门到深度原理,实现综合运用实战

    回车后必须在毫秒级返回结果——传统的数据库已经远远不够用了。 这时候,Elasticsearch 8.0站了出来。它不仅是当前分布式检索领域的事实标准,更是未来三年每一位后端开发者、数据工程师、SRE必须掌握的核心技能。而搭建一个生产级别
    的头像 发表于 05-20 13:47 108次阅读

    [VirtualLab] 光纤耦合优化

    和对准系统是确保耦合效率的基本步骤。 快速物理光学建模和设计软件VirtualLab Fusion可以对耦合透镜等核心部件进行仿真和优化,从而设计耦合系统,分析耦合系统的性能和稳健性。作为对这个主题
    发表于 05-12 08:19

    FRED应用:目标平面特定照度分布优化

    摘要 本章主要讲述如何利用FRED 优化功能修改模型并且达到想要的目标平面照度分布。要优化的模型是PMMA 导光管,6个变量控制着导光管的形状,优化评价函数是当前照度和理想照度之差,通过用户自定义
    发表于 04-27 08:18

    VirtualLab:光栅的优化与分析

    | | 光栅是光学工程师使用的最基本的工具。为了设计和分析这类组件,快速物理光学建模和设计软件VirtualLab Fusion为用户提供了许多有用的工具。其中包括参数优化,以轻松优化系统,以及参数
    发表于 04-23 08:17

    [VirtualLab] 倾斜光栅的参数优化及公差分析

    ,也称为RCWA)对倾斜光栅的优化方法。优化后的光栅的衍射效率超过90%。此外,还研究了其对光栅的倾角偏差和圆角边缘的影响。 建模任务 **优化 ** 为了为倾斜光栅找到一组优化
    发表于 04-22 08:18

    RAG(检索增强生成)原理与实践

    text-embedding-3-small/large :性能强大,支持多语言 sentence-transformers :开源方案,适合中文 BGE系列 :国内优秀的开源模型 m3e :专门针对中文优化 2.2 向量检索的工作流
    发表于 02-11 12:46

    从0到1搭建实时日志监控系统:基于WebSocket + Elasticsearch的实战方案

    低成本、实时性高的日志监控系统。 2. 技术选型 数据存储 :Elasticsearch(高效检索与聚合) 实时推送 :WebSocket(全双工通信,避免HTTP轮询) 后端服务 :Node.js
    发表于 01-09 16:43

    请问Keil的优化等级到底该如何选择?

    在Keil MDK(Microcontroller Development Kit)中,优化等级是编译器的核心设置之一,它直接影响生成代码的大小、执行速度和调试便利性。选择合适的优化等级是平衡性
    发表于 11-20 07:51

    蜂鸟E203内核优化方法

    对蜂鸟E203内核进行优化可以考虑以下几个方面: 编译器优化:使用适合蜂鸟E203的编译器选项和指令集,优化编译器的选项和参数,开启对硬件的特定支持,比如使用-O2等优化选项,以提高代
    发表于 10-21 07:55

    格灵深瞳突破文本人物检索技术难题

    格灵深瞳参与研究的GA-DMS框架,为攻破上述技术难题提供了全新解决方案。研究团队通过数据构建和模型架构的协同改进,推动CLIP在人物表征学习中的应用,显著提升了基于文本的人物检索效果。该成果已入选EMNLP 2025 主会(自然语言处理领域的顶级国际会议之一)。
    的头像 发表于 09-28 09:42 817次阅读
    格灵深瞳突破文本人物<b class='flag-5'>检索</b>技术难题

    孔夫子旧书网开放平台接口实战:古籍图书检索与商铺数据集成

    本文详解孔夫子旧书网古籍数据接口的实战调用,涵盖认证签名、古籍检索、商铺集成与特色数据处理四大场景,提供可复用的Python代码及避坑指南,助力学术研究、旧书商管理与古籍数字化落地。
    的头像 发表于 09-23 13:59 970次阅读

    阿里巴巴开放平台关键字搜索商品接口实战详解:OAuth2.0 认证落地 + 检索效率优化(附避坑代码)

    、签名失败、检索频率超限三大坑,导致接口调用成功率低、数据获取效率差。本文结合 10 年电商 API 对接经验,从 “认证落地 - 参数优化 - 效率提升 - 错误排查” 全流程拆解,所有代码均经实战验证,可直接复用,帮你避开 90% 的调用问题。
    的头像 发表于 09-16 16:26 1196次阅读

    如何二进制安装Linux集群

    ElasticSearch是使用Java语言开发的,所以运行时依赖JDK。
    的头像 发表于 06-17 14:49 1219次阅读

    鸿蒙5开发宝藏案例分享---优化应用时延问题

    鸿蒙性能优化宝藏指南:6大实战案例让你的应用飞起来! 大家好!今天在翻鸿蒙文档时挖到了 性能优化宝藏库 !官方竟然悄悄藏了这么多实战案例,从UI渲染到数据库操作应有尽有。这些案例要是早发现,我上周
    发表于 06-13 10:08