关于java:2021Java后端工程师面试指南Elasticsearch

41次阅读

共计 8388 个字符,预计需要花费 21 分钟才能阅读完成。

前言

文本已收录至我的 GitHub 仓库,欢送 Star:https://github.com/bin3923282…
种一棵树最好的工夫是十年前,其次是当初

Tips

面试指南系列,很多状况下不会去深挖细节,是小六六以被面试者的角色去回顾常识的一种形式,所以我默认大部分的货色,作为面试官的你,必定是懂的。

https://www.processon.com/vie…

下面的是脑图地址

叨絮

明天来看看 Elasticsearch
而后上面是后面的文章汇总

  • 2021-Java 后端工程师面试指南 -(引言)
  • 2021-Java 后端工程师面试指南 -(Java 根底篇)
  • 2021-Java 后端工程师面试指南 -(并发 - 多线程)
  • 2021-Java 后端工程师面试指南 -(JVM)
  • 2021-Java 后端工程师面试指南 -(MySQL)
  • 2021-Java 后端工程师面试指南 -(Redis)

Es 其实用的很多,而且如果体量大点的话,基本上都须要应用到它,所以把握它还是很有必要的,那么咱们来一起看看吧

### 说说什么是 Elasticsearch

  • Elasticsearch,基于 lucene. 分布式的 Restful 实时搜寻和剖析引擎(实时)
  • 分布式的实时文件存储, 每个字段都被索引并可被搜寻
  • 高扩展性, 可扩大至上百台服务器, 解决 PB 级结构化或非结构化数据
  • Elasticsearch 用于全文检索, 结构化搜寻, 剖析 / 合并应用

聊聊 Elasticsearch 的个性:

  • Elasticsearch 没有典型意义的事务(无事务性)
  • Elasticsearch 是一种面向文档的数据库
  • Elasticsearch 没有提供受权和认证个性

什么是全文检索和 Lucene?

全文检索,倒排索引

全文检索是指计算机索引程序通过扫描文章中的每一个词,对每一个词建设一个索引,指明该词在文章中呈现的次数和地位,当用户查问时,检索程序就依据当时建设的索引进行查找,并将查找的后果反馈给用户的检索形式。这个过程相似于通过字典中的检索字表查字的过程。全文搜寻搜索引擎数据库中的数据。

lucene
lucene,就是一个 jar 包,外面蕴含了封装好的各种建设倒排索引,以及进行搜寻的代码,包含各种算法。咱们就用 java 开发的时候,引入 lucene jar,而后基于 lucene 的 api 进行去进行开发就能够了。

那你聊聊 Elasticsearch 的外围概念,就是咱们常常用的那些。

近实时
近实时,两个意思,从写入数据到数据能够被搜寻到有一个小提早(大略 1 秒);基于 es 执行搜寻和剖析能够达到秒级。

Cluster(集群)
集群蕴含多个节点,每个节点属于哪个集群是通过一个配置(集群名称,默认是 elasticsearch)来决定的,对于中小型利用来说,刚开始一个集群就一个节点很失常

Node(节点)

集群中的一个节点,节点也有一个名称(默认是随机调配的),节点名称很重要(在执行运维治理操作的时候),默认节点会去退出一个名称为“elasticsearch”的集群,如果间接启动一堆节点,那么它们会主动组成一个 elasticsearch 集群,当然一个节点也能够组成一个 elasticsearch 集群。

Index(索引 - 数据库)
索引蕴含一堆有类似构造的文档数据,比方能够有一个客户索引,商品分类索引,订单索引,索引有一个名称。一个 index 蕴含很多 document,一个 index 就代表了一类相似的或者雷同的 document。比如说建设一个 product index,商品索引,外面可能就寄存了所有的商品数据,所有的商品 document。

Type(类型 - 表)
每个索引里都能够有一个或多个 type,type 是 index 中的一个逻辑数据分类,一个 type 下的 document,都有雷同的 field,比方博客零碎,有一个索引,能够定义用户数据 type,博客数据 type,评论数据 type。

Document(文档 - 行)
文档是 es 中的最小数据单元,一个 document 能够是一条客户数据,一条商品分类数据,一条订单数据,通常用 JSON 数据结构示意,每个 index 下的 type 中,都能够去存储多个 document。

Field(字段 - 列)
Field 是 Elasticsearch 的最小单位。一个 document 外面有多个 field,每个 field 就是一个数据字段。

shard
单台机器无奈存储大量数据,es 能够将一个索引中的数据切分为多个 shard,散布在多台服务器上存储。有了 shard 就能够横向扩大,存储更多数据,让搜寻和剖析等操作散布到多台服务器下来执行,晋升吞吐量和性能。每个 shard 都是一个 lucene index。

replica
任何一个服务器随时可能故障或宕机,此时 shard 可能就会失落,因而能够为每个 shard 创立多个 replica 正本。replica 能够在 shard 故障时提供备用服务,保证数据不失落,多个 replica 还能够晋升搜寻操作的吞吐量和性能。primary shard(建设索引时一次设置,不能批改,默认 5 个),replica shard(随时批改数量,默认 1 个),默认每个索引 10 个 shard,5 个 primary shard,5 个 replica shard,最小的高可用配置,是 2 台服务器。

说说 Elasticsearch 乐观并发管制

Elasticsearch 是分布式的。当文档被创立、更新或删除,文档的新版本会被复制到集群的其它节点。Elasticsearch 即是同步的又是异步的,意思是这些复制申请都是平行发送的,并无序 (out of sequence) 的达到目的地。这就须要一种办法确保老版本的文档永远不会笼罩新的版本。
上文咱们提到 index、get、delete 申请时,咱们指出每个文档都有一个_version 号码,这个号码在文档被扭转时加一。Elasticsearch 应用这个_version 保障所有批改都被正确排序。当一个旧版本呈现在新版本之后,它会被简略的疏忽。
咱们利用_version 的这一长处确保数据不会因为批改抵触而失落。咱们能够指定文档的 version 来做想要的更改。如果那个版本号不是当初的,咱们的申请就失败了。
用 version 来保障并发的程序一致性

聊聊 text,keyword 类型的区别

  • text:当一个字段是要被全文搜寻的,比方 Email 内容、产品描述,应该应用 text 类型。设置 text 类型当前,字段内容会被剖析,在生成倒排索引以前,字符串会被分析器分成一个一个词项。text 类型的字段不用于排序,很少用于聚合。
  • keyword:keyword 类型实用于索引结构化的字段,比方 email 地址、主机名、状态码和标签。如果字段须要进行过滤(比方查找已公布博客中 status 属性为 published 的文章)、排序、聚合。keyword 类型的字段只能通过准确值搜寻到。

那你说说查问 api 返回的次要蕴含什么货色

hits
响应中最重要的局部是 hits,它蕴含了 total 字段来示意匹配到的文档总数,hits 数组还蕴含了匹配到的前 10 条数据。
hits 数组中的每个后果都蕴含_index、_type 和文档的_id 字段,被退出到_source 字段中这意味着在搜寻后果中咱们将能够间接应用全副文档。这不像其余搜索引擎只返回文档 ID,须要你独自去获取文档。
每个节点都有一个_score 字段,这是相关性得分(relevance score),它掂量了文档与查问的匹配水平。默认的,返回的后果中关联性最大的文档排在首位;这意味着,它是依照_score 降序排列的。这种状况下,咱们没有指定任何查问,所以所有文档的相关性是一样的,因而所有后果的_score 都是获得一个两头值 1
max_score 指的是所有文档匹配查问中_score 的最大值。

took
took 通知咱们整个搜寻申请破费的毫秒数。

shards
_shards 节点通知咱们参加查问的分片数(total 字段),有多少是胜利的(successful 字段),有多少的是失败的(failed 字段)。通常咱们不心愿分片失败,不过这个有可能产生。如果咱们蒙受一些重大的故障导致主分片和复制分片都故障,那这个分片的数据将无奈响应给搜寻申请。这种状况下,Elasticsearch 将报告分片 failed,但仍将持续返回残余分片上的后果。

timeout

time_out 值通知咱们查问超时与否。个别的,搜寻申请不会超时。如果响应速度比残缺的后果更重要,你能够定义 timeout 参数为 10 或者 10ms(10 毫秒),或者 1s(1 秒)

聊聊 shard&replica 机制

  • index 蕴含多个 shard
  • 每个 shard 都是一个最小工作单元,承载局部数据,lucene 实例,残缺的建设索引和解决申请的能力
  • 增减节点时,shard 会主动在 nodes 中负载平衡
  • primary shard 和 replica shard,每个 document 必定只存在于某一个 primary shard 以及其对应的 replica shard 中,不可能存在于多个 primary shard
  • replica shard 是 primary shard 的正本,负责容错,以及承当读申请负载
  • primary shard 的数量在创立索引的时候就固定了,replica shard 的数量能够随时批改
  • primary shard 的默认数量是 5,replica 默认是 1,默认有 10 个 shard,5 个 primary shard,5 个 replica shard
  • primary shard 不能和本人的 replica shard 放在同一个节点上(否则节点宕机,primary shard 和正本都失落,起不到容错的作用),然而能够和其余 primary shard 的 replica shard 放在同一个节点上

ES 是如何实现 master 选举的?

前置条件:

  • 只有是候选主节点(master:true)的节点能力成为主节点。
  • 最小主节点数(min_master_nodes)的目标是避免脑裂。

Elasticsearch 的选主是 ZenDiscovery 模块负责的,次要蕴含 Ping(节点之间通过这个 RPC 来发现彼此)和 Unicast(单播模块蕴含一个主机列表以管制哪些节点须要 ping 通)这两局部;
获取主节点的外围入口为 findMaster,抉择主节点胜利返回对应 Master,否则返回 null。

选举流程大抵形容如下:

  • 第一步:确认候选主节点数达标,elasticsearch.yml 设置的值 discovery.zen.minimum_master_nodes;
  • 第二步:对所有候选主节点依据 nodeId 字典排序,每次选举每个节点都把本人所晓得节点排一秩序,而后选出第一个(第 0 位)节点,暂且认为它是 master 节点。
  • 第三步:如果对某个节点的投票数达到肯定的值(候选主节点数 n /2+1)并且该节点本人也选举本人,那这个节点就是 master。否则从新选举始终到满足上述条件。

如何解决 ES 集群的脑裂问题

所谓集群脑裂,是指 Elasticsearch 集群中的节点(比方共 20 个),其中的 10 个选了一个 master,另外 10 个选了另一个 master 的状况。

当集群 master 候选数量不小于 3 个时,能够通过设置起码投票通过数量(discovery.zen.minimum_master_nodes)超过所有候选节点一半以上来解决脑裂问题;
当候选数量为两个时,只能批改为惟一的一个 master 候选,其余作为 data 节点,防止脑裂问题。

聊聊 es 的写入流程

Elasticsearch 采纳多 Shard 形式,通过配置 routing 规定将数据分成多个数据子集,每个数据子集提供独立的索引和搜寻性能。当写入文档的时候,依据 routing 规定,将文档发送给特定 Shard 中建设索引。这样就能实现分布式了。

每个 Index 由多个 Shard 组成(默认是 5 个),每个 Shard 有一个主节点和多个正本节点,正本个数可配。但每次写入的时候,写入申请会先依据_routing 规定抉择发给哪个 Shard,Index Request 中能够设置应用哪个 Filed 的值作为路由参数,如果没有设置,则应用 Mapping 中的配置,如果 mapping 中也没有配置,则应用_id 作为路由参数,而后通过_routing 的 Hash 值抉择出 Shard(在 OperationRouting 类中),最初从集群的 Meta 中找出出该 Shard 的 Primary 节点。

申请接着会发送给 Primary Shard,在 Primary Shard 上执行胜利后,再从 Primary Shard 上将申请同时发送给多个 Replica Shard,申请在多个 Replica Shard 上执行胜利并返回给 Primary Shard 后,写入申请执行胜利,返回后果给客户端。

那你说说具体在 shard 上的写入流程呗

在每一个 Shard 中,写入流程分为两局部,先写入 Lucene,再写入 TransLog。

写入申请达到 Shard 后,先写 Lucene 文件,创立好索引,此时索引还在内存外面,接着去写 TransLog,写完 TransLog 后,刷新 TransLog 数据到磁盘上,写磁盘胜利后,申请返回给用户。这里有几个关键点:

和数据库不同,数据库是先写 CommitLog,而后再写内存,而 Elasticsearch 是先写内存,最初才写 TransLog,一种可能的起因是 Lucene 的内存写入会有很简单的逻辑,很容易失败,比方分词,字段长度超过限度等,比拟重,为了防止 TransLog 中有大量有效记录,缩小 recover 的复杂度和进步速度,所以就把写 Lucene 放在了最后面。

写 Lucene 内存后,并不是可被搜寻的,须要通过 Refresh 把内存的对象转成残缺的 Segment 后,而后再次 reopen 后能力被搜寻,个别这个工夫设置为 1 秒钟,导致写入 Elasticsearch 的文档,最快要 1 秒钟才可被从搜寻到,所以 Elasticsearch 在搜寻方面是 NRT(Near Real Time)近实时的零碎。

每隔一段比拟长的工夫,比方 30 分钟后,Lucene 会把内存中生成的新 Segment 刷新到磁盘上,刷新后索引文件曾经长久化了,历史的 TransLog 就没用了,会清空掉旧的 TransLog。

Lucene 缓存中的数据默认 1 秒之后才生成 segment 文件,即便是生成了 segment 文件,这个 segment 是写到页面缓存中的,并不是实时的写到磁盘,只有达到肯定工夫或者达到肯定的量才会强制 flush 磁盘。如果这期间机器宕掉,内存中的数据就丢了。如果产生这种状况,内存中的数据是能够从 TransLog 中进行复原的,TransLog 默认是每 5 秒都会刷新一次磁盘。但这仍然不能保障数据安全,因为依然有可能最多失落 TransLog 中 5 秒的数据。这里能够通过配置减少 TransLog 刷磁盘的频率来减少数据可靠性,最小可配置 100ms,但不倡议这么做,因为这会对性能有十分大的影响。个别状况下,Elasticsearch 是通过正本机制来解决这一问题的。即便主分片所在节点宕机,失落了 5 秒数据,仍然是能够通过副原本进行复原的。

总结一下,数据先写入内存 buffer,而后每隔 1s,将数据 refresh 到 os cache,到了 os cache 数据就能被搜寻到(所以咱们才说 es 从写入到能被搜寻到,两头有 1s 的提早)。每隔 5s,将数据写入 translog 文件(这样如果机器宕机,内存数据全没,最多会有 5s 的数据失落),translog 大到肯定水平,或者默认每隔 30mins,会触发 commit 操作,将缓冲区的数据都 flush 到 segment file 磁盘文件中。

说说 es 的更新流程吧

Lucene 中不反对局部字段的 Update,所以须要在 Elasticsearch 中实现该性能,具体流程如下:

  • 到 Update 申请后,从 Segment 或者 TransLog 中读取同 id 的残缺 Doc,记录版本号为 V1。
  • 将版本 V1 的全量 Doc 和申请中的局部字段 Doc 合并为一个残缺的 Doc,同时更新内存中的 VersionMap。获取到残缺 Doc 后,Update 申请就变成了 Index 申请。
  • 加锁。
  • 再次从 versionMap 中读取该 id 的最大版本号 V2,如果 versionMap 中没有,则从 Segment 或者 TransLog 中读取,这里根本都会从 versionMap 中获取到。
  • 查看版本是否抵触(V1==V2),如果抵触,则回退到开始的“Update doc”阶段,从新执行。如果不抵触,则执行最新的 Add 申请。
  • 在 Index Doc 阶段,首先将 Version + 1 失去 V3,再将 Doc 退出到 Lucene 中去,Lucene 中会先删同 id 下的已存在 doc id,而后再减少新 Doc。写入 Lucene 胜利后,将以后 V3 更新到 versionMap 中。
  • 开释锁,局部更新的流程就完结了

详细描述一下 ES 搜寻的过程?

搜寻被执行成一个两阶段过程,即 Query Then Fetch;

Query 阶段:
查问会播送到索引中每一个分片拷贝(主分片或者正本分片)。每个分片在本地执行搜寻并构建一个匹配文档的大小为 from + size 的优先队列。PS:在搜寻的时候是会查问 Filesystem Cache 的,然而有局部数据还在 Memory Buffer,所以搜寻是近实时的。
每个分片返回各自优先队列中 所有文档的 ID 和排序值 给协调节点,它合并这些值到本人的优先队列中来产生一个全局排序后的后果列表。
Fetch 阶段:
协调节点分别出哪些文档须要被取回并向相干的分片提交多个 GET 申请。每个分片加载并 丰盛 文档,如果有需要的话,接着返回文档给协调节点。一旦所有的文档都被取回了,协调节点返回后果给客户端。

说说 es 的写一致性

咱们在发送任何一个增删改操作的时候,比如说 put /index/type/id,都能够带上一个 consistency 参数,指明咱们想要的写一致性是什么?
put /index/type/id?consistency=quorum

  • one:要求咱们这个写操作,只有有一个 primary shard 是 active 沉闷可用的,就能够执行
  • all:要求咱们这个写操作,必须所有的 primary shard 和 replica shard 都是沉闷的,才能够执行这个写操作
  • quorum:默认的值,要求所有的 shard 中,必须是大部分的 shard 都是沉闷的,可用的,才能够执行这个写操作

聊聊 elasticsearch 深度分页以及 scroll 滚动搜寻

深度分页
深度分页其实就是搜寻的深浅度,比方第 1 页,第 2 页,第 10 页,第 20 页,是比拟浅的;第 10000 页,第 20000 页就是很深了。
搜寻得太深,就会造成性能问题,会消耗内存和占用 cpu。而且 es 为了性能,他不反对超过一万条数据以上的分页查问。那么如何解决深度分页带来的问题,咱们应该防止深度分页操作(限度分页页数),比方最多只能提供 100 页的展现,从第 101 页开始就没了,毕竟用户也不会搜的那么深,咱们平时搜寻淘宝或者京东也就看个 10 来页就顶多了。

滚动搜寻
一次性查问 1 万 + 数据,往往会造成性能影响,因为数据量太多了。这个时候能够应用滚动搜寻,也就是 scroll。
滚动搜寻能够先查问出一些数据,而后再紧接着顺次往下查问。在第一次查问的时候会有一个滚动 id,相当于一个锚标记,随后再次滚动搜寻会须要上一次搜寻滚动 id,依据这个进行下一次的搜寻申请。每次搜寻都是基于一个历史的数据快照,查问数据的期间,如果有数据变更,那么和搜寻是没有关系的。

es 在数据量很大的状况下如何进步性能

filesystem

es 每次走 fileSystem cache 查问速度是最快的
所以将每个查问的数据 50% 容量
= fileSystem cache 容量。

数据预热
数据预热是指,每隔一段时间,将热数据
手动在后盾查问一遍,将热数据刷新到 fileSystem cache 上

冷热拆散
相似于 MySQL 的分表分库
将热数据独自建设一个索引 调配 3 台机器只放弃热机器的索引
另外的机器放弃冷数据的索引,但有一个问题,就是当时必须晓得哪些是热数据 哪些是冷数据

不能够深度分页

跟产品经理说,你零碎不容许翻那么深的页,默认翻的越深,性能就越差。

相似于 app 里的举荐商品一直下拉进去一页一页的
相似于微博中,下拉刷微博,刷进去一页一页的,你能够用 scroll api

完结

es 可能我本人用的也比拟少,就用来做一些搜寻,没有用来做 bi,所以呢?也不是那么深刻吧,心愿对大家有帮忙,接下来温习下队列

日常求赞

好了各位,以上就是这篇文章的全部内容了,能看到这里的人呀,都是 真粉

创作不易,各位的反对和认可,就是我创作的最大能源,咱们下篇文章见

微信 搜 “ 六脉神剑的程序人生 ” 回复 888 有我找的许多的材料送给大家

正文完
 0