Elasticsearch中的document

Posted by RussXia on April 4, 2019

Reading and Writing documents

在es中每个索引都会被分成几个分片(shard),每个分片又会有几个副本(replication)。在删除、新增、更新文档时,必须同步到各个副本,否则从各个副本中读取的数据就会不一致。我们把保持分片副本间的同步和提供数据读取称之为”data replication model”。

es中的 data replication model 基于主备模型(primary-backup model)。以replication group(副本组,实际是主分片)的单个副本为基础。其它副本叫做 replica shards(副本分片)。主分片是所有索引操作的入口。它负责验证索引操作是否有效。一旦主分片接受一个索引操作,主分片的副本分片也会接受该操作。

Basic write model

每个索引操作都会先路由到对应的replication group(分片组),一旦确定了分片组,就会内部转发到分片组中的主分片。主分片负责验证操作和同步到其他副本。ES的主节维护一份可以工作的分片副本列表,称之为 in-sync copies。

主分片主要遵循以下流程:

  • 验证操作,如果结构有问题就拒绝(例如,对 object 字段指定一个数字值)
  • 本地执行操作,例如删除/index相关文档,这一步也会验证字段,不通过就reject。
  • 向还存在于in-sync copies的副本同步操作,如果存在多个副本,这一步是并行的。
  • 主分片确认了分片结果即可返回信息到客户端(可以配置wait_for_active_shards参数来调整,默认是只等待主分片处于活跃状态)。

Failure handing(失败处理)

在索引期间,可能会发生许多情况–例如磁盘损坏,节点之间丢失连接,或者某些配置错误导致不能在副本分片上执行某些操作等。主节点必须上报这些信息。

对于主分片自身错误的情况,主分片所在的节点会发送一个消息给master节点。这个索引会暂时不可用(默认最多一分钟),master节点会提升一个副本分片为主分片,请求会被转发到新的主分片处理。 master 同样会监控节点的健康,并且可能会主动降级主分片。这通常发生在主分片所在的节点和集群失去联系的时候。

一旦在主分片的上的操作执行成功,主分片必须处理在副本分片上执行时可能发生的错误(保证主从节点数据的一致性)。错误的原因有可能是主分片无法同步到副本分片,也可能是副本分片执行结果无法返回给主分片。这些错误情况都将导致 in-sync replica set 中的一个分片丢失。为了避免数据不一样,主分片发送一条消息到master节点,要求将有问题的分片从in-sync replica set 中摘出去,一旦master节点确认移除了这个节点(green–>yellow),主分片也会确认此处操作。master此时也会指导另一个节点建立一个副本分片,以便使系统回复健康(yellow–>green)。

当请求转发到副本分片时,主分片也会使用副本来验证自己是不是仍是一个活跃的主节点(主节点发生了网络隔离或者长时间的gc),在它意识到自己被降级前,它会继续处理收到的索引操作。副本分片会拒绝这个”老的”主节点的操作请求(因为它已经不是主节点了),它会访问master节点,然后发现自己被替换了。后续操作也会被路由到新的主节点。

Basic read model

通过ID的查询是非常轻量的,但是复杂的聚合操作会浪费大量的cpu资源。主备模型的好处之一就是保证所有副本分片都是一致的(正在执行的操作例外)。因此,单个 in-sync 副本也可以处理读请求。

当一个读请求被一个节点接收,这个节点负责转发请求到其他持有相关分片的节点,整理各个节点的响应,返回给客户端。我们称这个节点为协调节点。基本流程如下:

  • 读请求转发到相关分片,注意,因为大多数搜索都会发送到一个或多个索引,通常需要从多个分片读取,每个分片负责其中的一段数据。
  • 从the shard replication group中选择一个活跃的副本,可以是主分片也可以是副本分片。默认情况下,es会轮训整个副本分片。
  • 发送分片级别的读请求到选中的副本。
  • 合并结果并响应。(通过ID查询的get请求,会跳过这个步骤,因为只有一个相关分片)

Failure handling

当分片不能响应时,协调节点会从 replication group 中选择另一个副本,并发送请求到该副本代替不可用的副本。没有可用的分片副本会报错。某些情况下,Elasticsearch 更喜欢尽早响应,即使只有部分的结果,而不是等待问题解决(你可以在响应结果的 _shards 字段,检查本次结果是完整的还是部分的)

A few simple implications

  • Efficient reads(高效读取)
    在正常操作下,每个读操作,对相应的分片组只会操作一次。只有在故障的情况下,才会对多个副本执行相同的搜索。

  • Read unacknowledged(读未确认)
    由于主分片首先在本地进行索引,然后复制请求,所以并发读取可以在确认之前已经看到更改。

  • Two copies by default
    该模型可以容错,同时只保留两个数据副本。这与 quorum-based(投票选主) 的系统相反,其中容错的最小副本为 3。

Failures(可能出现的问题)

  • A single shard can slow down indexing(单个分片可以降低索引速度)
    由于每次操作,主分片都会等待所有 in-sycn 中的副本,单个副本慢会拖慢整个replication group。这也是Efficient reads带来的代价。当然,单个缓慢的分片,也会减少路由给他的unlucky searches。

  • Dirty reads(脏读)
    当被隔离的主节点发送请求到它的副本或者主节点请求master时,才会意识到自己被隔离。这会导致被隔离的主节点可能会暴露未被确认的写入(由于Read unacknowledged机制的存在)。此时,操作已经被写到了主分片,并且同时可以被读取。es 通过每秒(默认)ping一次master降低这种错误,并且,如果 联系不上master,会拒绝索引操作。


存疑

  • 在某些极端的情况下,连续请求两次,一次路由到主节点,一次是还没有完成同步的副本节点。由于Read unacknowledged机制的存在,是不是拿到的数据会不一致?
  • 引入Read unacknowledged机制的目的是什么?提前看到索引操作的结果?那万一读请求被路由到还没有完成同步的副本节点呢? ***