1、直接上架构图

2、前情提要

  • 底层 lucene :lucene 就是一个 jar 包,里面包含了封装好的各种建立倒排索引的算法代码

  • 倒排索引:在搜索引擎中,每个文档都有一个对应的文档 ID,文档内容被表示为一系列关键词的集合。倒排索引就是关键词到文档ID 的映射,每个关键词都对应着一系列的文件,这些文件中都出现了关键词。举个例子 :

3、分布式架构

  多台独立的机器上分别存在es进程,每个es进程中存在多个shard。shard分为primary和replica,replica是primary的从备份,每个primary的replica一般都分布在其他机器上,保证可用性。如果创建一个索引product_idx,那么该索引的数据就会保存在多个shard中。es 集群多个节点,会自动选举一个节点为 master 节点,这个 master 节点其实就是干一些管理的工作的,比如维护索引元数据、负责切换 primary shard 和 replica shard 身份等。要是 master 节点宕机了,那么会重新选举一个节点为 master 节点。如果某个非 master 节点宕机了。那么此节点上的 primary shard 不就没了。那好,master 会让 primary shard 对应的 replica shard(在其他机器上)切换为 primary shard。如果宕机的机器修复了,修复后的节点也不再是 primary shard,而是 replica shard。

4、es写数据

  • 客户端选择一个node节点发送请求过去,该node成为协调节点
  • 协调节点对document路由,找到应该写入的shard primary
    • shard写入内存buffer的同时写入translog
      • 写内存buffer后,每1s执行refresh(所以es是准实时的,有1s的延迟)操作将内存中的数据写入os cache中,写入后将该部分数据从内存buffer中删除,写入os cache中后,搜索引擎就可以查到了,然后os cache会写入segment file中,写入segment file同时就建立好了倒排索引
      • 写translog也是先写os cache,然后每过5s将os cache中的数据存入translog中(所以会存在最多5s的数据丢失)
        • 当translog大的一定程度或者每30分钟,会执行flush操作(第一步:将buffer中的数据刷入os cache中,清空buffer。第二步:将一个commit point 写入磁盘,里面包含了所有的segment file,同时将os cache中的数据都fsync到磁盘中 。第三步:清空translog日志,重启一个translog日志)
  • shard primary写完之后会同步到自己所有的replica
  • 等primary和replica都写完,发送响应结果给客户端

关于写的总结

  • 准实时:有1s的延迟,因为shard写入内存buffer然后buffer默认每隔1s才刷入os cache中
  • translog的作用 :在执行flush操作之前,数据都在buffer或者os cache中,此时如果宕机数据丢失。那么translog的作用就是当出现宕机的情况,重启时会自动读取translog日志,恢复数据
  • 5s数据丢失 : shard写入os cache 再写入translog,每隔5s执行一次,那么就会出现5s的数据丢失,当然你可以配置每次修改都写translog,但是性能较低 

5、es读数据

  • 写入数据的时候会生成全局唯一doc id
  • 那么读取数据的时候,发送请求到一个node,成为协调节点
  • 协调节点对doc id进行哈希路由,转发到对应的node,然后通过随机轮询算法,在primary和replica中选择一个,让读请求负载均衡
  • 接收请求的node将数据返回给协调节点
  • 协调节点返回document给客户端
  • 写请求是写入 primary shard,然后同步给所有的 replica shard;读请求可以从 primary shard 或 replica shard 读取,采用的是随机轮询算法。

6、es搜索数据全过程

  • 客户发送查询请求到一个node,成为协调节点
  • 协调节点将请求转发到所有的shard对应的primary或者replica都可以
  • 每个shard返回匹配的doc id给协调节点
  • 协调节点通过这些doc id去查询具体的document
  • 再进行筛选返回给客户端

7、删除数据

  • 磁盘存在.del文件,将数据写入.del文件中标识数据已过期,那么查询的时候发现数据再.del文件中就不会返回
  • 如果是更新操作,将原来的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。