ElasticSearch写入数据的工做原理是什么?

面试题

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

面试官心理分析

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

对 es 基本就是个黑盒,你还能干啥?你惟一能干的就是用 es 的 api 读写数据了。要是出点什么问题,你啥都不知道,那还能期望你什么呢?面试

面试题剖析

es 写数据过程

  • 客户端选择一个 node 发送请求过去,这个 node 就是 coordinating node(协调节点)。
  • coordinating node 对 document 进行路由,将请求转发给对应的 node(有 primary shard)。
  • 实际的 node 上的 primary shard 处理请求,而后将数据同步到 replica node
  • coordinating node 若是发现 primary node 和全部 replica node 都搞定以后,就返回响应结果给客户端。

 

 

es 读数据过程

能够经过 doc id 来查询,会根据 doc id 进行 hash,判断出来当时把 doc id 分配到了哪一个 shard 上面去,从那个 shard 去查询。算法

  • 客户端发送请求到任意一个 node,成为 coordinate node
  • coordinate node 对 doc id 进行哈希路由,将请求转发到对应的 node,此时会使用 round-robin随机轮询算法,在 primary shard 以及其全部 replica 中随机选择一个,让读请求负载均衡。
  • 接收请求的 node 返回 document 给 coordinate node
  • coordinate node 返回 document 给客户端。

es 搜索数据过程

es 最强大的是作全文检索,就是好比你有三条数据:api

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 数据,最终返回给客户端。
写请求是写入 primary shard,而后同步给全部的 replica shard;读请求能够从 primary shard 或 replica shard 读取,采用的是随机轮询算法。

写数据底层原理

 

 

先写入内存 buffer,在 buffer 里的时候数据是搜索不到的;同时将数据写入 translog 日志文件。restful

若是 buffer 快满了,或者到必定时间,就会将内存 buffer 数据 refresh 到一个新的 segment file 中,可是此时数据不是直接进入 segment file 磁盘文件,而是先进入 os cache 。这个过程就是 refresh数据结构

每隔 1 秒钟,es 将 buffer 中的数据写入一个新的 segment file,每秒钟会产生一个新的磁盘文件 segment file,这个 segment file 中就存储最近 1 秒内 buffer 中写入的数据。并发

可是若是 buffer 里面此时没有数据,那固然不会执行 refresh 操做,若是 buffer 里面有数据,默认 1 秒钟执行一次 refresh 操做,刷入一个新的 segment file 中。负载均衡

操做系统里面,磁盘文件其实都有一个东西,叫作 os cache,即操做系统缓存,就是说数据写入磁盘文件以前,会先进入 os cache,先进入操做系统级别的一个内存缓存中去。只要 buffer中的数据被 refresh 操做刷入 os cache中,这个数据就能够被搜索到了。

为何叫 es 是准实时的? NRT,全称 near real-time。默认是每隔 1 秒 refresh 一次的,因此 es 是准实时的,由于写入的数据 1 秒以后才能被看到。能够经过 es 的 restful api 或者 java api,手动执行一次 refresh 操做,就是手动将 buffer 中的数据刷入 os cache中,让数据立马就能够被搜索到。只要数据被输入 os cache 中,buffer 就会被清空了,由于不须要保留 buffer 了,数据在 translog 里面已经持久化到磁盘去一份了。

重复上面的步骤,新的数据不断进入 buffer 和 translog,不断将 buffer 数据写入一个又一个新的 segment file 中去,每次 refresh 完 buffer 清空,translog 保留。随着这个过程推动,translog 会变得愈来愈大。当 translog 达到必定长度的时候,就会触发 commit 操做。

commit 操做发生第一步,就是将 buffer 中现有数据 refresh 到 os cache 中去,清空 buffer。而后,将一个 commit point写入磁盘文件,里面标识着这个 commit point 对应的全部 segment file,同时强行将 os cache 中目前全部的数据都 fsync 到磁盘文件中去。最后清空 现有 translog 日志文件,重启一个 translog,此时 commit 操做完成。

这个 commit 操做叫作 flush。默认 30 分钟自动执行一次 flush,但若是 translog 过大,也会触发 flush。flush 操做就对应着 commit 的全过程,咱们能够经过 es api,手动执行 flush 操做,手动将 os cache 中的数据 fsync 强刷到磁盘上去。

translog 日志文件的做用是什么?你执行 commit 操做以前,数据要么是停留在 buffer 中,要么是停留在 os cache 中,不管是 buffer 仍是 os cache 都是内存,一旦这台机器死了,内存中的数据就全丢了。因此须要将数据对应的操做写入一个专门的日志文件 translog 中,一旦此时机器宕机,再次重启的时候,es 会自动读取 translog 日志文件中的数据,恢复到内存 buffer 和 os cache 中去。

translog 其实也是先写入 os cache 的,默认每隔 5 秒刷一次到磁盘中去,因此默认状况下,可能有 5 秒的数据会仅仅停留在 buffer 或者 translog 文件的 os cache 中,若是此时机器挂了,会丢失 5 秒钟的数据。可是这样性能比较好,最多丢 5 秒的数据。也能够将 translog 设置成每次写操做必须是直接 fsync 到磁盘,可是性能会差不少。

实际上你在这里,若是面试官没有问你 es 丢数据的问题,你能够在这里给面试官炫一把,你说,其实 es 第一是准实时的,数据写入 1 秒后能够搜索到;可能会丢失数据的。有 5 秒的数据,停留在 buffer、translog os cache、segment file os cache 中,而不在磁盘上,此时若是宕机,会致使 5 秒的数据丢失。

总结一下,数据先写入内存 buffer,而后每隔 1s,将数据 refresh 到 os cache,到了 os cache 数据就能被搜索到(因此咱们才说 es 从写入到能被搜索到,中间有 1s 的延迟)。每隔 5s,将数据写入 translog 文件(这样若是机器宕机,内存数据全没,最多会有 5s 的数据丢失),translog 大到必定程度,或者默认每隔 30mins,会触发 commit 操做,将缓冲区的数据都 flush 到 segment file 磁盘文件中。

数据写入 segment file 以后,同时就创建好了倒排索引。

删除/更新数据底层原理

若是是删除操做,commit 的时候会生成一个 .del 文件,里面将某个 doc 标识为 deleted 状态,那么搜索的时候根据 .del 文件就知道这个 doc 是否被删除了。

若是是更新操做,就是将原来的 doc 标识为 deleted 状态,而后新写入一条数据。

buffer 每 refresh 一次,就会产生一个 segment file,因此默认状况下是 1 秒钟一个 segment file,这样下来 segment file 会愈来愈多,此时会按期执行 merge。每次 merge 的时候,会将多个 segment file 合并成一个,同时这里会将标识为 deleted 的 doc 给物理删除掉,而后将新的 segment file 写入磁盘,这里会写一个 commit point,标识全部新的 segment file,而后打开 segment file 供搜索使用,同时删除旧的 segment file

底层 lucene

简单来讲,lucene 就是一个 jar 包,里面包含了封装好的各类创建倒排索引的算法代码。咱们用 Java 开发的时候,引入 lucene jar,而后基于 lucene 的 api 去开发就能够了。

经过 lucene,咱们能够将已有的数据创建索引,lucene 会在本地磁盘上面,给咱们组织索引的数据结构。

倒排索引

在搜索引擎中,每一个文档都有一个对应的文档 ID,文档内容被表示为一系列关键词的集合。例如,文档 1 通过分词,提取了 20 个关键词,每一个关键词都会记录它在文档中出现的次数和出现位置。

那么,倒排索引就是关键词到文档 ID 的映射,每一个关键词都对应着一系列的文件,这些文件中都出现了关键词。

举个栗子。

有如下文档:

对文档进行分词以后,获得如下倒排索引。

另外,实用的倒排索引还能够记录更多的信息,好比文档频率信息,表示在文档集合中有多少个文档包含某个单词。

那么,有了倒排索引,搜索引擎能够很方便地响应用户的查询。好比用户输入查询 Facebook,搜索系统查找倒排索引,从中读出包含这个单词的文档,这些文档就是提供给用户的搜索结果。

要注意倒排索引的两个重要细节:

  • 倒排索引中的全部词项对应一个或多个文档;
  • 倒排索引中的词项根据字典顺序升序排列

上面只是一个简单的栗子,并无严格按照字典顺序升序排列。

 

免费Java资料须要本身领取,涵盖了Java、Redis、MongoDB、MySQL、Zookeeper、Spring Cloud、Dubbo/Kafka、Hadoop、Hbase、Flink等高并发分布式、大数据、机器学习等技术。
传送门:
相关文章
相关标签/搜索