
What's this?
In another repository Iris, a very simple Raft tool library is written based on the original Raft paper and using actix-web.
The tool library includes the following parts:
- Follower, Leader and Candidate node state machines
- Term, log index
AppendEntriesRPC,VoteRequestRPC- Heartbeat packet mechanism, timeout election, random election timeout and election timeout
Unimplemented parts:
- Log consistency check process
- High consistency (to be precise, the log replication process before the node joins the cluster)
- Two-stage method required to solve the cluster split problem
- Log compression
In this tool library, only keys and values of type String can be stored with fixed logic, because the internal data storage uses Map<String, String>. Obviously, this is a huge flaw, which means redundant serialization and deserialization steps. Considering Rust's ownership mechanism, there will be additional clones. And because the logic is fixed, it is also difficult to implement the extended functions of ordinary kv storage (such as automatic expiration, automatic disk backup, shard storage, etc.) in every application using the tool library.
Usage
According to the original paper, it is divided into the following parts:
- Timer (heartbeat packet mechanism, timeout mechanism, random election timeout and election timeout mechanism)
- Network (including RPC, serialization and deserialization, and data packet processing according to the state machine)
- Internal storage
- Disk persistence
In order to achieve the best possible performance and concurrency safety, the Actor mode is first considered to encapsulate the operations.
Taking storing a Log Entry as an example, the specific method is as follows:
-
Define basic data types
The basic data type here refers to the data that the
Log Entrywill carry in the entire implementation. For example, the basic data type in the Iris implementation isString.In addition, for the sake of implementation completeness, we also need to define an
Errortype to express as accurately as possible the errors that may occur during data processing. -
Implement a
SaveLogstructure and implementactix::MessageDoes this look a bit strange? Actually, this
SaveLogacts as a function, declaring the parameters that will be passed toActor(term: u64, index: u64, data: T) and the return value (type Result = Result<(), E>;).As for
std::marker::PhantomData<E>, sinceEis not used as a field in the structure, it will generate unbounded lifetime. So we need to use a placeholder tool so that it can be declared in the structure but cannot generate real memory consumption, PhantomData is very suitable. -
Define an "aggregate" feature, provide it to users to implement and pass it into the implementation through an interface.
At this point, we have provided a "function" for users to process and save
Log Entry. The usage is as follows:
References and Acknowledgements
In Search of an Understandable Consensus Algorithm Original Raft paper
A rigorous and scalable implementation of actix-raft
raft-rs is a high-performance and easy-to-understand implementation
Thanks!