ES recovery、主副分片复制会有一段时间block写入?

简介: ES在主副本分片复制时候不会block写入(version > 2.x)ES在recovery主分片时候会有一段时间block写入

背景:

ES recovery、主副分片复制会有一段时间block写入?

先说结论:

1.ES在主副本分片复制时候不会block写入(version > 2.x)

2.ES在recovery主分片时候会有一段时间block写入

主副分片同步(新增副本分片)(该部分来自于:参考2)

1.在ES 2.0 版本之前,副本recovery要经历三个阶段:需要block写一段时间(这也是最容易实现一致性的流程)(此时translog还是只有一个大文件)

流程:
phase1:主分片的lucene做快照,发送到target节点。期间不阻塞写操作,在此拷贝期间新增的数据会写到主分片的translog中。
phase2:将主分片translog做快照,发送到target节点进行重放,重放期间不会阻塞写操作。
phase3:为主分片加写锁,此时会block写入,将剩余的translog发送到target节点。由于此时数据量很小,写入过程的阻塞时间很短。

从phase1开始,就要阻止lucene执行commit操作,避免translog被刷盘后清除。
后续版本去掉了phase3的这个过程,也就意味着不再需要block写入;

2.ES2.x及之后版本
translog被重构,允许多个文件,在translog允许多文件的场景下,也就意味着允许recovery保留所需的文件,同时允许engine执行flush,以及执行lucene的commit(这将创建一个新的translog文件);
引入了translog.view概念,view是一个引用,包含了包括所有当前未提交的translog文件,以及所有未来新创建的translog文件,直到view关闭;因此可以通过该view做operations的遍历操作;
不再需要block写入的阶段,通过将拷贝期间的写入操作同时转发到正在建立的副本分片(多写)来避免copy translog过程中的实时写入数据不能被副本获取的情况,从而保证主副一致;

流程:
创建一个Translog.view,用来重放operations;
phase1:将主分片的lucene做快照,发送到target。期间允许索引操作和flush操作。发送完毕后,告知target启动engine,engine启动(副本的lucene)后,即phase1即将结束(phase2开始之前),新的索引操作都会转发副分片正常执行
phase2:将主分片的translog做快照,发送到target去重放;

完整性:
phase2对translog的快照包含了从phase1开始的新增操作。而phase1即将结束、phase2开始之前,副分片已经可以正常处理写操作,只要把phase2的translog重放(主要是为了恢复phase1中target的engine未启动之前主分片写入的数据),就可以保证副分片不丢数据;

image.png

一致性:
由于没有了阻塞写操作的第三阶段,接下来的问题就是解决phase1和phase2之间的写操作,与phase2重放操作之间的时序和冲突问题。在phase1执行完毕后,副分片已经可以正常处理写请求,副分片的新增写操作和 translog重放的写操作是并行执行的。如果translog重放慢,又把他写回老数据怎么办(translog的数据覆盖掉新写入/更新的数据)?
es现在的机制是在写操作(新增、更新、删除)中做异常处理。新增不存在冲突,只需要判断update、delete操作的版本号是否小于lucene中doc的版本号,大于才能操作;
注:Index,Delete,都继承自Operation,每个Operation都有一个版本号,这个版本号就是lucene中doc版本号;

ES在recovery

1.recovery副本分片
副本分片从node1,move到node2的流程:
1.master节点将该副本分片标记成relocating状态,此时从主分片开始拷贝lucene文件到node2(拷贝完成之后启动node2副本分片的lucene引擎),然后走主副本分片同步数据的逻辑(如上描述);
2.完成后该副本被标记为started,然后node1中的副本分片进行删除,完成此次recovery。
注:copy过程中写入是会写到3个分片上(主、副本、recovery后的副本),‘recovery后的副本’是在阶段2(阶段1的文件拷贝完成、lucene启动后)才接受写入。
recovery副本分片的场景:相当于直接增加一个副本分片,然后再下掉老的副本分片;

image.png

此过程不会block写入;

2.recovery主分片
primary分片从node0,move到node1的过程:
1.master节点下发状态,将该主分片标记relocating,更新routing_table和routing_nodes;
2.target分片会开始复制primary的lucene文件块;此时写入请求到达source节点时,会正常写入到source主分片中(不会同时写到target)。
注意:在分片的整个relocating过程中,对target节点的请求都会被转发到source节点,直到target节点应用了master下发的分片变为STARTED的集群状态
3.lucene文件拷贝完成后进入下一阶段。该阶段主要是target分片复制translog,并重放translog
该阶段收到的写入请求后复制给target节点(将target分片加入到 replication group)(即source分片写入、target分片也写入)。
4.tranlog复制并重放完成意味着数据已经对齐,进入下一阶段(handoff阻塞阶段)。该阶段是为了完成主分片状态的转移,该阶段对收到的写入请求放到队列(delayedOperations)中,写入流程结束,但是不会返回响应给client,待主分片状态转移完成后继续执行,最多阻塞30分钟。delayedOperations中的操作会在本阶段的阻塞过程结束后处理
注:该阶段时间很短,只是修改一个状态,使写入进入阻塞;
5.最后一个阶段是执行失败重试的逻辑,该阶段主要是target分片向master节点发送变更状态为started请求,并等待master下发状态变更;
上一步的阻塞阶段虽然时间很短,但是依然会有写入,delayedOperations中的数据在进入该阶段的时候处理;与该阶段的写入请求是统一的处理逻辑。
处理逻辑:
该阶段的写入请求和delayedOperations中的请求都会执行失败,抛出 ShardNotInPrimaryModeException异常,并捕获该异常,等待1分钟后重试写入,再次失败则退出;
如果1分钟内收到了新的集群状态,也会重试写入,然后写入成功。

补充解释:阻塞和失败重试阶段时间都比较短,但是完成了很多事情,阻塞阶段刚开始是primary分片开始阻塞写入,并告诉target分片可以开始变更分片状态了,此时的写入全部进入队列;
target分片响应了(primary分片接受响应)之后,开始进入“失败重试阶段”;
注:primary接受handoff响应做了什么事情?取消阻塞状态,将primary是主分片的标记清除(也就是说ES不再认为该分片是主分片)
primary开始向target发送recovery结束的消息,target分片接受到消息之后,认为自己可以成为主分片了,所以开始向master节点请求将分片标记为started状态;
master节点收到请求之后立刻下发状态变更命令,target分片状态变更完成之后,整个流程结束;
在此期间的写入请求会因为source(primary)分片已经不是主分片状态了,全部报错(但是不返回客户端),等待一分钟后重试;

图片来自参考1:
image.png

参考:
1.https://blog.51cto.com/u_15162069/2883927
2.https://www.easyice.cn/archives/231#i-2

相关文章
|
弹性计算 网络协议 容灾
PostgreSQL 时间点恢复(PITR)在异步流复制主从模式下,如何避免主备切换后PITR恢复(备库、容灾节点、只读节点)走错时间线(timeline , history , partial , restore_command , recovery.conf)
标签 PostgreSQL , 恢复 , 时间点恢复 , PITR , restore_command , recovery.conf , partial , history , 任意时间点恢复 , timeline , 时间线 背景 政治正确非常重要,对于数据库来说亦如此,一个基于流复制的HA架构的集群,如果还有一堆只读节点,当HA集群发生了主备切换后,这些只读节点能否与新的主节点保持
1661 0
|
7月前
|
NoSQL Redis 容器
Redis集群报错cluster_state:fail,如何解决并重新恢复集群(IP问题/ slot未完全分配问题)
Redis集群报错cluster_state:fail,如何解决并重新恢复集群(IP问题/ slot未完全分配问题)
112 0
|
12月前
|
Oracle 关系型数据库
|
12月前
|
关系型数据库 MySQL 数据库
修改innodb_buffer_pool_instances解决mysqlbinlog恢复慢的问题
一个客户的mysql数据库恢复在最后一步是滚binlog,结果恢复特别慢,CPU占用率100%,磁盘IO几乎是零,show processlist发现线程在sleep。从general log里面看不到任何动静,似乎找不到解决的办法。
336 0
|
弹性计算 容灾 关系型数据库
PostgreSQL PITR 任意时间点恢复过程中如何手工得到recovery需要的下一个WAL文件名 - 默认情况下restore_command自动获取
标签 PostgreSQL , recovery , recovery.conf , restore_command , timeline , 时间线 , next wal , PITR , 时间点恢复 背景 PostgreSQL数据库支持PITR时间点恢复。默认情况下,只需要配置目标是时间点,resotre_command即可,PG会自动调用resotre_command去找需要的WA
1366 0
|
Oracle 关系型数据库 数据库