Xline 源码解读(四)—— CURP 状态机引擎

在上一篇源码解读的文章(Xline 源码解读(三) —— CURP Server 的实现)中,我们简单阐述了Xline 的 Curp Server 是如何实现的。接下来,就让我们话接上回,继续深入地来了解 Curp Server 中的一些核心的数据结构,特别是 conflict_checked_channel 和 command worker,它们相互协作,共同推动着 CURP Server 内部状态机状态转换。

01、为什么我们需要冲突检测队列?

冲突检测队列本质是一个多生产者多消费者的 channel,其核心职责是维护动态变化的冲突关系,保证在同一时间内,所有的 receiver 都不会接收到冲突的命令。receiver 接收到的命令的顺序(后面称之为冲突序),满足以下两点:

  1. 如果 cmd A 与 cmd B 存在冲突,并且 A 先于 B 被压入队列当中,则 A 会先从队列中弹出。而 B 只有当 A 执行完毕后,才能从队列中弹出。
  2. 如果 cmd A 与 cmd B 不存在冲突,且 A 先于 B 被压入队列,则按照 FIFO 顺序,即 A 会先从队列中弹出,B 后弹出。

单看文字的话可能有些抽象,不过没有关系,让我们来看一个简单的例子:假设我们现在有 A、B、C 三个 command,进入冲突检测队列的顺序依次为 A,B,C。其中 A 与 B 冲突,而 C 与 A 和 B 均不产生冲突,则冲突检测队列的初始状态如下:

当 A、B、C 都进入到队列当中后,3 个不同的 cmd_worker 分别从 channel 获取 command,由于 cmd_worker_1 会先接收到 A。B 则会因为与 A 产生冲突而被缓存在队列当中。C 由于没有任何命令与其冲突,因此可以被 cmd_worker_2 接收。而 B 只有在 A 被执行并且 drop 之后,才会从队列当中弹出。如下图所示: 

可能有些读者会产生疑问:既然 spec_pool 的职责就是判断 fast path 中是否存在冲突,对应了 CURP paper 中的 witness,那为什么还要引入一个冲突检测队列呢?主要原因有二:

  1. 任何命令,不管走的是 fast path 还是 slow path, 最终都必须要在 leader 上得到执行。因此,leader 必须在这些混合的命令中,找到一个合理的执行顺序,来保证命令的执行不会打破 CURP 对命令执行顺序的假设。而 spec_pool 中只保存了可以在 fast path 被执行的命令,并不涉及 slow path 中的命令
  2. 在达成共识的过程当中,我们必须先判断命令是否存在于 spec_pool 当中。这是一个同步的操作,如果将复杂冲突序的计算工作放到 spec_pool 当中,那会很容易形成 bottleneck。因此,我们将判断是否有冲突和计算出冲突序这两个职责进行拆分,将前者放到同步的 spec_pool 当中,而将后者放到异步的冲突检测队列当中执行。

02、冲突检测队列是如何工作的?

要理解冲突检测队列的工作原理,离不开下面两个问题的探讨:

  1. 我们应当如何对冲突关系进行建模?
  2. 面对会动态变化的冲突关系,我们如何快速地找到所有没有冲突的命令?

针对第一个问题,我们可以将所有的命令都看成是一张有向无环图中的顶点,而将冲突关系视为图中顶点之间的有向边。假设命令 A 和命令 B 之间存在冲突(命令的抵达顺序为先 A 后 B),我们便可将冲突关系看成是 A 和 B 之间的一条弧<A, B>,其中弧头总是指向后进来的顶点(这一顺序性就保证了图中不会出现环形冲突)。

一旦我们将冲突关系定义为一个有向无环的非连通图中的一条边,那么执行某个命令时所需要计算的冲突顺序问题,就转换成了一个求有向无环图中,该命令所在的连通分量的拓扑排序问题。针对每个命令,successors(也就是后继) 保存了哪些 cmd 与当前 cmd 冲突,successors 的长度就是该 顶点的出度。而 predecessor_cnt (前驱数)则代表了这个 cmd 与之前的多少个 cmd 存在冲突,也就是该顶点元素的入度。

同样回到我们前面所提到的 A、B、C 的例子当中,当我们使用 DAG 来描述命令的冲突关系,其情况如下图所示。

当 cmd_worker 从 channel 当中接收命令时,channel 只需要遍历这个有向无环图中的每一个连通分量,并找到第一个入度为 0 的顶点即可。只有当 command 执行完毕后,channel 才会更新 B 的 predecessor_cnt,以解决 A 与 B 之间的冲突关系。

03、状态机引擎的架构

正如我们在文章开头所说的那样,冲突检测队列和 command worker 共同组成了 Curp Server 的状态机引擎。冲突检测队列向 command worker 提供无冲突的命令,而 command worker 则负责执行这些命令,并根据结果推动更新冲突检测队列当中的冲突关系。

从结构上来看,Curp Server 状态机引擎是由三对 channel 和一个 filter 构成,其中这三对 channel 分别为:(send_tx,filter_rx)、(filter_tx, recv_rx) 以及 (done_tx, done_rx)具体的结构可以参考下图。

其数据流方向为:send_tx -> filter_rx -> filter -> filter_tx -> recv_rx -> done_tx -> done_rx

其中,send_tx 为 RawCurp 对象所拥有,负责在 propose(对应了 curp 的 fast path)、以及应用日志 apply(对应了 curp 的 slow path) 时向冲突检测队列投递对应的 CEEvent。冲突检测队列则会在计算出冲突顺序后,将 CEEvent 转换成为 Task 并通过 (filter_tx, recv_rx) 投递到 command worker 当中执行。command worker 在执行完Task 后将结果通过 (done_tx, done_rx) 反馈到冲突检测队列中,并更新队列中依赖图中的顶点信息。

04、状态是如何转换的

要理解一个状态机的工作原理,我们需要理解以下两个问题:

  1. 状态机提供了哪些事件以及哪些状态
  2. 哪些事件会导致状态发生转移 让我们先来看看 Curp Server 的状态机引擎都提供了哪些事件。
/// Event for command executor
enum CEEvent<C> {/// The cmd is ready for speculative executionSpecExeReady(Arc<LogEntry<C>>),/// The cmd is ready for after syncASReady(Arc<LogEntry<C>>),/// omit some code...
}/// CE task
struct Task<C: Command> {/// Corresponding vertex idvid: u64,/// Task typeinner: TaskType<C>,
}/// Task Type
enum TaskType<C: Command> {/// Execute a cmdSpecExe(Arc<LogEntry<C>>, Option<C::Error>),/// After sync a cmdAS(Arc<LogEntry<C>>, C::PR),/// omit some code...
}

从前面的描述中我们可以看出,Curp Server 的状态机引擎主要的事件可以分为两类,一类是 CEEvent,它描述了命令本身的信息,包括了命令的来源,其中 SpecExeReady 表明这个命令是来自于 fast path, 而 ASReadey 则表明这个命令来自于 slow path。而另一类则是 Task,它描述命令在依赖图中的顶点 id,以及当前命令所需要执行的操作。

Curp Server 的状态机引擎也定义了如下的状态:

/// Execute state of a cmd
enum ExeState {/// Is ready to executeExecuteReady,/// ExecutingExecuting,/// Has been executed, and the resultExecuted(bool),
}/// After sync state of a cmd
enum AsState<C: Command> {/// Not Synced yetNotSynced(Option<C::PR>),/// Is ready to do after syncAfterSyncReady(Option<C::PR>),/// Is doing after syncingAfterSyncing,/// Has been after syncedAfterSynced,
}

其中,ExeState 代表命令的执行状态,而 AsState 则代表了命令是否执行完了 after_sync 阶段。Curp Server 通过组合 ExeState 和 AsState 两种状态来代表命令执行过程中的不同状态。不同的状态所代表的语义如下:

  • (ExecuteReady, NotSynced(None): 代表命令已经可以准备执行execute 阶段,并且该命令属于 fast path,无需等待 after_sync 结束即可向用户返回结果。此状态也是 fast path 路径下,状态机引擎的初始状态。
  • (ExecuteReady,AfterSyncRead(None)): 代表命令已经可以准备执行 execute 阶段,并且该命令属于 slow path,需要等到after_sync结束才能向用户返回结果。此状态也是 slow path 路径下,状态机引擎的初始状态。
  • (Executeing,NotSynced(Some(C::PR))): 代表命令执行 pre_execute 成功,并拿到了 pre_execute 的执行结果 Some(C::PR), 同时命令也进入了执行状态。
  • (Executeing,NotSynced(None)):代表命令 pre_execute 执行失败
  • (Executed(true),NotSynced(Some(C::PR))): 代表命令执行成功
  • (Executed(false),NotSynced(None)): 代表 fast path 中的命令执行失败
  • (Executed(true),AfterSyncRead(LogIndex, Some(C::PR))): 代表命令执行完毕,开始准备执行 after_sync
  • (Executed(true),AfterSyncing):代表命令执行完毕,正在执行 after_sync 阶段
  • (Executed(true),AfterSynced): 代表命令执行成功,且 after_sync 也执行成功
  • (Executeing,AfterSyncReady(Some(C::PR))): 代表命令正在执行,并准备执行 after_sync 阶段
  • (Executeing,AfterSyncReady(None)):代表命令的 pre_execute 阶段失败
  • (Executed(false),AfterSyncReady(None)): 代表 slow path 中的命令执行失败。

    各种状态之间的转换关系如下:

05、Summary

在 Xline 中,不论是来自于 fast path 的命令,还是来自 slow path 的命令,这些命令最终都会在 leader 节点上得到执行。在这个过程当中,仅凭 spec_pool 来判断命令是否冲突是显然不够的。因为 spec_pool 只能判断新的命令是否与正在 execute 但还没有 after_sync 的命令冲突,但它不能起到动态维护命令冲突关系的作用。为了解决冲突关系的动态维护,我们引入了冲突检测队列,并通过冲突检测队列和 command worker 共同构造 Curp Server 的状态机引擎。通过 command worker 的执行,使得来自不同路径(fast path 和 slow path)的命令能够根据自身的状态,进行状态转移,并向用户返回相应的结果。

06、往期回顾

Xline 源码解读(一) —— 初识 CURP 协议

Xline 源码解读 (二)—— Lease 的机制与实现

Xline 源码解读(三) —— CURP Server 的实现

Xline是一个用于元数据管理的分布式KV存储。Xline项目以Rust语言写就,欢迎大家参与我们的开源项目!

GitHub链接:

https://github.com/xline-kv/Xline

Xline官网:www.xline.cloud
Xline Discord: 

https://discord.gg/XyFXGpSfvb

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/112571.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

利用Python爬虫获取某乎热榜

如今&#xff0c;某乎必须要登录才能查看相关话题内容&#xff0c;给我们的日常造成了极大的不便&#xff0c;今天我就教大家如何利用简单的代码&#xff0c;绕开登录限制。 准备工作 配置好python运行环境&#xff0c;推荐 pycharm。复制下面的源代码&#xff0c;运行&#x…

LNMP架构部署Discuz论坛系统

文章目录 LNMP架构&部署Discuz论坛系统部署LNMP架构环境前期准备安装Nginx安装mariadb安装php配置nginx 部署Discuz论坛系统下载Discuz论坛系统代码包部署Discuz论坛系统配置虚拟主机安装Discuz论坛访问站点尝试注册一个账号 LNMP架构&部署Discuz论坛系统 部署LNMP架构…

试着写几个opencv的程序

一、认识opencv OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一个开源计算机视觉库&#xff0c;旨在提供丰富的图像处理和计算机视觉功能&#xff0c;以帮助开发者构建视觉应用程序。OpenCV最初由英特尔开发&#xff0c;现在由社区维护和支持。它支持…

Day5力扣打卡

打卡记录 对角线上不同值的数量差&#xff08;矩阵对角线遍历 前缀和&#xff09; 链接 思路&#xff1a;由于任意行 i 与 列 j&#xff0c;满足对角线上 i j t 的关系&#xff0c;t 的范围为 [1 - n, m - 1]&#xff0c;设 s t n&#xff0c;可以得到 s的范围为 [1, n …

计算机网络学习笔记(四):网络层(待更新)

目录 4.1 IP地址、子网划分、合并超网 4.1.1 IP地址、子网掩码、网关 4.1.2 IP地址的编址方法1&#xff1a;IP地址分类&#xff08;A~E类地址、保留的IP地址&#xff09; 4.1.4 IP地址的编址方法2&#xff1a;子网划分&#xff08;等长、变长&#xff09; 4.1.5 IP地址的编…

Adobe 推出 Photoshop Elements 2024 新版

&#x1f989; AI新闻 &#x1f680; Adobe 推出 Photoshop Elements 2024 新版 摘要:Adobe 最新发布 Photoshop Elements 2024 版本,新增引入 AI 功能,提供匹配颜色、创建照片卷、一键选择照片天空或背景等新功能,界面也进行了优化更新。本次发布重点加强了 AI 支持,简化复杂…

打卡go学习第一天

8.1 下面展示一些 代码。 package mainimport ("fmt""net""os""time" )type Clock struct {Name stringAddr string &#xff5d; func main() {clocks : []Clock{{Name: "New York", Addr: "localhost:8000"…

spring cloud Eureka集群模式搭建(IDEA中运行)

spring cloud Eureka集群模式搭建&#xff08;IDEA中运行&#xff09; 新建springboot 工程工程整体目录配置文件IDEA中部署以jar包形式启动总结 新建springboot 工程 新建一个springboot 工程&#xff0c;命名为&#xff1a;eureka_server。 其中pom.xml文件为&#xff1a; …

OnlyOffice documentType类型值

参考官网说明&#xff1a; https://api.onlyoffice.com/editors/config/#documentType 其值为&#xff1a;word | cell | slide

SpringCloud: feign整合sentinel实现降级

一、加依赖&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache…

060:mapboxGL点击某处,通过flyTo,以动画的形式聚焦到此点

第060个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+mapbox中点击某处,通过flyto,以动画的形式聚焦到此点。这里用到了flyTo的方法,里面可以设置bearing,zoom,pitch等众多的属性内容。 直接复制下面的 vue+mapbox源代码,操作2分钟即可运行实现效果 文章目录 示…

RabbitMQ运行机制和通讯过程介绍

文章目录 1.RabbitMQ 环境搭建2.RabbitMQ简介3.RabbitMQ的优势&#xff1a;4. rabbitmq服务介绍4.1 rabbitmq关键词说明4.2 消息队列运行机制4.3 exchange类型 5.wireshark抓包查看RabbitMQ通讯过程 1.RabbitMQ 环境搭建 参考我的另一篇&#xff1a;RabbitMQ安装及使用教程&am…

SystemVerilog Assertions应用指南 Chapter1.20“ $past”构造

1.20“ $past”构造 SVA提供了一个内嵌的系统任务“$past”,它可以得到信号在几个时钟周期之前的值。在默认情况下,它提供信号在前一个时钟周期的值。结构的基本语法如下 $past (signal_name ,number of clock cycles) 这个任务能够有效地验证设计到达当前时钟周期的状态所采用…

购药不烦恼:线上购药小程序的快捷方式

在这个数字化时代&#xff0c;线上购药小程序的快捷方式正在改变着我们购药的方式。本文将介绍如何通过使用Python和Flask框架创建一个简单的线上购药小程序的原型&#xff0c;为用户提供购药的便利和快捷体验。 安装和设置 首先&#xff0c;确保你已经安装了Python和Flask。…

AUTOSAR AP 硬核知识点梳理(2)— 架构详解

一 AUTOSAR 平台逻辑体系结构 图示逻辑体系结构描述了平台是如何组成的,有哪些模块,模块之间的接口是如何工作的。 经典平台具有分层的软件体系结构。定义明确的抽象层,每个抽象层都有精确定义的角色和接口。 对于应用程序,我们需要考虑使用的软件组件,希望它们是可重用的…

墨迹天气商业版UTF-8模板,Discuz3.4灰白色风格(带教程)

1.版本支持&#xff1a;Discuzx3.4版本&#xff0c;Discuzx3.3版本&#xff0c;DiscuzX3.2版本。包括网站首页&#xff0c;论坛首页&#xff0c;论坛列表页&#xff0c;论坛内容页&#xff0c;论坛瀑布流,资讯列表页(支持多个)&#xff0c;产品列表页(支持多个)&#xff0c;关于…

微信小程序之首页-后台交互及WXS的使用

目录 前言 一. 前后台数据交互及封装request 1.准备后台 1.1 配置数据源 1.2 部分后台获取数据方法编写 2.准备前端 2.1封装Request 2.2 前端JS方法编写 2.3 前端页面展示index.wxml 二.WXS的使用 1.简介 2.WXS优化OA系统 2.1 使用及定义 2.2 导入要使用的项目 2.…

如何理解TCP/IP协议?

一、是什么 TCP/IP&#xff0c;传输控制协议/网际协议&#xff0c;是指能够在多个不同网络间实现信息传输的协议簇 TCP&#xff08;传输控制协议&#xff09; 一种面向连接的、可靠的、基于字节流的传输层通信协议 IP&#xff08;网际协议&#xff09; 用于封包交换数据网…

分类预测 | MATLAB实现基于BiGRU-AdaBoost双向门控循环单元结合AdaBoost多输入分类预测

分类预测 | MATLAB实现基于BiGRU-AdaBoost双向门控循环单元结合AdaBoost多输入分类预测 目录 分类预测 | MATLAB实现基于BiGRU-AdaBoost双向门控循环单元结合AdaBoost多输入分类预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 1.MATLAB实现基于BiGRU-AdaBoos…

nodejs+vue 校园通勤车-计算机毕业设计

在此情况下开发一款校园通勤车可视化系统小程序&#xff0c;于是乎变得非常合乎时宜。 经过网上调查和搜集数据,我们可以发现校园通勤车可视化管理方面的小程序在并不是相当普及,同时在校园通勤车可视化管理方面的可以有许多改进。目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪…