面试题

#elasticsearch#lasticsearch在数十亿级别以上的大量数据下如何提高查询效率,做到毫秒级数据查询呢?

面试官心理分析

在 JAVA 高级面试中这个问题肯定是要被问及的,为什么呢,因为可以知道你有没有实际操作过elasticsearch。

其实elasticsearch的性能并没有大家想象中的那么好,当数据量非常大的时候性能问题就会显现出来了。比如当有几十亿的数据的时候,跑一个查询可能需要10来秒中左右,这时候你就懵了,什么原因啊。但是你可能又发现一个现象:第一次搜索的时候很慢,后面再次搜索的时候就很快了,基本就是在100毫秒左右,这是啥玩意儿?

所以我会说这个问题,面试官实际就是想看你有没有实际操作过elasticsearch,如果你只是自己学习学习,玩玩 Demo 的话,那你肯定就是一脸疑问了。

不过,你很幸运看到这篇文章,接下来就带着心中的疑问往下看,去寻找答案吧......

面试题剖析

在elasticsearch中要做性能优化必须根据场景来进行优化,什么意思?就是不可能调整一个参数或者换种语法就可以实用于所有环境,这或许在部分场景中可以,但是绝对不是在所有的场景下都实用。

下面进入正题......

性能优化的杀手锏——filesystem cache

elasticsearch的数据实际上是保存导磁盘文件中的,也就是说我们向elasticsearch中写入数据,实际上都是写到磁盘文件里去了的。

当我们查询的时候,操作系统会将磁盘文件的数据自动缓存导 filesystem cache 里面去,如下图。

elasticsearch搜索引擎是严重依赖于底层操作系统的 filesystem cache 的,加入 filesystem cache 足够多的内存,尽可能让内存可以容纳elasticsearch中所有的 idx segment file 索引文件数据,这样你在搜索的时候基本上都是走的 filesystem cache 的内存,这样性能肯定非常高的。

那么走磁盘和走内存两者的性能到底有多大的差异呢?

这个问题我们也在实际环境中做过测试:如果走磁盘,搜索性能一般都是秒级别的,从1秒、2秒到几十秒不等。但是如果走内存那这个性能就要高出一个数量级,基本都是毫秒级别的,从几毫秒到几百毫秒不等。

一个真实的案例:

某个公司 elasticsearch 节点有 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,十分之一的数据可以放内存,其他的都在磁盘,然后你执行搜索操作,大部分操作都是走磁盘,性能肯定差。

上面的案列总结起来就是:如果你想让你的elasticsearch搜索性能更好,就尽可能的让你的机器内存可以容纳更多的索引数据。根据实践,最佳的情况下至少可以容纳你的总数据的一半。

我们自己生产环境实践经验:最佳的情况下,是仅仅在 elasticsearch 中存你要用来搜索的那些索引数据,这样减少了elasticsearch的数据索引的大小,就能尽可能的让搜索数据都保存到filesystem cache 内存中。如果内存留给 filesystem cache 的是 100G,那么你就将索引数据控制在 100G 以内,这样的话,你的数据几乎全部走内存来搜索,性能非常之高,一般可以在 1 秒以内。

比如说你现在有一行数据。id,name,age .... 30 个字段。但是你现在搜索,只需要根据 id,name,age 三个字段来搜索。如果你傻乎乎往 elasticsearch 里写入一行数据所有的字段,就会导致说 90% 的数据是不用来搜索的,结果硬是占据了 elasticsearch 机器上的 filesystem cache 的空间,单条数据的数据量越大,就会导致 filesystem cahce 能缓存的数据就越少。

其实,仅仅写入 elasticsearch 中要用来检索的少数几个字段就可以了,比如说就写入 es id,name,age 三个字段,然后你可以把其他的字段数据存在 mysql/hbase 里,我们一般是建议用 elasticsearch + hbase 这么一个架构。

hbase 的特点是适用于海量数据的在线存储,就是对 hbase 可以写入海量数据,但是切记不要做复杂的搜索,做一些根据 id 或者范围进行查询的简单操作就可以了。从 elasticsearch 中根据 name 和 age 去搜索,拿到的结果可能就 20 个 doc id,然后根据 doc id 到 hbase 里去查询每个 doc id 对应的完整的数据,给查出来,再返回给前端。

写入 elasticsearch 的数据最好小于等于或者是略微大于 es 的 filesystem cache 的内存容量。然后你从 elasticsearch 检索可能就花费 20ms,然后再根据 es 返回的 id 去 hbase 里查询,查 20 条数据,可能也就耗费个 30ms。

如果按照原来那么玩将1T 的数据全部放到elasticsearch中,这时有大量的数据的数据是无法保存到 filesystem cache 的内存中的,这样查询性能肯定会非常的差。

数据预热

即便就按照上面说的来做,也无法很好的解决内存和elasticsearch数据大小的问题,那还可以做些什么呢?

其实可以做数据预热。

举个例子,拿微博来说,你可以把一些大V,平时看的人很多的数据,你自己提前后台搞个系统,每隔一会儿,自己的后台系统去搜索一下热数据,刷到 filesystem cache 里去,后面用户实际上来看这个热数据的时候,他们就是直接从内存里搜索了,很快。

或者是电商,你可以将平时查看最多的一些商品,比如说 华为 mate 30,热数据提前后台搞个程序,每隔 1 分钟自己主动访问一次,刷到 filesystem cache 里去。

对于那些你觉得比较热的、经常会有人访问的数据,最好做一个专门的缓存预热子系统,就是对热数据每隔一段时间,就提前访问一下,让数据进入 filesystem cache 里面去。这样下次别人访问的时候,性能一定会好很多。

冷热分离

elasticsearch 可以做类似于 mysql 的水平拆分,就是说将大量的访问很少、频率很低的数据,单独写一个索引,然后将访问很频繁的热数据单独写一个索引。最好是将冷数据写入一个索引中,然后热数据写入另外一个索引中,这样可以确保热数据在被预热之后,尽量都让他们留在 filesystem os cache 里,别让冷数据给冲刷掉。

你看,假设你有 6 台机器,2 个索引,一个放冷数据,一个放热数据,每个索引 3 个 shard。3 台机器放热数据 index,另外 3 台机器放冷数据 index。然后这样的话,你大量的时间是在访问热数据 index,热数据可能就占总数据量的 10%,此时数据量很少,几乎全都保留在 filesystem cache 里面了,就可以确保热数据的访问性能是很高的。但是对于冷数据而言,是在别的 index 里的,跟热数据 index 不在相同的机器上,大家互相之间都没什么联系了。如果有人访问冷数据,可能大量数据是在磁盘上的,此时性能差点,就 10% 的人去访问冷数据,90% 的人在访问热数据,也无所谓了。

document 模型设计

对于 MySQL,我们经常有一些复杂的关联查询。那么在 elasticsearch 里该怎么做?

我想告诉你的是:在elasticsearch 中最好不要用复杂的关联查询,用了一般性能都是是非常差的。

最好的做法就在在 JAVA 程序中就将关联关系做好,然后再存入到elasticsearch中,这样查询出来的数据就是关联好的数据了,这样做性能会好很多。

温馨提示:不要考虑用 es 做一些它不好操作的事情。如果真的有那种操作,尽量在 document 模型设计的时候,写入的时候就完成。另外对于一些太复杂的操作,比如 join/nested/parent-child 搜索都要尽量避免,性能都很差的。

分页性能优化

elasticsearch 的分页是较坑的,为啥呢?

举个例子吧,假如你每页是 10 条数据,你现在要查询第 100 页,实际上是会把每个 shard 上存储的前 1000 条数据都查到一个协调节点上,如果你有个 5 个 shard,那么就有 5000 条数据,接着协调节点对这 5000 条数据进行一些合并、处理,再获取到最终第 100 页的 10 条数据。

分布式的,你要查第 100 页的 10 条数据,不可能说从 5 个 shard,每个 shard 就查 2 条数据,最后到协调节点合并成 10 条数据吧?

你必须得从每个 shard 都查 1000 条数据过来,然后根据你的需求进行排序、筛选等等操作,最后再次分页,拿到里面第 100 页的数据。你翻页的时候,翻的越深,每个 shard 返回的数据就越多,而且协调节点处理的时间越长,非常坑爹。所以用 es 做分页的时候,你会发现越翻到后面,就越是慢。

我们之前也是遇到过这个问题,用 es 作分页,前几页就几十毫秒,翻到 10 页或者几十页的时候,基本上就要 5~10 秒才能查出来一页数据了。

有什么解决方案吗?

不允许深度分页(默认深度分页性能很差)

跟产品经理说,你系统不允许翻那么深的页,默认翻的越深,性能就越差。

类似于 app 里的推荐商品不断下拉出来一页一页的

类似于微博中,下拉刷微博,刷出来一页一页的,你可以用 scroll api。

scroll 会一次性给你生成所有数据的一个快照,然后每次滑动向后翻页就是通过游标 scroll_id移动,获取下一页下一页这样子,性能会比上面说的那种分页性能要高很多很多,基本上都是毫秒级的。

这个适合于那种类似微博下拉翻页的,不能随意跳到任何一页的场景。也就是说,你不能先进入第 10 页,然后去第 120 页,然后又回到第 58 页,不能随意乱跳页。所以现在很多产品,都是不允许你随意翻页的,app,也有一些网站,做的就是你只能往下拉,一页一页的翻。

初始化时必须指定 scroll 参数,告诉 es 要保存此次搜索的上下文多长时间。你需要确保用户不会持续不断翻页翻几个小时,否则可能因为超时而失败。

除了用 scroll api,你也可以用 search_after 来做,search_after 的思想是使用前一页的结果来帮助检索下一页的数据,显然,这种方式也不允许你随意翻页,你只能一页页往后翻。初始化时,需要使用一个唯一值的字段作为 sort 字段。

JAVA 经典面试题:ES如何做到亿级数据查询毫秒级返回?相关推荐

  1. 经典面试题:ES如何做到亿级数据查询毫秒级返回?

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 来源:8rr.co/5Csc 面试题 es 在数据量很大的情况下( ...

  2. ES如何做到亿级数据查询毫秒级返回

    一.面试题 ES在数据量很大的情况下(数十亿级别)如何提高查询效率? 二.面试官心理分析 这个问题是肯定要问的,说白了,就是看你有没有实际干过ES,因为啥?其实ES性能并没有你想象中那么好的.很多时候 ...

  3. currenttimemillis 毫秒还是秒_Elasticsearch(ES)如何做到亿级数据查询毫秒级返回

    前言: 这个问题其实是更面向原理及实操方面的内容.换个问法,可以是这样来问:ES 在数据量很大的情况下(数十亿级别)如何提高查询效率? 为了精简,如下内容将Elasticsearch简称为ES 如果你 ...

  4. Elasticsearch如何做到亿级数据查询毫秒级返回?

    https://zhuanlan.zhihu.com/p/60458049 如果面试的时候碰到这样一个面试题:ES 在数据量很大的情况下(数十亿级别)如何提高查询效率? 这个问题说白了,就是看你有没有 ...

  5. [转载] Elasticsearch如何做到亿级数据查询毫秒级返回

    转自微信公众号:Java思维导图 一.前题: 如果面试的时候碰到这样一个面试题:ES 在数据量很大的情况下(数十亿级别)如何提高查询效率? 这个问题说白了,就是看你有没有实际用过ES,因为啥?其实 E ...

  6. 知乎1.3万亿条数据查询毫秒级响应,如何做到的?

    点击"开发者技术前线",选择"星标????" 在看|星标|留言,  真爱 来自:孙晓光 | 责编:乐乐 链接:dzone.com/articles/lesson ...

  7. Java经典面试题整理及答案详解(八)

    简介: Java经典面试题第八节来啦!本节面试题包含了进程.线程.Object类.虚拟内存等相关内容,希望大家多多练习,早日拿下心仪offer- 了解更多: Java经典面试题整理及答案详解(一) J ...

  8. Java经典面试题整理及答案详解(五)

    Java经典面试题第五弹来啦!本节面试题主要是针对Java初级基础提问,看看你还记得多少? 1.String str="hello",这个字符串对象在栈内存中明明有一个引用(str ...

  9. Java经典面试题整理及答案详解(四)

    简介: Java经典面试题第四弹来啦!本节小编整理了关于Java开发框架常见的面试题,希望大家多多怜惜,一起进步- 1.SpringMVC返回值,使用SpringMVC的时候我看到两种风格的开发,一种 ...

最新文章

  1. java远程操作ftp服务器上传下载
  2. 技术宝典 | 基于标准 WebRTC 低延迟直播的开源实践
  3. ORACLE 异常错误处理
  4. lisp求面与面的差集_Lisp 入门
  5. JDK 8_jstack命令使用
  6. python xlrd模块_Python中xlrd模块解析
  7. Merge the incoming changes into the current branch
  8. kido机器人用流量吗_海底捞、呷哺、巴奴都在用!送餐机器人会成为“火锅标配”吗?...
  9. win+ubuntu系统引导修复
  10. python catia二次开发_CATIA VBA二次开发教程|使用零件的Body生成Product
  11. JSP常用内置对象方法
  12. 豆瓣python-豆瓣+python
  13. 走好职场每一步:关于求职技巧、跳槽迷思、职场困惑
  14. Unity 3D中级项目:捕鱼达人
  15. “测验你左右脑分别有几岁”到底是个什么鬼?
  16. GDR(Gradual Decoding Refresh, GradualDecoder Refresh)
  17. return的作用,返回函数值和结束程序执行
  18. 你想要成为团队里什么样的角色呢?
  19. 海康威视摄像头 onvif 鉴权
  20. 扒一扒你不知道的《经济学人》大家族,其中一款重磅产品被严重忽略

热门文章

  1. jflash烧录教程_手把手教你用一元pos机打造高速25系列flash烧录器(路由党福利)...
  2. SpringBoot整合MQ消息队列
  3. 解决MySQL CPU占用100%的经验总结
  4. 最近写了一个简单的面向对象的脚本语言 Q 语言
  5. ESP1020E汉王签字屏API版 支持红色笔迹
  6. 笔记:处理token过期
  7. 阿里达摩院春招 Research Intern 招聘
  8. JAVA获取股票实时KDJ,炒股10年,这是我见过最简单透彻的KDJ分析【建议收藏】
  9. Linux(Centos7)下,阿帕奇(Apache)服务器的安装与配置
  10. python 3爬取 全国高校对四川历年招生数据(文理省控线,文理专业线)存入Excel表(重构)