前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >内存吞金兽(Elasticsearch)的那些事儿 -- 常见问题痛点及解决方案

内存吞金兽(Elasticsearch)的那些事儿 -- 常见问题痛点及解决方案

作者头像
房上的猫
发布2021-08-31 16:09:26
5500
发布2021-08-31 16:09:26
举报
文章被收录于专栏:个人随笔个人随笔

系列目录

内存吞金兽(Elasticsearch)的那些事儿 -- 认识一下

内存吞金兽(Elasticsearch)的那些事儿 -- 数据结构及巧妙算法

内存吞金兽(Elasticsearch)的那些事儿 -- 架构&三高保证

内存吞金兽(Elasticsearch)的那些事儿 -- 写入&检索原理

内存吞金兽(Elasticsearch)的那些事儿 -- 常见问题痛点及解决方案

1、大数据量的查询效率如何保证:

查询的流程:往 ES 里写的数据,实际上都写到磁盘文件里去了,查询的时候,操作系统会将磁盘文件里的数据自动缓存到 Filesystem Cache 里面去

最佳的情况下,就是机器的内存,至少可以容纳总数据量的一半,仅仅在 es 中就存少量的数据,就是要用来搜索的那些索引,如果内存留给 filesystem cache 的是 100G,那么将索引数据控制在 100G 以内,这样的话,数据几乎全部走内存来搜索,性能非常之高,一般可以在 1 秒以内,但是生成环境的数据量往往还是会很多,有大致四种方案:

1)数据预热

平时看的人很多的数据,每隔一会儿,去搜索一下热数据,刷到 filesystem cache 里去,后面用户实际上来看这个热数据的时候,就是直接从内存里搜索了;

2)冷热分离

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

3)es+Hbase架构:

es只存储索引字段,其他数据放到mysql/hbase中;

举例说明:id,name,age .... 30 个字段。现在搜索,只需要根据 id,name,age 三个字段来搜索。如果往 es 里写入一行数据所有的字段,就会导致说 90% 的数据是不用来搜索的,结果硬是占据了 es 机器上的 filesystem cache 的空间,单条数据的数据量越大,就会导致 filesystem cahce 能缓存的数据就越少。其实,仅仅写入 es 中要用来检索的少数几个字段就可以了,比如说就写入es id,name,age 三个字段,然后你可以把其他的字段数据存在 mysql/hbase 里,我们一般是建议用 es + hbase 这么一个架构。

4)document 模型设计

对于 MySQL,我们经常有一些复杂的关联查询。es 里面的复杂的关联查询尽量别用,一旦用了性能一般都不太好。

要先在 Java 系统里就完成关联,将关联好的数据直接写入 es 中。搜索的时候,就不需要利用 es 的搜索语法来完成 join 之类的关联搜索了。

2、分页查询痛点及解决方案:

假设现在要查询第100页的10条数据,但是对于es来说,from=1000000,size=100,这时 es需要从各个分片上查询出来10000100条数据,然后汇总计算后从其中取出100条。如果有5个分片则需要查询出来5*10000100条数据,如果现在有并发的100个查询请求,就会有50亿左右的数据,占用的内存是非常高的,所以在使用es的分页查询过程中,刚开始翻页可能速度比较快,可能到第一百页查询就需要4-5s,翻到1000页以后,系统资源占用成指数级上升,很容易就会出现OOM直接报错。

分页方案:

1)基本的from-size查询,es为了避免深度分页带来的内存开销,from最大值设定到了10000,目前后台运营的翻页最多关心近10页的数据;

2)search after按照第一个检索到的最后显示的“balance”和‘_id’值,作为下一个检索search_after的参数,例如假定size是10,当查询990-1000时,通过上次传递的最后一个检索到的值,在分片上就可以取到10条文档,不支持上一页查询。

3)scroll查询

scroll查询原理是在第一次查询的时候一次性生成一个快照,根据上一次的查询的id来进行下一次的查询,这个就类似于关系型数据库的游标,然后每次滑动都是根据产生的游标id进行下一次查询,这种性能比上面说的分页性能要高出很多,基本都是毫秒级的。

注意点:scroll不支持跳页查询。

使用场景:对实时性要求不高的查询。

代码:

设置查询条件

| BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); QueryBuilder builder = QueryBuilders.queryStringQuery("123456").field("code"); boolQueryBuilder.must(QueryBuilders.termQuery("logType", "10")) .must(builder); |

|:----|

首次查询

  • 第一次查询,跟平时的search查询一样需要设置index和type以及查询条件。
  • 如果把查询类型设置成SCAN,那么不能获取结果并且不支持排序,只能获得scrollId,如果使用默认设置或者不设置,那么第一次在获取id的同时也可以获取到查询结果。
  • 这个size大小的意思不是总分页的大小,实际数量应该是:所以实际返回的数量是:分片的数量*size
  • 滚动时间设置是指在这个查询搜索结果的缓存时间,时间不能太久,毕竟内存空间是有限的。

| SearchResponse response1 = client.prepareSearch("_audit_0221").setTypes("_log_0221") .setQuery(boolQueryBuilder) .setSearchType(.setSearchType(SearchType.DEFAULT)) .setSize(10).setScroll(TimeValue.timeValueMinutes(5)) .addSort("logTime", SortOrder.DESC) .execute().actionGet();//第一次查询 for (SearchHit searchHit : response1.getHits().hits()) { biz handle....; } |

|:----|

第二次查询

| while (response1.getHits().hits().length>0) { for (SearchHit searchHit : response1.getHits().hits()) { System.out.println(searchHit.getSource().toString()); } response1 = client.prepareSearchScroll(response1.getScrollId()).setScroll(TimeValue.timeValueMinutes(5)) .execute().actionGet(); } |

|:----|

4) 利用scroll-scan遍历数据

使用场景:500w用户,需要遍历所有用户发送数据,并且对顺序没有要求,这个时候我们可以使用scroll-scan。

| 查询 SearchResponse response = client.prepareSearch("_audit_0221").setTypes("_log_0221") .setQuery(boolQueryBuilder) .setSearchType(SearchType.SCAN) .setSize(5).setScroll(TimeValue.timeValueMinutes(5)) .addSort("logTime", SortOrder.DESC) .execute().actionGet(); 获取结果 SearchResponse response1 = client.prepareSearchScroll(scrollId).setScroll(TimeValue.timeValueMinutes(5)) .execute().actionGet(); while (response1.getHits().hits().length>0) { for (SearchHit searchHit : response1.getHits().hits()) { System.out.println(searchHit.getSource().toString()); } response1 = client.prepareSearchScroll(response1.getScrollId()).setScroll(TimeValue.timeValueMinutes(5)) .execute().actionGet(); } |

|:----|

scroll和scroll-scan区别

  1. scroll支持排序,scroll-scan不支持排序,是按照索引顺序返回,可以提高查询效率。
  2. scroll-scan第一次查询只支持返回id,没有结果。

总结:

代码语言:txt
复制
1. es的分页查询不支持深度分页,如果偏要使用要结合具体业务场景进行使用。不能当成关系型数据库中的分页进行使用。
2. 要想提高产品体验和查询效率不能过于依赖技术,要结合需求进行分析以提高体验,因为很多搜索类产品都不支持深度分页。
3. 如果在不涉及排序的情况下尽量使用scroll-scan,它是按照索引顺序返回,提高效率。
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-08-25 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 系列目录
    • 1、大数据量的查询效率如何保证:
      • 2、分页查询痛点及解决方案:
      相关产品与服务
      文件存储
      文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档