Raft in Rust (原子多播+撮合引擎)

前言

Raft作为一个分布式协同算法,这是原子多播的一个非常重要的视线。今天也得到了广泛的应用。当前情况下,我们为了更好的实现一个快速的撮合引擎,我们进一步探索原子多播在交易系统中的应用。Rust是现代编译执行语言的代表,可以达到可以比肩C语言的执行效率。所以,我们必然要考虑如何在Rust里面应用Raft协议。

对于Raft的算法详解,csdn已经有很多文章,推荐大家看一下:

raft-zh_cn/raft-zh_cn.md at master · maemual/raft-zh_cn · GitHub
 

可资借鉴的项目

tikv/raft-rs 

https://github.com/tikv/raft-rshttps://github.com/tikv/raft-rsraft-rs/examples at master · tikv/raft-rs · GitHub

​​​​​​https://crates.io/crates/raft

raft - Rust

tikv/raft-engine 

https://github.com/tikv/raft-enginehttps://github.com/tikv/raft-engine

openraft 

GitHub - datafuselabs/openraft: rust raft with improvementsrust raft with improvements. Contribute to datafuselabs/openraft development by creating an account on GitHub.https://github.com/datafuselabs/openraft这个项目是 https://github.com/async-raft/async-raft 这个项目的分支,但是async-raft已经停止更新了,async-raft原作者也在openraft项目上有一些代码提交。虽然async-raft有更多的历史下载量,但是我们后续还是需要使用 OpenRaft。

这个项目还是非常活跃的,比之前的async-raft感觉提升了很多。下面这个例子我们还是值得学习。 

https://github.com/datafuselabs/openraft/tree/main/example-raft-kv

现在看起来这个项目的质量还是相当的高。

databend

GitHub - datafuselabs/databend: A modern Elasticity and Performance cloud data warehouse, activate your object storage for real-time analytics.A modern Elasticity and Performance cloud data warehouse, activate your object storage for real-time analytics. - GitHub - datafuselabs/databend: A modern Elasticity and Performance cloud data warehouse, activate your object storage for real-time analytics.https://github.com/datafuselabs/databenddatabend项目本身有基于openraft的metastore。而这个metastore是试用了持久化的方式存储数据。所以这对我们来说有很大的借鉴价值。

我们非常高兴有幸获得了Databend社区的帮助来了解 openraft 和metasrv的一些实现。也得知 openraft 在SAP里担任了非常重要的角色。所以,我们也替Databend社区高兴。和他们的沟通一直是愉快的。

Databend负责社区的吴总待人很好,他的联系方式:WeChat ID: River_wubx 有空约饭局。

commitlog

GitHub - zowens/commitlog: Append-only commit log library for RustAppend-only commit log library for Rust. Contribute to zowens/commitlog development by creating an account on GitHub.https://github.com/zowens/commitlog这个库可以看看能不能帮忙做eventlog

sled

https://github.com/spacejam/sledhttps://github.com/spacejam/sled在openraft项目文档里,推荐使用 rocksdb 做日志存储。但是呢,由于 rocksdb 已经长期没有更新,所以我们有很大可能性需要考虑使用sled作为替代方案。我们需要在commitlog和sled中间做出选择。

darksteel

这个项目是我们实验项目的一个基础。非常好的演示了如何使用openraft。 中间的子项目 darksteel-codegen为了通过宏处理,简化raft协议开发。有很好的借鉴价值。

https://github.com/darksteel-rs/darksteelhttps://github.com/darksteel-rs/darksteel

设计原则

MySQL

大家在使用mysql的时候,一定了解mysql binlog的实现和mysql snapshot相互配合进行数据复制和同步的机制。这种机制在mysql的实现上是单机的。

snapshot + binlog 通过落盘的方式对数据进行持久化。这样我们从任何一个binlog的事务点都能向后恢复数据。snapshot全量数据,binlog是增量数据。在实际的应用中,增量在实际的应用中,同步起来确实是比每次同步全量数据要方便的多。

而MySQL的数据同步大量还是通过主从来实现。这样在主库出现问题的时候,切换从库为主库还是有可能出现数据不一致的问题。

TiDB

TiDB本身使用了Raft进行数据库之间的共识算法。在HA上对MySQL是一个促进。

MySQL + Raft

阿里云RDS的MySQL三节点,基于Raft和semi sync实现,容量最高可达3TB。不想入分布式数据库坑的同学们可以关注。下面是相关的原理介绍。

How To Make MySQL Work With Raft - ppt downloadAbout Me Lixun Peng Location Hangzhou, China Occupation Staff Database Engineer at Alibaba Cloud Oracle ACE Director (for MySQL)https://slideplayer.com/slide/14273652/

撮合引擎

而撮合引擎的设计往往把订单簿作为snapshot, 订单簿里包含的都是用户的有效订单。而binlog里面存在的就是对订单的命令。通过订单指令,推动订单簿作为状态机进行状态变化。由于撮合引擎的算法是确定性算法(输入固定的情况下,输出一定相同)。

Raft协议,作为原子多播协议,是为了保证在多活实例中,每个撮合系统都能够得到一个相同顺序,相同内容的订单指令来推动状态机。这样,Raft协议就可以帮助多机热备的撮合引擎之间制造相同的输入流。

所以,通过Raft来实现分布式高可用,性能优越的撮合引擎,自然是我们可以考虑的方向。

实验项目

基于对openraft项目文档的认真阅读分析。我们基本上可以知道如何使用openraft实现一个原子多播系统。而DarkSteel的帮助是让我们比较简化对状态机和命令的定义。

我们在此基础上加入了OrderBook的Rust实现。希望能逐步完成下面的项目:

matchengine-rs: 原子多播是实现交易引擎的一种非常重要的方式。这是一个实验项目。准备使用async-raft实现一个集群化的撮合引擎。项目现在还在进展中。https://gitee.com/raymondshen/matchengine-rs

希望大家能够参与讨论。

实现RaftStorage

RaftStorage在 openraft 项目里面有两个参考实现。所以我们可以借鉴:

https://github.com/datafuselabs/openraft/tree/main/memstore

memstore实现了一个内存存储模块。说明了如何实现,并且测试一个RaftStorage模块。

​​​​​​https://github.com/datafuselabs/openraft/tree/main/example-raft-kv

raft-kv也是实现了一个内存存储模块来保存key value,功能上可能稍微又些增强,但是基本上还是不涉及持久化。

RaftStorage在 databend metasrv中有更加深入的应用。

​​​​​​https://github.com/datafuselabs/databend/tree/main/metasrv/src/store

这里有一个相对复杂的使用sled进行日志存储的实现。可以值得我们借鉴。当然 RaftStorage主要是实现对订单命令的落盘。在一定程度上,是顺序处理的。我们使用 commitlog 也是一种比较快的实现方式。

实现RaftNetwork

<TBD >

实现OrderBook

在databend/metasrv里面,StateMachine 的实现是使用了SledTree来操作 Sled数据库完成的。所以,基本上对于已经确认的Log。StateMachine是直接写Sled进行落盘的。对于内存化撮合来讲,OrderBook的操作时尽量需要在内存中存储。定期本地化 SnapShot 来实现。

对OrderBook的还原还是通过对SnapShot的加载,然后对后续的 Log 进行回放。当最后一个 Log被回放完成。我们也就把OrderBook恢复到了停机前的最新版。

OrderBook的落盘实际上我们可以考虑在 RaftStorage::purge_logs_upto 函数里面实现。

当然OrderBook的Snapshot可以通过文件方式存储。这样以来文件系统的方式应该是最为可靠快捷的方式。

需要存储多少个Snapshot,并且我们需要格多少个Log才存储一次Snapshot。这完全可以由配置来决定。

实现管理工具

<TBD>

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值