Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/canonical/raft
Unmaintained C implementation of the Raft consensus protocol
https://github.com/canonical/raft
Last synced: 3 months ago
JSON representation
Unmaintained C implementation of the Raft consensus protocol
- Host: GitHub
- URL: https://github.com/canonical/raft
- Owner: canonical
- License: other
- Archived: true
- Created: 2018-10-29T16:20:28.000Z (about 6 years ago)
- Default Branch: master
- Last Pushed: 2024-03-04T14:52:15.000Z (8 months ago)
- Last Synced: 2024-04-10T05:28:35.833Z (7 months ago)
- Language: C
- Homepage:
- Size: 3.71 MB
- Stars: 932
- Watchers: 32
- Forks: 136
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Authors: AUTHORS
Awesome Lists containing this project
README
This project is unmaintained
============================[English](./README.md)|[简体中文](./README_CH.md)
The dqlite team is no longer maintaining our raft implementation as an
independent project. Instead, the raft source code has been incorporated into
[canonical/dqlite](https://github.com/canonical/dqlite) as a private
implementation detail. v0.18.1 is the last release of dqlite's libraft. We
regret any inconvenience caused by this change.If you depend on dqlite but not on raft directly, see
[canonical/dqlite](https://github.com/canonical/dqlite) for up-to-date
instructions on how to use dqlite's bundled raft build configuration. If you
formerly depended on dqlite's libraft, you should switch to the maintained fork
[cowsql/raft](https://github.com/cowsql/raft).[A discussion thread](https://github.com/canonical/dqlite/discussions/620) is
open on the dqlite repository for any questions about this change.The remainder of this README is of historical interest only.
-----
Fully asynchronous C implementation of the Raft consensus protocol.
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 (send/receive
RPC messages) and disk persistence (store log entries and snapshots).A stock implementation of the I/O interface is provided when building the
library with default options. It is based on [libuv](http://libuv.org) and
should fit the vast majority of use cases. The only catch is that it currently
requires Linux, since it uses the Linux
[AIO](http://man7.org/linux/man-pages/man2/io_submit.2.html) API for disk
I/O. Patches are welcome to add support for more platforms.See [raft.h](https://github.com/canonical/raft/blob/master/include/raft.h) for full documentation.
License
-------This raft C library is released under a slightly modified version of LGPLv3,
that includes a copyright exception letting users to statically link the library
code in their project and release the final work under their own terms. See the
full [license](LICENSE) text.Features
--------This implementation includes all the basic features described in the Raft
dissertation:- Leader election
- Log replication
- Log compaction
- Membership changesIt 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
- Pre-vote protocolInstall
-------If you are on a Debian-based system, you can get the latest development release from
dqlite's [dev PPA](https://launchpad.net/~dqlite/+archive/ubuntu/dev):```
sudo add-apt-repository ppa:dqlite/dev
sudo apt-get update
sudo apt-get install libraft-dev
```Building
--------To build ``libraft`` from source you'll need:
* A reasonably recent version of [libuv](https://libuv.org/) (v1.18.0 or beyond).
* Optionally, but recommended, a reasonably recent version of [liblz4](https://lz4.github.io/lz4/) (v1.7.1 or beyond).```bash
sudo apt-get install libuv1-dev liblz4-dev libtool pkg-config build-essential
autoreconf -i
./configure --enable-example
make
```Example
-------The best way to understand how to use the library is probably reading the code
of the [example server](https://github.com/canonical/raft/blob/master/example/server.c)
included in the source code.You can also see the example server in action by running:
```bash
./example/cluster
```which spawns a little cluster of 3 servers, runs a sample workload, and randomly
stops and restarts a server from time to time.Quick guide
-----------It is recommended that you read
[raft.h](https://github.com/canonical/raft/blob/master/include/raft.h) for
documentation details, but here's a quick high-level guide of what you'll need
to do (error handling is omitted for brevity).Create an instance of the stock ```raft_io``` interface implementation (or
implement your own one if the one that comes with the library really does not
fit):```C
const char *dir = "/your/raft/data";
struct uv_loop_s loop;
struct raft_uv_transport transport;
struct raft_io io;
uv_loop_init(&loop);
raft_uv_tcp_init(&transport, &loop);
raft_uv_init(&io, &loop, dir, &transport);
```Define your application Raft FSM, implementing the ```raft_fsm``` interface:
```C
struct raft_fsm
{
void *data;
int (*apply)(struct raft_fsm *fsm, const struct raft_buffer *buf, void **result);
int (*snapshot)(struct raft_fsm *fsm, struct raft_buffer *bufs[], unsigned *n_bufs);
int (*restore)(struct raft_fsm *fsm, struct raft_buffer *buf);
}
```Pick a unique ID and address for each server and initialize the raft object:
```C
unsigned id = 1;
const char *address = "192.168.1.1:9999";
struct raft raft;
raft_init(&raft, &io, &fsm, id, address);
```If it's the first time you start the cluster, create a configuration object
containing each server that should be present in the cluster (typically just
one, since you can grow your cluster at a later point using ```raft_add``` and
```raft_promote```) and bootstrap:```C
struct raft_configuration configuration;
raft_configuration_init(&configuration);
raft_configuration_add(&configuration, 1, "192.168.1.1:9999", true);
raft_bootstrap(&raft, &configuration);
```Start the raft server:
```C
raft_start(&raft);
uv_run(&loop, UV_RUN_DEFAULT);
```Asynchronously submit requests to apply new commands to your application FSM:
```C
static void apply_callback(struct raft_apply *req, int status, void *result) {
/* ... */
}struct raft_apply req;
struct raft_buffer buf;
buf.len = ...; /* The length of your FSM entry data */
buf.base = ...; /* Your FSM entry data */
raft_apply(&raft, &req, &buf, 1, apply_callback);
```To add more servers to the cluster use the ```raft_add()``` and
```raft_promote``` APIs.Usage Notes
-----------The default [libuv](http://libuv.org) based ```raft_io``` implementation compresses the raft
snapshots using the ```liblz4``` library. Next to saving disk space, the lz4
compressed snapshots offer additional data integrity checks in the form of a
[Content Checksum](https://github.com/lz4/lz4/blob/dev/doc/lz4_Frame_format.md), this allows raft
to detect corruptions that occurred during storage. It is therefore recommended to not disable
lz4 compression by means of the ```--disable-lz4``` configure flag.Detailed tracing will be enabled when the environment variable `LIBRAFT_TRACE` is set upon startup.
The value of it can be in `[0..5]` range and reperesents a tracing level, where
`0` means "no traces" emitted, `5` enables minimum (FATAL records only), and `1`
enables maximum verbosity (all: DEBUG, INFO, WARN, ERROR, FATAL records).Notable users
-------------- [dqlite](https://github.com/canonical/dqlite)
Credits
-------Of course the biggest thanks goes to Diego Ongaro :) (the original author of the
Raft dissertation).A lot of ideas and inspiration was taken from other Raft implementations such
as:- CoreOS' Go implementation for [etcd](https://github.com/etcd-io/etcd/tree/master/raft)
- Hashicorp's Go [raft](https://github.com/hashicorp/raft)
- Willem's [C implementation](https://github.com/willemt/raft)
- LogCabin's [C++ implementation](https://github.com/logcabin/logcabin)