亲宝软件园·资讯

展开

ElasticSearch写入流程

IT巅峰技术 人气:0

一、前言

介绍我们在前面已经知道ElasticSearch底层的写入是基于lucence依进行doc写入的。ElasticSearch作为一款分布式系统,在写入数据时还需要考虑很多重要的事项,比如:可靠性、原子性、一致性、实时性、隔离性、性能等多个指标。

ElasticSearch是如何做到的呢?下面我们针对ElasticSearch的写入进行分析。

二、lucence写

2.1 增删改

ElasticSearch拿到一个doc后调用lucence的api进行写入的。

 public long addDocument();
 public long updateDocuments();
 public long deleteDocuments();

如上面的代码所示,我们使用lucence的上面的接口就可以完成文档的增删改操作。在lucence中有一个核心的类IndexWriter负责数据写入和索引相关的工作。

//1. 初始化indexwriter对象
IndexWriter writer = new IndexWriter(new Directory(Paths.get("/index")), new IndexWriterConfig());
//2. 创建文档
Document doc = new Document();
doc.add(new StringField("empName", "王某某", Field.Store.YES));
doc.add(new TextField("content", "操作了某菜单", Field.Store.YES));
//3. 添加文档
writer.addDocument(doc);
//4. 提交
writer.commit();

以上代码演示了最基础的lucence的写入操作,主要涉及到几个关键点: 初始化: Directory是负责持久化的,他的具体实现有很多,有本地文件系统、数据库、分布式文件系统等待,ElasticSearch默认的实现是本地文件系统。 Document: Document就是es中的文档,FiledType定义了很多索引类型。这里列举几个常见的类型:

IndexWriter:IndexWriter在doc进行commit后,才会被持久化并且是可搜索的。IndexWriterConfig:IndexWriterConfig负责了一些整体的配置参数,并提供了方便使用者进行功能定制的参数: 

PS:在ElasticSearch中,为了支持分布式的功能,新增了一些系统默认字段:

2.2. 并发模型

上面我们知道indexwriter负责了ElasticSearch索引增删改查。那它具体是如何管理的呢?

2.2.1. 基本操作

关键点:  

2.2.2 更新

Lucene的update和数据库的update不太一样,Lucene的更新是查询后删除再新增。  

2.2.3 删除

上面已经说了,在update中会删除,普通的也会删除,lucence维护了一个全局的删除表,每个线程也会维护一个删除表,他们双向同步数据

2.2.4 flush和commit

每一个WriterPerThread线程会根据flush策略将文档形成segment文件,此时segment的文件还是不可见的,需要indexWriter进行commit后才能被搜索。 这里需要注意:ElasticSearch的refresh对应于lucene的flush,ElasticSearch的flush对应于lucene的commit,ElasticSearch在refresh时通过其它方式使得segment变得可读。

2.2.5 merge

merge是对segment文件合并的动作,这样可以提升查询的效率并且可以真正的删除的文档。

小结

在这里我们稍微总结一下,一个ElasticSearch索引的一个分片对应一个完整的lucene索引, 而一个lucene索引对应多个segment。我们在构建同一个lucene索引的时候, 可能有多个线程在并发构建同一个lucene索引, 这个时候每个线程会对应一个DocumentsWriterPerThread, 而每个 DocumentsWriterPerThread会对应一个index buffer. 在执行了flush以后, 一个 DocumentsWriterPerThread会生成一个segment。

三、 ElasticSearch的写

3.1. 宏观看ElasticSearch请求

在前面的文章已经讨论了写入的流程ElasticSearch

图片来自官网 当写入文档的时候,根据routing规则,会将文档发送至特定的Shard中建立lucence。

注意上面的写入延时=主分片延时+max(Replicas Write),即写入性能如果有副本分片在,就至少是写入两个分片的延时延时之和。

3.2. 详细流程

3.2.1 协调节点内部流程

如上图所示:

3.2.2 主分片节点流程*

 写入(index)

该部分是elasticsarch的核心写入流程,在前面的文章也介绍了,请求到该节点会最终调用lucence的方法,建立lucence索引。其中主要的关键点:

update

介绍其实就是乐观锁的机制,每次更新一次版本号加 1 ,不像关系式数据库有事物,你在更新数据,可能别人也在更新的话,就把你的给覆盖了。你要更新的时候,先查询出来,记住版本号,在更新的时候最新的版本号和你查询的时候不一样,说明别人先更新了。你应该读取最新的数据之后再更新。写成功后,会转发写副本分片,等待响应,并最后返回数据给协调节点。具体的流程:

public boolean enoughShardsActive(final int activeShardCount) {
  if (this.value < 0) {
    throw new IllegalStateException("not enough information to resolve to shard count");
  }
  if (activeShardCount < 0) {
    throw new IllegalArgumentException("activeShardCount cannot be negative");
  }
  return this.value <= activeShardCount;
}

为什么会要校验这个活跃的分片数呢?

发送请求至副本

@Override
public void tryAction(ActionListener<ReplicaResponse> listener) {
  replicasProxy.performOn(shard, replicaRequest, primaryTerm, globalCheckpoint, maxSeqNoOfUpdatesOrDeletes, listener);
}

等待结果

privatevoid decPendingAndFinishIfNeeded() {
  assert pendingActions.get() > 0 : "pending action count goes below 0 for request [" + request + "]";
  if (pendingActions.decrementAndGet() == 0) {
    finish();
  }
}

在以前的版本中,其实是异步请求副本分片的,后来觉得丢失数据的风险很大,就改成同步发送了,即Primary等Replica返回后再返回给客户端。如果副本有写入失败的,ElasticSearch会进行一些重试,但最终并不强求一定要在多少个节点写入成功。在返回的结果中,会包含数据在多少个shard中写入成功了,多少个失败了,如果有副本上传失败,会将失败的副本上报至Master。

PS:ElasticSearch的数据副本模型和kafka副本很相似,都是采用的是ISR机制。即:ES里面有一个:in-sync copies概念,主分片会在索引的时候会同步数据至in-sync copies里面所有的节点,然后再返回ACK给client。而in-sync copies里面的节点是动态变化的,如果出现极端情况,在in-sync copies列表中只有主分片一个的话,这里很容易出现SPOF问题,这个是在ElasticSearch中是如何解决的呢?

就是依靠上面我们分析的wait_for_active_shards参数来防止SPOF,如果配置index的wait_for_active_shards=3就会提前校验必须要有三个活跃的分片才会进行同步,否则拒绝请求。对于可靠性要求高的索引可以提升这个值。

PS:为什么是先写lucence再写入translog呢,这是因为写入lucence写入时会有数据检查,有可能会写入失败,这个是发生在内存之中的,如果先写入磁盘的translog的话,还需要回退日志,比较麻烦

3.2.3 副本分片节点流程8

这个过程和主分片节点的流程基本一样,有些校验可能略微不同,最终都会写入lucence索引。

四、总结

本文介绍了ElasticSearch的写入流程和一些比较详细的机制,最后我们总结下开头我们提出的问题,一个分布式系统需要满足很多特性,大部分特性都能够在ElasticSearch中得到满足。

加载全部内容

相关教程
猜你喜欢
用户评论