分布式搜索引擎面试题

798 阅读10分钟

es的分布式架构原理能说一下么(es是如何实现分布式的)?

面试官心里分析

在搜索这块,Lucene是最流行的搜索库,几年前业内一般都问,你了解lucene吗?你知道倒排索引的原理吗?现在早已经out了,因为很多项目都是直接使用基于lucene的分布式搜索引擎elasticsearch,简称为es

而现在分布式搜索基本已经成为大部分互联网行业的java系统的标配,其中尤为流行的就是es,前几年es没活之前,大家一般用solr。但是这些年开始转向es了

面试题剖析

先说下一些基本概念吧

es的设计理念就是分布式搜索引擎,底层其实还是基于lucene的。

核心思想就是在多台机器上启动多个es进程实例,组成一个es集群

es中储存数据的基本单位是索引,比如说你现在要在es中存储一些订单数据,你就应该在es中创建一个索引,order_idx,所有的订单数据就都写到这个索引里面去,一个索引差不多相当于是mysql里的一张表 index->type->mapping->document->field

index:mysql里的一张表

type:没发跟mysql里去对比,一个index可以有多个type。每个type的字段都是差不多的,但是有一些略微的差别。

先看图

image.png

实际上你往index里的一个type里面写一条数据,叫做一条document,一条document就代表了mysql中某表里的一行记录,每条document有多个field,每个field就代表了这个document中的一个字段的值

接着你搞一个索引,这个索引可以拆分成多个shard,每个shard存储部分数据

接着就是这个shard的数据实际是有多个备份,就是说每个shard都有一个primary shard,负责写入数据,但是还有几个replica shard,primary shard写入数据之后,会将数据同步到其他几个replica shard上去

通过这个replica的方案,每个shard的数据都有多个备份,如果某个机器宕机了,没关系啊。还有别的数据副本在别的机器上呢。高可用了吧!

es集群多个节点,会自动选举一个节点为master节点,这个master节点其实就是干一些管理的工作,比如维护索引元数据啦,负责切换primary shard和replica shard身份啦之类的

要是master宕机了,那么会重新选举一个节点为master节点

如果是非master节点宕机了,那么会由master节点,让那个宕机节点上的primary shard的身份转移到其他机器上的replica shard。急着你要是修复那个宕机的机器,重启之后,master节点会控制将缺失replica shard分配过去,同步后续修改的数据之类的,让集群恢复正常

其实上述就是elasticsearch作为一个分布式搜索引擎最基本的一个框架设计

es写入数据的工作原理是什么啊?es查询数据的工作原理是什么?底层的lucene介绍一下呗?倒排索引了解吗?

面试官心里分析

问这个,其实面试官就是看你了不了解es的一些基本原理,因为用es无非就是写入数据,搜索数据。你要是不明白你发起一个写入和搜索请求的时候,es在干什么,那你真的就是瞎用

对es基本就是黑盒,你还能干啥?你唯一能干的就是调用es的api读写数据,中途出现问题,你将手足无措。

面试题剖析

查询,GET某条数据,写入某个document,这个document会自动给你分配一个全局唯一的id,doc id,同时也是根据doc id进行hash路由到对应的primary shard上面去。也可以手动指定doc id,比如用订单id啊 、用户id啊。

你可以通过doc id查询,会根据doc id进行hash,判断出来当时把doc id分配到了哪个 shard上面去,从那个shard去查询

es写数据过程

  1. 客户端选择一个node发送请求过去,这个node就是coordinating node(协调节点)
  2. coordinating node,对document进行路由,将请求转发给对应的node(有primary shard)
  3. 实际的node上的primary node处理请求,然后将数据同步到replica node
  4. coordinating node,如果发现primary node和所有replica node都搞定之后,就返回相应结果给客户端

es读数据过程

  1. 客户端发送请求到任意一个节点,成为coordinate node
  2. coordinate node对document进行路由,将请求转发到对应的node,此时会使用round-robin随机轮询算法,在primary shard以及其所有replica中随机选择一个,让读请求负载均衡
  3. 接收请求的node返回document给corrdinate node
  4. corrdinate node返回document给客户端

es搜索数据过程

es最强大的是做全文检索,就是比如你有三条数据

java真好玩儿啊

java好难学啊

j2ee特别牛

你根据java关键词来搜索,将包含java的document给搜索出来

es就会给你返回:java真好玩儿啊,java好难学啊

  1. 客户端发送请求到一个coordinate node
  2. 协调节点将搜索请求转发到所有的shard对应的primary shard或replica shard也可以
  3. query phase:每个shard将自己的搜索结果(其实就是一些doc id),返回给协调节点,由协调节点进行数据的合并、排序、分页等操作,产出最终结果
  4. fetch phase:接着由协调节点,根据doc id去各个节点上拉取实际的document数据,最终返回给客户端

如果你指说了上些的话,面试官可能觉得还不够,这是后你还要说说数据是怎么写入shard,有兴趣的同学可以点击下边链接进行查看 blog.csdn.net/zhaoziyun21… 相关架构图也是值得看一看的

es在数据量很大的情况下(数十亿级别),如何提高查询效率啊?

面试官心里分析

问这个问题,是肯定的,说白了,就是看你有没有实际干过es,因为啥?es说白了其实性能并没有你想象的那么好,很多时候数据量大了,特别是有几亿条数据的时候,你可能会懵逼发现,跑个搜索怎么一下5到10秒,坑爹了。第一次搜索的时候5到10秒,后面反而就快了,可能就几百毫秒。

是不是有点懵逼,每个用户第一次访问都会比较慢,比较卡吗?

所以你要没玩过es,或者就是自己玩玩demo,被问到这个问题容易懵逼,显示出你对es确实玩的不怎么样

面试题剖析

说实话,es性能优化是没什么银弹的,啥意思呢?就是不要期待着随手调一个参数,就可以万能的应对所有的性能慢的场景。也许有的场景是你换个参数或者调整一下语法,就可以搞定的,但是绝对不是所有的场景都可以这样

一块一块来分析吧

(1)性能优化杀手锏--filesystem cache

先看图

image.png

es的搜索引擎严重依赖于底层的filesystem cache,你如果给filesystem cache更多的内存,尽量让内存可以容纳所有的index segment file索引数据文件,那么你搜索的时候就基本都是走内存的,性能会非常高

如果最佳情况下,我们一般在生产环境时,仅仅在es中写入用来检索的少数几个字段数据,内存留给filesystem cache,其他字段的数据可以写到mysql啊,一般建议使用es+hbase这么一个架构。

(2)缓存预热

对于那些你觉得比较热的,经常会有人访问的数据,最好做一个专门的缓存预热子系统,就是对热数据,每隔一段时间,你就提前访问一下(写个程序自己去搜索一下),让数据进入filesystem cache里面去。这样期待下次别人访问的时候,直接从filesystem cache里查询,性能一定会好一些

(3)冷热分离

你最好是将冷数据写入一个索引中,然后热数据写入另一个索引中,这样可以确保热数据在被预热之后,尽量都让他们留在filesystem cache里,别让冷数据给冲刷掉了

确保热数据的访问性能是很高的,数据量可能就 10%,90%的人访问热数据,对冷数据而言,数据量可能90%,访问的人才10%

(4)document模型设计

避免搜索的时候做一些乱七八糟的条件,设计导入数据的时候,就自己搞好

(5)分页性能优化

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

分布式的,你要查第100页的10条数据,你是不可能说从5个shard,每个shard就查2条数据?最后到协调节点合并成10条数据?你必须得从每个shard都查1000条数据过来,然后根据你的需求进行排序、筛选等等操作,最后再次分页,拿到里面的第100页数据。

翻页翻的越深,每个shard返回的数据就越多,而且协调节点处理的时间越长,非常坑人,所以es做分页的时候,你会发现越翻到后面,就越是慢

针对这个问题可以使用scroll来优化,scroll会一次性给你生成所有数据的一个快照, 然后每次翻页就是通过游标移动,获取下一页下一页这样子,性能会比上面说的那种分页性能高的多得多

但是唯一的缺点就是,这个适合于那种类似微博下拉翻页的,不能随意跳到任何一页的场景,同时这个scroll是只会保留一段时间内的数据快照,你需要确保用户不会持续不断翻页翻几个小时的

es生产集群的部署架构是什么?每个索引的数据量大概有多少?每个索引大概有多少个分片

  1. es生产集群我们部署了5台机器,每台机器是6核64G的,集群总内存是320G
  2. 我们es集群的日增数据大概是2000万条,每天日增量数据大概是500MB,每个月增量数据大概是6亿,15G。目前系统已经运行几个月了。现在es集群里数据总量大概是100G左右
  3. 目前线上有5个索引(结合自己的业务系统来说,看看那些数据是需要放入es的),每个索引数据量大概是20G,所以这个数据量内,我们每个索引分配的是8个shard,比默认的5个shard多了3个shard

大概这么说一下就可以