谈谈ES读写数据那些事

前言

ES最强的的能力就是能做全文检索,在互联网平台或者文档档案平台随处可见,那么ES中数据如何实现读写操作的呢以及ES是如何检索数据的呢,下面文章就揭晓下这些问题。

ES写数据过程

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

上述可以理解为协调节点对document进行路由转发到其它节点包含主分片,然后主分片进行处理数据同步到副本,最后再由协调节点返回响应结果给客户端。其过程即如下图所示 es-1

ES读数据过程

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

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

ES搜索数据过程

ES最强大的是做全文检索

  1. 客户端发送请求到一个coordinate 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写数据底层原理

ES写数据过程分析

  1. 先写入内存buffer,此时buffer中的数据是无法搜索的,同时将数据写入translog日志文件。

    如果buffer快满时,或者到一定时间,此时会将内存buffer数据refresh到一个新文件segment file中但是此时数据不是直接进入segment file磁盘文件,而是先进入os cache 此过程就是refresh。

    默认每间隔1s钟,es将buffer中数据写入一个新的segment file,即每秒钟会写入一个新的segment file,此时segment file就存储最近1s内buffer中写入数据。

  2. 如果buffer中无数据,不会执行refresh操作,如果buffer里面有数据,默认1秒钟执行一次refresh操作,输入一个新的segment file中。 操作系统里面,磁盘文件其实都有一个东西,叫做os cache,即操作系统缓存,就是说数据写入磁盘文件之前,会先进入os cache,先进入操作系统级别的一个内存缓存中去。只要buffer中的数据被refresh操作输入os cache中,这个数据就可以被搜索到了。

  3. ES是准实时(NRT),全称 near real-time.默认是每隔1秒refresh一次的,所以es是准实时的,因为写入的数据1s之后才能被看到。

    可以通过es的restful api或者 java api,手动执行一次 refresh操作,就是手动将buffer中的数据刷入os cache中,让数据立马就可以被搜索到。只要

    数据被输入os cache中,buffer 就会被清空了,因为不需要保留buffer了,数据在translog里面已经持久化到磁盘去一份了。

  4. 重复上面的步骤,新的数据不断进入buffer和translog,不断将buffer数据写入一个又一个新的segment file中去,每次refresh完buffer清空,translog保留。

    随着这个过程的推进,translog会变得越来越大。当translog达到一定长度的时候,就会触发commit操作。

  5. commit操作发生的第一步,就是将buffer中现有的数据refresh到os cache中去,清空buffer。然后将一个commit point写入磁盘文件,里面标识者这个commit

    point 对应的所有segment file,同时强行将os cache中目前所有的数据都fsync到磁盘文件中去。最后清空现有 translog日志文件,重启一个translog,此时commit操作完成。

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

  7. 执行commit 操作之前,数据要么是停留在buffer中,要么是停留在os cache中,无论是buffer 还是os cache都是内存,一旦这台机器死了,内存中的数据就全丢失。所以需要将数据对应的操作写入一个专门的日志文件translog中,一旦此时机器宕机了,再次重启的时候,es会自动读取translog日志文件中的数据,恢复到内存buffer和os cache。

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

  9. es第一是准实时的,数据写入1秒后就可以搜索到:可能会丢失数据的。有5秒的数据,停留在buffer、translog os cache 、segment file os cache中,而不在磁盘上,此时如果宕机,会导致5秒的数据丢失。

ES总体写入数据分析

数据先写入内存buffer,然后每隔1s,将数据refresh到 os cache,到了 os cache数据就能被搜索到(所以我们才说es从写入到能被搜索到,中间有1s的延迟)。每隔5s,将数据写入到translog文件(这样如果机器宕机,内存数据全没,最多会有5s的数据丢失),translog达到一定程度,或者默认每隔30min,会触发commit操作,将缓冲区的数据都flush到segment file磁盘文件中。数据写入 segment file之后,同时就建立好了倒排索引 。如下图所示

es-2

ES写入数据流程几大特性

  1. 可靠性

    通过Replica和TransLog两套机制保证数据的可靠性。

  2. 一致性

    Lucene中的Flush锁只保证Update接口里面Delete和Add中间不会Flush,但无法保证主分片与副本分片一致。因为如果add之后立即flush,这个时候segment是主分片可见的,但副本分片要落后于主分片。不过最终都会一致。

  3. 原子性

    Add和Delete具有原子性。当部分更新时,使用Version和锁保证更新是原子的

  4. 实时性

    Flush之后的segment对用户可见,最快可配置100ms,可实现near-real-time。特定的查询,直接查TransLog,可实现real-time。

  5. 隔离性

    采用Version和局部锁来保证更新的是特定版本的数据;

  6. 高效性

    • 不需要所有Replica都返回后才能返回给用户,只需要返回特定数目的就行;
    • 生成的Segment现在内存中提供服务,等一段时间后才刷新到磁盘,Segment在内存这段时间的可靠性由TransLog保证;
    • TransLog可以配置为周期性的Flush,但这个会给可靠性带来影响;
    • 每个线程持有一个Segment,多线程时相互不影响,相互独立,性能更好;
    • 系统的写入流程对版本依赖较重,读取频率较高,因此采用了versionMap,减少热点数据的多次磁盘IO开销;

ES 删除、更新数据操作原理

如果是删除操作,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。

底层lucence

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

倒排索引

在搜索引擎中,每个文档都有一个对应的文档ID,文档内容被标识为一系列关键词的集合,例如文档1经过分词,提取到了20个关键词,每个关键词item都会记录它在文档中出现的次数和出现位置。那么,倒排索引就是关键词到文档ID的映射,每个关键词都对应着一系列的文件,这些文件中都出现了关键词。另外,实用的倒排索引还可以记录更多的信息,比如文档频率信息,表示在文档集合中有多少个文档包含某个词。

  • 倒排索引中的所有词项对应一个或多个文档
  • 倒排索引中的词项根据字典顺序升序排列
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章