C-Raft¶
C-Raft is a fully asynchronous C implementation of the Raft consensus protocol.
Design¶
The library has modular design: its core part implements only the core Raft algorithm logic, in a fully platform independent way. On top of that, a pluggable interface defines the I/O implementation for networking and disk persistence.
A stock implementation of the I/O interface is provided when building the library with default options. It is based on libuv and should fit the vast majority of use cases.
Features¶
C-Raft implements all the basic features described in the Raft dissertation:
Leader election
Log replication
Log compaction
Membership changes
It also includes a few optional enhancements:
Optimistic pipelining to reduce log replication latency
Writing to leader’s disk in parallel
Automatic stepping down when the leader loses quorum
Leadership transfer extension
Non-voting servers
Quick start¶
Make sure that libuv is installed on your system, then run:
1 2 3 | autoreconf -i
./configure --enable-example
make
|
Then create a main.c
file with this simple test program that just runs a
single raft server and implements a basic state machine for incrementing a
counter:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | #include <raft.h>
#include <raft/uv.h>
static raft_id id = 12345;
static const char *address = "127.0.0.1:8080";
static const char *dir = "/tmp/raft-quick-start";
static struct uv_loop_s loop;
static struct raft_uv_transport transport;
static struct raft_io io;
static struct raft_fsm fsm;
static struct raft raft;
static struct raft_configuration conf;
static struct uv_timer_s timer;
static struct raft_apply apply;
static unsigned counter = 0;
static uint64_t command;
static int applyCommand(struct raft_fsm *fsm,
const struct raft_buffer *buf,
void **result) {
counter += *(uint64_t *)buf->base;
printf("counter: %u\n", counter);
return 0;
}
static void submitCommand(uv_timer_t *timer) {
struct raft_buffer buf;
command = uv_now(timer->loop) % 10;
buf.len = sizeof command;
buf.base = &command;
raft_apply(&raft, &apply, &buf, 1, NULL);
}
int main() {
mkdir(dir, 0755);
uv_loop_init(&loop);
raft_uv_tcp_init(&transport, &loop);
raft_uv_init(&io, &loop, dir, &transport);
fsm.apply = applyCommand;
raft_init(&raft, &io, &fsm, id, address);
raft_configuration_init(&conf);
raft_configuration_add(&conf, id, address, RAFT_VOTER);
raft_bootstrap(&raft, &conf);
raft_start(&raft);
uv_timer_init(&loop, &timer);
uv_timer_start(&timer, submitCommand, 0, 1000);
uv_run(&loop, UV_RUN_DEFAULT);
}
|
You can compile and run it with:
1 | cc main.c -o main -lraft -luv && ./main
|