官网文档:https://www.elastic.co/guide/en/elasticsearch/reference/7.3/docs-replication.html
简介
elasticsearch每个索引(index)由多个分片(shard)构成,每个分片又可以有多个副本(replica),这些副本共同组成了副本组(replication group),在添加或删除文档的时候副本组必须保持同步,如果不能保持同步,从一个副本都的数据就会跟另一个副本读的数据有很大的差异。保持副本组各分片数据同步,并提供一致性读取的过程叫做数据副本模型(data replication model)
elasticsearch数据副本模型是基于主备模式,在微软的论文PacificA paper中有详细的介绍。该模型的基本思想是副本组中要有一个主分片,其他的叫做副分片,主分片是写操作的入口。主分片会校验写操作保证其正确性,主分片写完后,需要将写请求转发到其他副分片。
写模型
每个索引操作首先会通过路由(routing)解析对应的副本组,一般会根据文档的id通过hash计算得到,确定副本组后,请求就会被转给给主分片,主分片校验请求,写数据,然后转发给其他副分片。有的副分片有可能已经离线了,所以不要求所有副本都能处理请求。elasticsearch会维护一份可以处理数据请求的列表,这个列表叫做in-sync copies,该列表由主节点负责维护。根据名称可以看出,它们是状态良好的分片,可以保证正确的处理已经给客户端返回的那些索引和删除操作。主分片负责维护这种不变性,需要确保所有的操作都被该列表中的分片正确的处理了。
写失败处理
索引过程中可能会发生很多问题,例如磁盘损坏、节点离线或者一些配置错误可能导致主分片写成功而副分片写失败,这些虽然不经常发生,有问题主分片就要进行处理。
如果主分片写失败,其所在节点会向主节点汇报,当前写操作需要等待(默认1分钟),等到主节点提升一个副分片为主分片,然后请求被转发到新的主分片进行处理。需要注意的是主节点还会一直监测各节点的健康状况,有可能会主动将主分片降级,这往往是因为拥有主分片的节点因为网络原因从集群中脱离了。
主分片一旦写操作完成,它需要负责处理在副分片写失败的潜在风险,有可能因为网络原因导致请求没被转发到副分片或者副分片的响应到不了主分片,这些都会导致一个结果:在in-sync列表的这个副分片丢失了一次应该确认的写操作,为了避免破坏上述所说的不变性,主分片会向主节点请求将该副分片从in-sync同步列表中移除,只有主节点确认将该副分片从该同步列表中移除后,主分片才会向客户端返回响应。主节点随后会在其它从节点上再构建一个新的副分片,这样集群才会到一个健康的状态。
当把请求转发给副分片时,主分片会通过副分片校验它是主分片的合法性。如果主分片因为网络原因或长时间的GC而导致离线,它可能已经被降级还没意识到这一点,还在处理索引请求。接收到被降级的主分片发来的索引请求后,副分片会拒绝执行,当主分片接收到副分片发来的拒绝执行响应后,它就会知道自己已经不是主分片。主分片向主节点确认后知道自己被替换,然后把请求转发到新的主分片。
只有主分片没有副本的情况
这个一个正常的场景,或者发生在所有的副本分片都出错了,在这种情况下,主分片执行的操作得不到额外的验证,可能就会导致一些问题。另一方面,主分片不能让其它副本失败,而是通过主节点代表它处理,这就意味着主节点知道这个主分片是唯一状态良好的分片了,所以要确保不能提升其它过时的分片为主分片,在该主分片上的写操作不能出错,当然物理硬件损坏的话还是会导致数据丢失。
读模型
elasticsearch的读操作可以是非常轻量级的根据文档id查找或者是很耗CPU的复杂的聚合操作。主副本模型的好处是所有的副本都拥有一致的数据(当前正在写的除外),这样in-sync列表只要有一个分片正常就可以提供读操作。
当节点接收到读请求后,该节点(协调节点)负责转发请求到那些有需要索引的节点上,然后合并各节点结果,给客户端做出响应。
分片处理失败
当一个分片处理读请求失败时,协调节点会将请求发到拥有该分片副本组的其它节点上接着处理,如果该副本组都失败了,那就没辙了。
为了确保快速响应,下面几种API允许在一个或多个分片失败的情况下返回部分结果:
Search
Multi Search
Bulk
Multi Get