MIT Licensed
No CLAs
100% Community Guided
New Contributor Friendly
Questions Welcome
(Even during the talk!)
☹ (Currently) Nightly Only & Not on Crates.io
Friends of the Tree
@danburkert, @james-darkfox, @tschottdorf
@ongardie, @carllerche, @dwrensha,
#rust@irc.mozilla.org
The Big Picture
History
- 1st prototype developed for a Distributed Systems class at the University of Victoria. ~v0.9 nightly Rust.
- Weekly(ish) breaking changes, fun!
- Very naive, simple implementation on (mostly) stdlib.
A few finals later...
- Numerous libraries discovered or emerged during development.
- People started coding with me! WOW.
- 2nd prototype planned using emerging ecosystem to solve problems that existed.
- Crafted over time, without a hard deadline, resulting in better decisions and code.
- Mostly functional today, and getting better daily!
Goals
- Fast
- Unopinionated
- Correct
- General Purpose
Non-Goals
- Library/Idiom dictation
- Lock-in
Not just a key/value store! Build what you need.
Raft-rs represents more of an RPC and replication framework than a database or cache.
- Powerful asynchronous event loop.
- Enables single-threaded design.
- Interesting and Low Level.
- Way more fun than Node!
- ☹ Poor Windows support
- Fast Cerealization Protocol.
- No serialize/deserialize.
- Messages represent wire format.
- Cross platform schemas.
- ☹ Poor async support
(Dan forked it to add async! Improvements here soon!)
- Automated testing.
- Uses @huonw's Travis-Cargo app!
- Documentation updates via Github Pages.
- Test Coverage via Coveralls.
- It's bors!
- Keeps master green.
- Encourages code review.
How It All Connects
Built
For You
Client
- Provides all communication between program and the cluster.
- Clients can be inside or outside of the cluster.
- Calls block until it is appropriate to respond.
- Design your own interactions with the state machine!
A Simple API
// Create a Client associated with a cluster.
let mut client = raft::Client::new(cluster);
// Passes through durable log, is committed, may mutate state machine.
let prop_res = client.propose(msg);
// Immutable access to state machine.
let query_res = client.query(msg);
Server
- Acts as a MIO reactor.
- Virtually all networking and messaging code.
- Buffers incoming messages and dispatches to associated Consensus Module.
- Acts appropriately based on Actions returned by the module.
- No Raft algorithm specific logic.
A(nother) Simple API
// Spawn a server. This will block the current thread as long as it's running.
Server::run(id, addr, peers, persistent_log, state_machine).unwrap();
Consensus
- Contains all code related to the core Raft Algorithm.
- Zero networking or filesystem code. (Easy testing!)
- Handles elections, replication, committing, etc.
- Exclusive interfaces to the State Machine and Log.
- Hands Actions back to the Server.
Doing It Yourself
Persistent Log
-
Represents the replicated, persistent log of your application.
-
Has a strong ordering such that A → B → C and should only act to store information.
-
Entries placed into the log should not be acted on by the consuming application.
-
Generally not application specific.
-
Help us make some cool ones?
-
- Warning: API is not set in stone. Expect improvements!
Persistent Log API
/// Returns the latest known term.
fn current_term(&self) -> result::Result<Term, Self::Error>;
/// Sets the current term to the provided value. The provided term must be greater than
/// the current term. The `voted_for` value will be reset`.
fn set_current_term(&mut self, term: Term) -> result::Result<(), Self::Error>;
/// Increment the current term. The `voted_for` value will be reset.
fn inc_current_term(&mut self) -> result::Result<Term, Self::Error>;
/// Returns the candidate id of the candidate voted for in the current term (or none).
fn voted_for(&self) -> result::Result<Option<ServerId>, Self::Error>;
/// Sets the candidate id voted for in the current term.
fn set_voted_for(&mut self, server: ServerId) -> result::Result<(), Self::Error>;
/// Returns the index of the latest persisted log entry (0 if the log is empty).
fn latest_log_index(&self) -> result::Result<LogIndex, Self::Error>;
/// Returns the term of the latest persisted log entry (0 if the log is empty).
fn latest_log_term(&self) -> result::Result<Term, Self::Error>;
/// Returns the entry at the provided log index.
fn entry(&self, index: LogIndex) -> result::Result<(Term, &[u8]), Self::Error>;
/// Appends the provided entries to the log beginning at the given index.
fn append_entries(&mut self, from: LogIndex, entries: &[(Term, &[u8])]) -> result::Result<(), Self::Error>;
State Machine
- Represents the replicated state of the cluster.
- Consistent across all nodes.
- Is not mutated without going through Raft.
- Responsible for triggering log compaction.
- (We've yet to do this!)
- Warning: API is not set in stone. Expect improvements!
/// Applies a command to the state machine.
/// Returns an application-specific result value.
fn apply(&mut self, command: &[u8]) -> Vec<u8>;
/// Queries a value of the state machine. Does not go through the durable log, or mutate the
/// state machine.
/// Returns an application-specific result value.
fn query(&self, query: &[u8]) -> Vec<u8>;
/// Take a snapshot of the state machine.
fn snapshot(&self) -> Vec<u8>;
/// Restore a snapshot of the state machine.
fn restore_snapshot(&mut self, snapshot: Vec<u8>) -> ();
State Machine API
Building
_______
Together
Road to 1.0
- Membership Changes
- Log Compaction
- Snapshotting
- Testing of common failure situations
- Client Robustness
Future Fun
- Verified communication
- C Bindings
- New libraries to use
- Intensive failure testing
1.0 should represent a full implementation of Diego's Paper.
Get Involved
Help us:
- Define it!
- Abstract it!
- Test it!
- Break it!
- Fix it!
- Build off of it!
Find us on:
Raft-rs
By hoverbear
Raft-rs
A maturing Rust implementation of Raft.
- 1,936