文档索引步骤

  1. 客户端向node1发送新建,查问或删除申请。
  2. 节点应用文档的_id确定文档属于分片0,申请会被转发到node3,因为分片0的主分片目前被调配在node3上
  3. node3在主分片下面执行申请,如果胜利了,它会将申请并行转化到node1与node2的正本分片上,一旦所有的正本分片都报告胜利,node3将向协调节点报告胜利,协调节点向客户端报告胜利。

下面是按单个文档操作的,多个文档在应用bulk操作时和下面流程差不多,这里不再多说。

文档索引过程详解

整体流程图。

  • 协调节点默认应用文档ID参加计算(也反对通过routing), 以便为路由提供适合的分片。

    shard = hash(document_id) % (num_of_primary_shards)
  • 当分片所在的节点接管到来自协调节点的申请后,会将申请写入到memory buffer,而后定时(默认1秒)写入到filesystem cache(操作系统文件缓存,这里不禁JVM治理),从memory buffer到filesystem cache的过程就叫refresh。须要留神的是数据写入memory buffer后并不以马上被检索,而只有通过refresh写入到filesystem caceh后也就是写入到segment之后,此时文档才能够被检索到。
  • 因为memory buffer与filesystem cache都还未写入磁盘所以会有失落的可能。ES是通过translog机制来保证数据的可靠性的。在接管到申请后,同时也会写入到translog,当filesystem cache中的数据写入到磁盘后才会革除translog里的数据,这个过程称flush。flush是定时触发(默认30分钟)或translog变得太大(默认为512MS)。

并发下的update流程

ES应用版本号这种乐观锁的机制解决并发批改问题,ES保障了一个老版本的数据永远无奈重写或笼罩更新版本的数据,如果因版本号抵触批改失败能够应用retry_on_conflict参数设定重试次数。流程如下:

  1. 收到update申请后,从segment或者translog中读取同id的Doc,并获取此时版本号。
  2. 将第1步版本号对应的全量Doc和申请中的局部字段合并为一个残缺的Doc,同时更新内存中的versionMap。这个时候update申请相当于一个index申请了。
  3. 加锁。
  4. 再次从versionMap中读取该id最大版本号,如果versionMap没有,则从segment或translog里读。
  5. 查看版本号是否抵触(查看第1步与第4步的版本号是否雷同,雷同为不抵触,不雷同为抵触),如果抵触则回退到开始的update doc阶段从新执行;如果没抵触则执行最新的add申请。
  6. 在index doc阶段,首先将version+1,再将doc退出到lucene中,lucene会先删除同id下已存在的doc id,而后再减少新doc,写入lucene胜利后,将更新后的版本号更新到versionMap。
  7. 开释锁,局部更新流程完结。

ES里的translog

ES为了缩小磁盘IO保障读写性能,个别是每隔一段时间(比方5分钟)才会将segment写入磁盘长久化,对于还未flush到磁盘的数据,如果产生宕机或掉电,那么内存里的数据是会失落的,ES是如何保证数据的可靠性的呢?这里咱们来说下translog。

在每个shard中,写入流程分两局部,先写入lucene,再写入到translog。写完lucene文件创建好索引后,此时索引还在内存里,接着去写translog,写完translog后,刷新translog数据到磁盘上(这个是可配置的,可能会立刻flush到磁盘也可能距离一段时间再flush),写磁盘胜利后,申请返回用户。这里有几个关键点:

  1. 一是和数据库不同,数据库是先写commitlog,而后再写内存,而ES是先写内存再写translog,一种可能起因是lucene内存写入有很简单的逻辑,容易失败,比方分词,字段长度超限等,为了防止translog里有大量有效记录,就将写内存放到了后面
  2. 二是写入内存后,并不是可搜寻的,须要通过refresh将内存的对象转换成残缺的segment后,而后再次reopen后能力被搜寻,个别这个工夫设置为1秒,这也是ES被称为NRT(near real time)的起因
  3. 三是当ES作为nosql数据库时,查问形式是getDocById,这种查问能够间接从translog中查问(translog是以key/value模式写入的,key是_id,value是Doc内容),这时就成了RT实时零碎了。
  4. 四是每隔一段较长时间,比方30分钟后,lucene会将内存中生成的segment刷新到磁盘上,刷新后的索引文件曾经长久化了,历史的translog会被清掉

个性总结

  • 可靠性:因为lucene的设计不思考可靠性,在ES中通过replica和translog两套机制保证数据的可靠性
  • 一致性:lucence中的flush锁只保障update接口里的delete和add两头不会flush,然而add实现后依然有可能立刻产生flush,导致segment可读,这样就没法保障primary和其余replica能够同一时间flush,进而呈现查问不稳固的状况,这里只能实现最终一致性。
  • 原子性:add与delete都是间接调用lucene的接口,是原子的。当局部更新时,应用version和锁保障更新是原子的。
  • 隔离性:依然采纳version和部分锁来保住更新的是特定版本的数据
  • 实时性:应用定期refresh segment到内存,并且reopen segment形式保障搜寻能够在较短时间(比方1秒)内被搜寻到。通过将未刷新到磁盘数据记入translog,保障对未提交数据能够通过ID实时拜访到