本文来源 | https://zhuanlan.zhihu.com/p/60458049
导读:如果面试的时候碰到这样一个面试题:ES 在数据量很大的情况下(数十亿级别)如何提高查询效率?
这个问题,其实就是在看你是否用过 ES,其实 ES 性能并没有你想象中那么好的。很多时候数据量大了,特别是有几亿条数据的时候,可能你会懵逼的发现,跑个搜索怎么一下 5~10s。
第一次搜索的时候,是5~10s,后面反而就快了,可能就几百毫秒。
你就很懵,每个用户第一次访问都会比较慢,比较卡么?所以你要是没玩儿过 ES,或者就是自己玩玩儿 Demo,被问到这个问题容易懵逼,显示出你对 ES 确实玩的不怎么样。
说实话,ES 性能优化是没有银弹的,不要期待着随手调一个参数,就可以万能的应对所有性能慢的场景。也许有的场景你换个参数,或者调整一下语法,就可以搞定,但绝对不是所有场景都可以这样。
性能优化的杀手锏:Filesystem Cache
你向 ES 里写的数据,实际上都写到磁盘文件里去了,查询的时候,操作系统会将磁盘文件里的数据自动缓存到 Filesystem Cache 里面去。
ES 的搜索引擎严重依赖于底层的 Filesystem Cache,如果给 Filesystem Cache 更多的内存,尽量让内存可以容纳所有的 IDX Segment File 索引数据文件,那么你在搜索的时候基本都会走内存且性能会非常高。
性能差距究竟可以有多大?我们之前很多的测试和压测,如果走磁盘一般肯定上秒,搜索性能绝对是秒级别的,1 秒、5 秒、10 秒。但如果走 Filesystem Cache,则是走纯内存的,那么一般来说性能比走磁盘要高一个数量级,基本上就是毫秒级的,从几毫秒到几百毫秒不等。
这里有个真实的案例:某个公司 ES 节点有 3 台机器,每台机器看起来内存很多(64G),总内存就是 64 * 3 = 192G。
每台机器给 ES JVM Heap 是 32G,那么剩下来留给 Filesystem Cache 的就是每台机器才 32G,总共集群里给 Filesystem Cache 的就是 32 * 3 = 96G 内存。
而此时,整个磁盘上索引数据文件,在 3 台机器上一共占用了 1T 的磁盘容量,ES 数据量是 1T,那么每台机器的数据量是 300G。这样性能好吗?
Filesystem Cache 的内存才 100G,十分之一的数据可以放内存,其它的都在磁盘,然后你执行搜索操作,大部分操作都是走磁盘,性能肯定差。
根据我们自己的生产环境实践经验,最佳的情况下,是仅仅在 ES 中就存少量的数据,就是你要用来搜索的那些索引,如果内存留给 Filesystem Cache 的是 100G,那么你就将索引数据控制在 100G 以内即可。这样,你的数据几乎全部走内存来搜索,性能非常之高,一般可以在1秒以内。
比如,你现在有一行数据:id,name,age .... 30 个字段。但是你现在搜索,只需要根据 id,name,age 三个字段来搜索。如果你傻乎乎往 ES 里写入一行数据所有的字段,就会导致 90% 的数据无法用来搜索。
结果硬是占据了 ES 机器上的 Filesystem Cache 的空间,单条数据的数据量越大,就会导致 Filesystem Cahce 能缓存的数据就越少。
其实,仅仅写入 ES 中要用来检索的少数几个字段就可以了,比如写入 es id,name,age 三个字段。
然后你将其他的字段数据存在 MySQL/HBase 里,我们一般是建议用 ES + HBase 这个架构。
HBase 的特点是适用于海量数据的在线存储,就是对 HBase 可以写入海量数据,但是不要做复杂的搜索,做很简单的一些根据 id 或者范围进行查询的操作就可以了。
从 ES 中根据 name 和 age 去搜索,拿到的结果可能就 20 个 doc id,然后根据 doc id 到 HBase 里去查询每个 doc id 对应的完整的数据,查出来后再返回给前端。
写入 ES 的数据最好小于等于,或者是略微大于 ES 的 Filesystem Cache 的内存容量。你从 ES 检索可能只花费 20ms,然后再根据 ES 返回的 id 去 HBase 里查询,查 20 条数据,可能只耗费 30ms。
可能你原来那么玩儿,1T 数据都放 ES,会每次查询都是 5~10s,现在可能性能就会很高,每次查询就是 50ms。
数据预热
假如你按照上述的方案去做了,ES 集群中每个机器写入的数据量还是超过了 Filesystem Cache 一倍。那么可以做数据预热。拿微博举例,你可以把一些大 V,平时看的人很多的数据,提前在后台搞个系统。
每隔一会儿,去搜索一下热数据,刷到 Filesystem Cache 里去,后面用户实际来看这个热数据的时候,他们就是直接从内存里进行了搜索。又或者是电商,你可以将平时查看最多的一些商品,例如 iPhone 8,热数据提前后台搞个程序,每隔 1 分钟自己主动访问一次,刷到 Filesystem Cache 里去。
对于那些你觉得比较热的、经常会有人访问的数据,最好做一个专门的缓存预热子系统。就是对热数据每隔一段时间,就提前访问一下,让数据进入 Filesystem Cache 里面去。这样下次别人访问的时候,性能一定会好很多。
冷热分离
ES 可以做类似于 MySQL 的水平拆分,即将大量的访问很少、频率很低的数据,单独写一个索引,然后将访问很频繁的热数据单独写一个索引。
最好将冷数据写入一个索引中,然后热数据写入另外一个索引中,这样可以确保热数据在被预热之后,尽量都让他们留在 Filesystem OS Cache 里。
假设你有 6 台机器,2 个索引,一个放冷数据,一个放热数据,每个索引 3 个 Shard。3 台机器放热数据 Index,另外 3 台机器放冷数据 Index。
那么,你大量的时间是在访问热数据 Index,热数据可能就占总数据量的 10%,此时数据量很少,几乎全都保留在 Filesystem Cache 里面了,就可以确保热数据的访问性能是很高的。
但是对于冷数据而言,是在别的 Index 里的,跟热数据 Index 不在相同的机器上。
如果有人访问冷数据,可能大量数据是在磁盘上的,此时性能差点,就 10% 的人去访问冷数据,90% 的人在访问热数据,也无所谓了。
Document 模型设计
对于 MySQL,我们经常有一些复杂的关联查询。在 ES 里该怎么玩儿,ES 中复杂的关联查询尽量别用,一旦用了性能一般都不太好。
最好是先在 Java 系统里就完成关联,将关联好的数据直接写入 ES 中。搜索的时候,就不需要利用 ES 的搜索语法来完成 Join 之类的关联搜索了。
Document 模型设计是非常重要的,很多操作,不要在搜索的时候才想去执行各种复杂的乱七八糟的操作。
ES 能支持的操作就那么多,不要考虑用 ES 做一些它不好操作的事情。如果真的有那种操作,尽量在 Document 模型设计的时候,写入的时候就完成,另外对于一些太复杂的操作,比如 join/nested/parent-child 搜索都要尽量避免,性能都很差的。
分页性能优化
ES 的分页是较坑的。假如你每页是 10 条数据,你现在要查询第 100 页,实际上是会把每个 Shard 上存储的前 1000 条数据都查到一个协调节点上。
如果你有 5 个 Shard,那么就有 5000 条数据,接着协调节点对这 5000 条数据进行一些合并、处理,再获取到最终第 100 页的 10 条数据。
分布式则要查第 100 页的 10 条数据,不可能从 5 个 Shard中,每个查 2 条数据,最后到协调节点合并成 10 条数据吧?
所以,你必须得从每个 Shard 都查 1000 条数据过来,然后根据你的需求进行排序、筛选等操作,最后再次分页,拿到里面第 100 页的数据。
在翻页的时候,你翻的越深,每个 Shard 返回的数据就越多,而且协调节点处理的时间越长。所以用 ES 做分页的时候,你会发现越翻到后面,就越是慢。
我们之前也是遇到过这个问题,用 ES 做分页,前几页就几十毫秒,翻到 10 页或者几十页的时候,基本上就要 5~10 秒才能查出来一页数据了。
有什么解决方案吗?不允许深度分页(默认深度分页性能很差),跟产品经理提出这个问题。
类似于 App 里的推荐商品不断下拉出来一页一页的;类似于微博中,下拉刷微博,刷出来一页一页的,你可以用 Scroll API,关于如何使用,自行上网搜索。
Scroll 会一次性给你生成所有数据的一个快照,然后每次滑动向后翻页就是通过游标 scroll_id 移动,获取下一页、下一页这样子,性能会比上面说的那种分页性能要高很多,基本上都是毫秒级的。但是,这种只适合于类似微博下拉翻页的,不能随意跳到任何一页的场景。
所以现在很多产品,都是不允许你随意翻页的,App、也有一些网站,做的就是你只能往下拉,一页一页的翻。
初始化时必须指定 Scroll 参数,告诉 ES 要保存此次搜索的上下文多长时间。你需要确保用户不会持续不断翻页翻几个小时,否则可能因为超时而失败。
除了用 Scroll API,你也可以用 search_after 来做。search_after 的思想是使用前一页的结果来帮助检索下一页的数据。显然,这种方式也不允许你随意翻页,你只能一页页往后翻。初始化时,需要使用一个唯一值的字段作为 Sort 字段。
活动推荐
2019年6月21-23日,GIAC全球互联网架构大会将在深圳举办,组委会从互联网架构最热门的Cloud-Native、IoT、人工智能等前沿技术、数据及商业智能、大中台、经典架构、工程文化及管理等领域甄选前沿的有典型代表的技术创新及研发实践的架构案例,邀请了BAT、美团、滴滴等企业技术专家为我们分享最新的技术成果。
相关推荐
2. **实时性能**:Elasticsearch支持实时索引和搜索,提供毫秒级响应时间。 3. **RESTful API**:Elasticsearch使用HTTP和JSON作为交互方式,通过简单的RESTful API进行操作,易于集成到各种应用中。 4. **弹性...
1. **高性能**:Elasticsearch 能够在毫秒级时间内返回搜索结果,适用于需要快速响应的应用场景。 2. **可扩展性**:Elasticsearch 设计为易于水平扩展,可以通过添加更多节点来扩展集群,以支持更大的数据量和更高...
### ElasticSearch概述与核心知识点 #### 一、ElasticSearch简介 ##### 1. ES定义 ElasticSearch 是一个基于 Apache Lucene 构建的分布式、实时搜索与分析引擎。它不仅仅提供了强大的全文检索功能,还能够进行...
Elasticsearch 的全局搜索功能是其强大之处,它允许用户在大规模数据集中执行复杂的搜索查询,并在毫秒级时间内返回结果。这得益于它的分布式架构,能够将搜索请求分散到多个节点上并行处理,然后聚合结果。全局搜索...
实时性:Elasticsearch 支持实时索引和搜索,能够在毫秒级别内返回搜索结果。 多租户:Elasticsearch 支持多租户架构,可以为不同的用户或应用程序提供独立的索引和搜索功能。 丰富的查询功能:Elasticsearch 提供...
这种索引方式极大地提高了搜索速度,使得Elasticsearch能够在毫秒级别内返回结果。 在Elasticsearch 5.6.0中,用户可以方便地通过RESTful API进行数据的增删改查操作。这些API基于HTTP协议,易于理解和使用。例如,...
倒排索引使得Elasticsearch能够在毫秒级别内返回搜索结果。 3. **RESTful API** 与传统数据库不同,Elasticsearch采用RESTful接口,允许开发者使用HTTP协议与之交互。这种轻量级的通信方式降低了使用门槛,使得...
- 快速全文检索:ElasticSearch 能够在几毫秒内返回查询结果。 - 实时分析:支持实时的统计和聚合功能,便于进行数据分析。 - 分布式处理:支持横向扩展,能够处理PB级别的数据。 - 数据可视化:集成 Kibana 等...
**Elasticsearch 知识点总结** Elasticsearch 是一个基于 Lucene 的...以上是 Elasticsearch 的核心概念及与 MySQL 的对比,涵盖了数据结构、操作方式以及数据类型等方面,展示了其在全文检索和大数据处理上的优势。
Elasticsearch 具备出色的搜索性能,能够在毫秒级别内返回搜索结果。这对于需要实时反馈的应用场景尤为重要,如实时查询或推荐系统等。 #### 灵活的数据存储 Elasticsearch 支持多种数据类型和结构,包括结构化、...
在Python编程中,Elasticsearch是一个非常流行的开源搜索引擎和分析工具,它允许开发者高效地存储、检索和分析大量数据。本文将详细介绍如何使用Python来实现从Elasticsearch中获取数据并进行分页显示的方法。 首先...
在租房系统中,Elasticsearch可以快速索引和搜索房源信息,如位置、价格、面积等,为用户提供毫秒级的搜索体验。通过设置合适的映射(Mapping),我们可以确保数据被正确地分析和存储,支持多种查询语法,如全文搜索...
Elasticsearch是一个分布式、RESTful风格的搜索和数据分析引擎,广泛应用于日志分析、实时监控、全文检索等多个场景。 1. **配置文件**:`elasticsearch.yml`是Elasticsearch的主要配置文件,用于设定节点和集群的...
- **毫秒级查询速度**:即使在写入大量数据的同时,也能保持极低的查询延迟。 **5. 支持各种数据类型** - **关系型与JSON数据**:不仅支持传统的关系型数据,还允许存储复杂的JSON文档,并可以直接在SQL查询中...
2. **索引构建**:Python的Trie数据结构或倒排索引库(如Whoosh或Elasticsearch)用于创建高效的索引,使搜索操作能在毫秒级别完成。 3. **查询解析**:Python负责解析用户的查询语句,理解其意图,并转化为搜索...
- **Elasticsearch**: 对于复杂的全文搜索需求,可以使用Elasticsearch进行处理,以提高查询速度。 **3. 查询优化** - **关联查询**: 通过合理的索引设计和适当的查询分解,可以减少锁的竞争。 - **子查询与联表...
我戴尔D630笔记本的数据返回等待时间是43毫秒,USB-232转接的等待时间是58毫秒。你可以检测一下你的响应时间是多少,以检测COM口的优劣。软件会自动侦测最小的等待时间,精确到毫秒,一丝一毫不流失,一点时间不浪费...
因此,对搜索索引进行优化,如使用全文搜索引擎(如Elasticsearch)和缓存策略(如Varnish),可以显著提高搜索性能。 总结来说,Magento AJAX 搜索是提升 Magento 商城用户体验的关键特性之一,它通过实时反馈搜索...
同样的,我们:把数据放到OpenGL渲染的线程上去做图像相关操作,能实现更快的数据保存,基本上是毫秒级别的,而且图片质量不失真,速度快,如果只用CameraX去拍照片,你会发现CameraX图片质量大,而且返回数据结果慢...
Sphinx通过建立倒排索引,可以在毫秒级时间内返回搜索结果。 `laravel-scout-sphinx`扩展包的作用就是将Sphinx与Laravel Scout结合,提供了以下功能: 1. **安装与配置**:开发者可以通过Composer安装`laravel-...