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

一、ES写数据过程

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

二、ES度数据过程

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

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

三、ES搜索数据过程

es最强大的是做全文检索

  1. 客户端发送请求到一个coordinating node。
  2. 协调节点将搜索请求转发到所有的shard对应的primary shard或者replica shard,都可以
  3. query phase:每个shard将自己搜索的结果(其中就是一些doc id)返回给协调节点,由协调节点进行数据的合并、排序、分页等操作,产出最终结果。
  4. fetch phase: 接着有协调节点根据doc id去各个节点上拉取实际的document数据,最终返回给客户端。
    写请求是写入primary shard,然后同步给所有的replica shard
    读请求可以从primary shard或者replica shard读取,采用的是随机轮询算法。

es的写入性能比mysql高吗 es写入原理_搜索

四、写数据底层原理

  1. 先写入内存buffer,在buffer里的数据是搜索不到的;同时将数据写入translog日志文件。
    如果buffer快满了,或者到达一定时间,就将内存buffer数据refresh到一个新的segment file中,但是此时数据不是直接进入segment file磁盘文件,而是先进入os cache。这个过程就是refresh。
    这里新segment会被先写入到文件系统缓存–这一步代价会比较低,稍后再被刷新到磁盘–这一步代价比较高。不过只要文件已经在缓存中, 就可以像其它文件一样被打开和读取了,内存buffer被清空。此时,新segment 中的文件就可以被搜索了,这就意味着document从被写入到可以被搜索需要一秒种,如果要更改这个属性,可以执行以下操作
PUT /my_index
{
  "settings": {
    "refresh_interval": "30s" 
  }
}

每隔1秒钟,es将buffer中的数据写入一个新的segment file,每秒钟会写入一个新的segment file,这个segment file中就存储最近1秒内 buffer中写入的数据。

  1. 但是如果buffer里面此时没有数据,那当然不会执行refresh操作,如果buffer里面有数据,默认1秒钟执行一次refresh操作,输入一个新的segment file中。
    操作系统里面,磁盘文件其实都有一个东西,叫做os cache,即操作系统缓存,就是说数据写入磁盘文件之前,会先进入os cache,先进入操作系统级别的一个内存缓存中去。只要buffer中的数据被refresh操作输入os cache中,这个数据就可以被搜索到了。
  2. 为什么叫es是准实时的?NRT,全称near real-time。默认就是每个1miaorefresh一次的,所以es是准实时的,因为写入的数据1s之后才能被看到。
    可以通过es的restfull api或者java api,手动执行一次refresh操作,就是手动将buffer中的数据刷入os cache中,让数据立马就可以被搜索到。只要数据被输入os cache中,buffer就会被清空了,因为不需要保留buffer了,数据在translog里面已经持久化到磁盘去一份了。
  3. 重复上面的步骤,新的数据就不断进入buffer和translog,不断将buffer数据写入一个又一个新的segment file中去,每次refresh完buffer清空,translog保留
    随着这个过程的推荐,translog会变得越来越大。当translog达到一定的长度时候,就会触发commit操作。
  4. commit操作发送的第一步,就是讲buffer中现有的数据refresh到os cache中,清空buffer。然后将一个commit point写入磁盘文件,里面标识着这个commit对应的所有segment file,同时强行将os cache中目前所有的数据都fsync到磁盘文件中去。最后清空现有translog日志文件,重启一个translog,此时commit操作完成。
  5. 这个commit操作叫做flush。默认30分钟自动执行一次flush。但是如果translog过大,也会触发flush。flush操作就对应着commit的全过程。我们可以通过es api,手动执行flush操作,手动将os cache中的数据fsync强制刷到磁盘上去。
  6. translog日志文件的作用是什么?
    执行commit操作之前,数据要么是停留在buffer中,要么是停留在os cache中,无论是buffer还是os cache都是内存,一旦这条机器挂了,内存中的数据就全丢了。
    所以需要将数据对应的操作写入一个专门的日志文件translog中,一旦此时机器宕机了,再次重启的时候,es会自动读取translog日志文件中的数据,恢复到内存buffer和os cache中去。
  7. translog其实也是也写入os cache的,默认每隔5秒刷新一次到磁盘中,所以默认情况下,可能有5s的数据会仅仅停留在buffer或者translog文件的os cache中,如果此时机器挂了,会丢失5秒钟的数据。但是这样性能比较好,最多丢失5秒的数据。
    也可以将translog设置成每次写必须是直接fsync到磁盘,但是性能会差很多
  8. es第一是准实时的,数据写入1秒后就可以搜索到:可能会丢失数据的。有5秒的数据,停留在buffer、translog os cache 、segment file os cache中,而不在磁盘上,

此时如果宕机,会导致5秒的数据丢失。
10. 总结:数据写写入内存buffer,然后每隔1s,将数据refresh到os cache,到了os cache数据就能被搜索到。
每隔5s,将数据写入到translog文件(这样如果机器宕机,内存数据全美,最多有5s的数据丢失)
translog达到一定量或者默认每隔30min,会触发commit操作,将缓存区的数据flush到segment file磁盘文件中。
数据写入到segment file之后,同时就建立好了倒排索引

五、删除、更新数据底层原理

如果是删除操作,commit的时候会生成一个.del
文件,里面讲某个doc标识为delete状态,那么搜索的时候根据.del文件就知道这个doc是被删除了。
如果是更新操作,就是讲原来的doc标识为delete状态,然后重新写入一条记录。

buffer没refresh一次,就会产生一个segment file,所以默认情况下是1秒钟产生一个segment file,这样segment会越来越多,此时ES会定期执行merge。
每次merge的时候,会将多个大小相似的segment file合并为一个,同时这里会将标识为deleted的doc给物理删除掉,然后将新的segment file写入磁盘,这样会写一个commit point,标识所有新的segment file,然后打开segment file功搜索使用,同时删除旧的segment file。

六、底层Lucene

简单来说,lucence就是一个jar包,里面包含了封装好的各种简历倒排索引的算法代码。我们用java开发的时候,引入就lucene jar,然后基于Lucene的api就可以开发了。
通过lucene,我们可以将已有的数据建立索引,lucene会在本地磁盘上面,给我们组织索引的数据结构

七、倒排索引

在搜索引擎中,每个文档都有一个对应的文档ID,文档内容被标识为一系列关键词的集合,例如文档1经过分词,提取到了20个关键词,每个关键词item都会记录它在文档中出现的次数和出现位置。
那么,倒排索引就是关键词到文档ID的映射,每个关键词都对应着一系列的文件,这些文件中都出现了关键词。

举个栗子。

有以下文档:

es的写入性能比mysql高吗 es写入原理_倒排索引_02

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

es的写入性能比mysql高吗 es写入原理_数据_03

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

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

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

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

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