ElasticSearch 海量数据查询性能优化_ElasticSearch

ES 接收到查询请求后,会转发给所有相关的 Shard 分片,每个 Shard 在自己这块儿进行搜索,各自的结果汇总后再返回给客户端。

这个过程有2个核心性能关键点:

  • Shard 执行查询计算的耗时

  • Shard 读取各个 Segment 文件的 I/O 耗时

所以,我们就要从这两个角度进行优化。

  1. 尽量让 ES 的查询动作简单,避免进行复杂的查询计算。

  2. 尽量提升 I/O 效率,也就是用好文件系统缓存(从 ES 写入流程可以知道文件缓存有很大的作用)

1. 尽量让查询计算简单

这就涉及到 ES 中的数据建模方式。

例如关系数据库有两张表:

  • 订单表(编号、总金额、用户、日期)

  • 订单详情表(订单编号、商品信息)

查询订单时,需要对两张表进行关联查询。

这在关系数据库中很正常,因为关系数据库是根据实体及其关系来建模的。

但在 ES 中最好就不要这么定义数据结构了,ES 是搜索引擎,要以搜索的角度来规划数据,怎么便于搜索怎么来。

例如直接把这两张表的数据放在一个Document中,一个简单查询就完事儿了,不用让 ES 进行Document的关联查询。

2. 最大化使用操作系统的文件缓存

操作系统喜欢用文件缓存,只要内存充足,读取 Segment 文件的时候,就会将其内容一直放在缓存中,直到内存不够用了。

比如读 Segment 01 这个文件的时候,先加载到文件缓存。

如果缓存空间足够,就直接加载进来。

否则,就会移除一部分缓存的文件,腾出空间后再加载进来。

例如,你的 ES 数据量是 1000G,集群有3个节点,每个节点上面就是 300 多个G。

假设,每个节点中操作系统可以使用内存为 16G,那么,搜索的时候,直接读文件缓存的最大概率也只有 5% 左右,绝大部分的数据都要读物理文件,一起争用那一点文件缓存空间,性能自然很差。

优化方向有 2 个:

1)增加内存

2)减少 ES 中的数据量

2.1 增加内存

增加内存很简单,只要有钱就行。

那么需要增加到多少呢?

建议:操作系统可用内存 > 本节点数据量的 50%

这样数据命中缓存的概率就比较高了。如果不差钱,内存越大越好。

2.2 减少 ES 中的数据量

再强调一次 ES 是搜索引擎,是用来干搜索的。

很多人喜欢把数据全都放 ES 里,感觉它是分布式的,多放几台服务器,硬盘大点,很能装。

比如一个表有上百个字段,真正搜索的时候,都会用到吗?不一定吧。

那么,搜索用不到的数据尽量别放在 ES 里。

ES 服务于搜索,不是服务于存储。

所以,ES 中应该放与搜索相关的数据,不应该放全量数据。

全量数据的存储应该使用专业的存储系统,例如 HBASE。

在大数据环境中,有几个T的数据很正常,如果都放在 ES 里面,并且想要保障查询性能,内存要多大呢?

如果经济实力不允许,内存不是很充足,那么查询性能就很悲催了,每次查询花费几秒钟很正常。

如果 ES 中只放搜索相关的少量数据,把全量数据放在 HBASE,性能就会快很多。

ElasticSearch 海量数据查询性能优化_ElasticSearch _02

先从 ES 中查询出结果数据集,其中只包含核心字段,然后根据结果集中各条数据的 Key 到 HBASE 中进行精准查询,再把结果进行整合。

虽然是两次查询,但因为每部分都很快,所以整体下来也很快。

2.3 思路扩展

  • 冷热分离

数据通常有冷热之分,有一部分数据的使用频率明显高于其他数据。

如果文件系统的缓存不是很充足,那么数据就需要轮流呆在缓存中。

热数据自然呆的时间长,但是当加载冷数据时,就会把热数据挤出缓存了。那么下次就需要从磁盘重新加载。

所以,最好让热数据走一部分 Shard,冷数据走其他 Shard,防止冲刷缓存

  • 数据预加载

还是基于热数据的角度,可以事先调用一下,使其提前进入文件缓存。

这样,客户第一次查询的时候也会很快。

小结

想要 ES 查询速度快,需要使查询动作尽量简单,这需要在数据建模上多花些心思。

最重要的是要利用好文件缓存

增加内存是简单、粗暴、有效的方法。

还有就是尽量缩减 ES 中的数据量,不要存放与搜索需求无关的数据。可以配合 HBASE 这类的专业海量数据存储系统一起使用。

另外,冷热数据分离、数据预加载,也是比较有效的小技巧。