--- 摄于 2017 年 9 月 藏川线前段
距离同步(一)已经两周了,这两周,对 Network 的同步条件做了一些调整,同时对 Executor 的处理也做了一点微调,后续还会在 Executor 和 Chain 的通信方面做一些小的调整,为了性能,也为了稳定性。
current_height | global_height | other condition | action |
---|---|---|---|
20 | 19 | – | – |
20 | 21 | !is_sync && timeout | start sync |
20 | > 21 | !is_sync || timout | start sync |
更改的地方只有一个,就是在判断发起同步的条件,在当前节点只比全局小一的情况下,只需要判断是否在同步状态和超时条件就可以了,不需要判断上一个全局状态与新接到的全局状态之间的关系。
Network 的同步消息是同时发送给 Chain 和 Executor 的,这意味着,同步块的部分处理逻辑在两个模块中会比较类似,比如验证、缓存。这种同时分发的异步消息也导致一个比较麻烦的问题,就是 Executor 和 Chain 的状态一致性问题。
在这样的架构下,Chain 是整个节点的核心状态点,其他模块都需要以 Chain 的广播状态来确定整个节点的状态,并且根据这个状态来确定自己应该要做些什么。三个异步通信模块之间的关系,相对两个模块来说要复杂不止一倍,良好的消息通信设计就成了必须要慎重考虑的一部分内容。
通过前面的一系列文章,大致了解过了 Executor 和 Chain 对各种消息的处理流程,我们可以很清晰的看出,Executor 在接到同步块的情况下,会自顾自地将它们全部执行完,并且每执行一个块,都将结果发给 Chain 一次,理论上来说,最好的情况下,每一次结果的发送,都是正常的,并且 Chain 都能够接收和处理。但是现实情景下的消息发送和接收,是很有可能出现各种意外情况的,比如消息堵塞、消息顺序不一致等一些通信上的问题。
这是一个非常容易出现的问题,导致这个问题的原因有很多,例如,Chain 没有接到执行结果、Chain 被重启了、Chain 被删库了等等。
删库操作一般都是人为的,这个解决办法就是从链上同步回来。
Chain 被重启了,这个是一个测试用例,随机杀死 Executor 或者 Chain,看这个节点是否能够正常恢复过来,这里就会有许多情况了,比较难办的一种就是,在杀死 Executor 和 Chain 的时候,它们的状态刚好是不一致的,比如 Executor 已经执行到了 100,而 Chain 还在处理 98 高度的落盘。这种情况下,重启 Executor 和 Chain,Executor 的执行结果是缓存在内存中的,重启后已经丢失了,而执行结果中的 receipt 是无法实时从数据库中恢复的,Executor 会根据 Chain 的状态进行回滚,重新执行该高度得到结果。
如果是运行中因为消息异步发送或者消息发送失败导致 Chain 没有接到执行结果,这种情况下就会好处理很多,执行结果缓存在内存中,可以根据 Chain 的状态一次性发送所以没有接到的执行结果给 Chain,不用回滚状态重新执行。
CITA 距离 1.0 发版已经不远了,特性方面的开发已经快进入尾声,稳定性和健壮性在最近几个迭代上已经成为主要内容,看我最近的提交也可以看出,一直在做这方面的事情,分布式系统的测试感觉比开发功能还更麻烦。
下一篇就不预测内容了,脸疼 …
请登录后评论
评论区
加载更多