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的字段都是差不多的,但是有一些略微的差别。
先看图
实际上你往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写数据过程
- 客户端选择一个node发送请求过去,这个node就是coordinating node(协调节点)
- coordinating node,对document进行路由,将请求转发给对应的node(有primary shard)
- 实际的node上的primary node处理请求,然后将数据同步到replica node
- coordinating node,如果发现primary node和所有replica node都搞定之后,就返回相应结果给客户端
es读数据过程
- 客户端发送请求到任意一个节点,成为coordinate node
- coordinate node对document进行路由,将请求转发到对应的node,此时会使用round-robin随机轮询算法,在primary shard以及其所有replica中随机选择一个,让读请求负载均衡
- 接收请求的node返回document给corrdinate node
- corrdinate node返回document给客户端
es搜索数据过程
es最强大的是做全文检索,就是比如你有三条数据
java真好玩儿啊
java好难学啊
j2ee特别牛
你根据java关键词来搜索,将包含java的document给搜索出来
es就会给你返回:java真好玩儿啊,java好难学啊
- 客户端发送请求到一个coordinate node
- 协调节点将搜索请求转发到所有的shard对应的primary shard或replica shard也可以
- query phase:每个shard将自己的搜索结果(其实就是一些doc id),返回给协调节点,由协调节点进行数据的合并、排序、分页等操作,产出最终结果
- fetch phase:接着由协调节点,根据doc id去各个节点上拉取实际的document数据,最终返回给客户端
如果你指说了上些的话,面试官可能觉得还不够,这是后你还要说说数据是怎么写入shard,有兴趣的同学可以点击下边链接进行查看 blog.csdn.net/zhaoziyun21… 相关架构图也是值得看一看的
es在数据量很大的情况下(数十亿级别),如何提高查询效率啊?
面试官心里分析
问这个问题,是肯定的,说白了,就是看你有没有实际干过es,因为啥?es说白了其实性能并没有你想象的那么好,很多时候数据量大了,特别是有几亿条数据的时候,你可能会懵逼发现,跑个搜索怎么一下5到10秒,坑爹了。第一次搜索的时候5到10秒,后面反而就快了,可能就几百毫秒。
是不是有点懵逼,每个用户第一次访问都会比较慢,比较卡吗?
所以你要没玩过es,或者就是自己玩玩demo,被问到这个问题容易懵逼,显示出你对es确实玩的不怎么样
面试题剖析
说实话,es性能优化是没什么银弹的,啥意思呢?就是不要期待着随手调一个参数,就可以万能的应对所有的性能慢的场景。也许有的场景是你换个参数或者调整一下语法,就可以搞定的,但是绝对不是所有的场景都可以这样
一块一块来分析吧
(1)性能优化杀手锏--filesystem cache
先看图
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生产集群的部署架构是什么?每个索引的数据量大概有多少?每个索引大概有多少个分片
- es生产集群我们部署了5台机器,每台机器是6核64G的,集群总内存是320G
- 我们es集群的日增数据大概是2000万条,每天日增量数据大概是500MB,每个月增量数据大概是6亿,15G。目前系统已经运行几个月了。现在es集群里数据总量大概是100G左右
- 目前线上有5个索引(结合自己的业务系统来说,看看那些数据是需要放入es的),每个索引数据量大概是20G,所以这个数据量内,我们每个索引分配的是8个shard,比默认的5个shard多了3个shard
大概这么说一下就可以