es 在数据量很大的状况下(数十亿级别)如何提升查询效率啊?前端
这个问题是确定要问的,说白了,就是看你有没有实际干过 es,由于啥?其实 es 性能并无你想象中那么好的。不少时候数据量大了,特别是有几亿条数据的时候,可能你会懵逼的发现,跑个搜索怎么一下 5~10s
,坑爹了。第一次搜索的时候,是 5~10s
,后面反而就快了,可能就几百毫秒。mysql
你就很懵,每一个用户第一次访问都会比较慢,比较卡么?因此你要是没玩儿过 es,或者就是本身玩玩儿 demo,被问到这个问题容易懵逼,显示出你对 es 确实玩儿的不怎么样?程序员
说实话,es 性能优化是没有什么银弹的,啥意思呢?就是不要期待着随手调一个参数,就能够万能的应对全部的性能慢的场景。也许有的场景是你换个参数,或者调整一下语法,就能够搞定,可是绝对不是全部场景均可以这样。面试
你往es里写的数据,实际上都写到磁盘文件里去了,查询的时候,操做系统会将磁盘文件里的数据自动缓存到 filesystem cache
里面去。sql
es-search-processapi
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 性能要好,最佳的状况下,就是你的机器的内存,至少能够容纳你的总数据量的一半。app
根据咱们本身的生产环境实践经验,最佳的状况下,是仅仅在 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~10秒,如今可能性能就会很高,每次查询就是 50ms。
假如说,哪怕是你就按照上述的方案去作了,es 集群中每一个机器写入的数据量仍是超过了 filesystem cache
一倍,好比说你写入一台机器 60G 数据,结果 filesystem cache
就 30G,仍是有 30G 数据留在了磁盘上。
其实能够作数据预热。
举个例子,拿微博来讲,你能够把一些大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% 的人在访问热数据,也无所谓了。
对于 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,每一个 shard 就查 2 条数据?最后到协调节点合并成 10 条数据?你必须得从每一个 shard 都查 1000 条数据过来,而后根据你的需求进行排序、筛选等等操做,最后再次分页,拿到里面第 100 页的数据。你翻页的时候,翻的越深,每一个 shard 返回的数据就越多,并且协调节点处理的时间越长。很是坑爹。因此用 es 作分页的时候,你会发现越翻到后面,就越是慢。
咱们以前也是遇到过这个问题,用 es 做分页,前几页就几十毫秒,翻到 10 页 or 几十页的时候,基本上就要 5~10秒 才能查出来一页数据了。
有什么解决方案吗?
你系统不容许翻那么深的页,跟产品经理说,默认翻的越深,性能就越差。
相似于微博中,下拉刷微博,刷出来一页一页的,你能够用 scroll api
,关于如何使用,自行上网搜索。
scroll 会一次性给你生成全部数据的一个快照,而后每次翻页就是经过游标移动,获取下一页下一页这样子,性能会比上面说的那种分页性能也高不少不少,基本上都是毫秒级的。
可是 惟一的一点就是,这个适合于那种相似微博下拉翻页的,不能随意跳到任何一页的场景。也就是说,你不能先进入第 10 页,而后去 120 页,而后又回到 58 页,不能随意乱跳页。因此如今不少产品,都是不容许你随意翻页的,app,也有一些网站,作的就是你只能往下拉,一页一页的翻。
另外,这个 scroll 是要保留一段时间内的数据快照的,你须要确保用户不会持续不断翻页翻几个小时。
技术的提高是须要下苦工,须要坚持不懈的努力。就好比下面的分享的这些技术点,是否都学会并掌握了呢?如须要如下图谱以及跟多提高架构技术的资源可加入个人粉丝Qqun:855801563。我花了将近一个月时间搜集整理了一套架构技术提高知识点讲解以及一些面试题解析和答案免费分享给你们。助力各位程序员朋友突破自我提高技能,实现本身的目标。