大数据ES索引数据库如何优化

    ElasticSearch(以下简称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 性能好,最佳的情况下,就是你的机器的内存,至少可以容纳你的总数据量的一半。根据我们自己的生产环境实践经验,最佳的情况下,是仅仅在 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 能支持的操作就那么多,不要考虑用 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 做分页的时候,你会发现越翻到后面,就越是慢。


    有什么解决方案吗?两个思路:

    一、不允许深度分页(默认深度分页性能很差)。你系统不允许翻那么深的页,默认翻的越深,性能就越差。

    二、类似于 App 里的推荐商品不断下拉出来一页一页的;类似于微博中,下拉刷微博,刷出来一页一页的,你可以用 Scroll API,关于如何使用,大家可以自行上网搜索学习一下。  Scroll是如何做的呢?它会一次性给你生成所有数据的一个快照,然后每次滑动向后翻页就是通过游标 scroll_id 移动,获取下一页、下一页这样子,性能会比上面说的那种分页性能要高很多很多,基本上都是毫秒级的。


网友评论

1条评论

发表

网友评论

1条评论

发表

最新评论

08月31日 21:34

推荐文章

彩龙

Copyright © 2008-2020 彩龙社区(https://www.clzg.cn) 版权所有 All Rights Reserved.

免责声明: 本网不承担任何由内容提供商提供的信息所引起的争议和法律责任。

经营许可证编号:滇B2-20090009-7

下载我家昆明APP 下载彩龙社区APP