• Stars
    star
    135
  • Rank 260,728 (Top 6 %)
  • Language
    JavaScript
  • Created over 9 years ago
  • Updated about 8 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Raft implementation in Node.js

Skiff

Build Status ![Dependencies] (https://david-dm.org/pgte/skiff-algorithm.png) ![Gitter](https://badges.gitter.im/Join Chat.svg)

Abstract Node.js implementation of the Raft Consensus Algorithm.

If you're looking for a directly usable module, take a look at skiff (on top of LevelDB + Msgpack).

Contents:

Install

$ node install skiff --save

Require

var Node = require('skiff');

Create a node

var node = Node();

or, with options:

var options = {
  // ...
};
var node = Node(options);

Node create options

  • id: id of the node. if not defined, it's self assigned. accessible on node.id
  • standby: if true, will start at the standby state instead of the follower state. In the standby state the node only waits for a leader to send commands. Defaults to false.
  • cluster: the id of the cluster this node will be a part of
  • transport: the transport to communicate with peers. See the transport API
  • persistence: the node persistence layer. See the persistence API
  • uuid: function that generates a UUID. Defaults to using the cuid package.
  • heartbeatInterval: the interval between heartbeats sent from leader. defaults to 50 ms.
  • minElectionTimeout: the minimum election timeout. defaults to 150 ms.
  • maxElectionTimeout: the maximum election timeout. defaults to 300 ms.
  • commandTimeout: the maximum amount of time you're willing to wait for a command to propagate. Defaults to 3 seconds. You can override this in each command call.
  • retainedLogEntries: the maximum number of log entries that are committed to the state machine that should remain in memory. Defaults to 50.
  • metadata: to be used by plugins if necessary

Node API

.listen(options, listener)

Makes the peer listen for peer communications. Takes the following arguments:

  • options - connection options, depends on the transport provider being used.
  • listener - a function with the following signature: function (peerId, connection). The arguments for the listener function are:
    • peerId - the identification of the peer
    • connection - a connection with the peer, an object implementing the Connection API (see below).

.join(peer, [peerMetadata], cb)

Joins a peer into the cluster.

node.join(peer, cb);

The peer is a string describing the peer. The description depends on the transport you're using.

.leave(peer, cb)

Removes a peer from the cluster,

node.leave(peer, cb);

The peer is a string describing the peer. The description depends on the transport you're using.

.command(command[, options], callback)

Appends a command to the leader log. If node is not the leader, callback gets invoked with an error. Example:

node.command('some command', function(err) {
  if (err) {
    if (err.code == 'ENOTLEADER') {
       // redirect client to err.leader
    }
  } else {
    console.log('cluster agreed on this command');
  }
});

This command times out after the options.commandTimeout passes by, but you can override this by passing in some options:

node.command('some command', {timeout: 5000}, function(err) {
  if (err) {
    if (err.code == 'ENOTLEADER') {
       // redirect client to err.leader
    }
  } else {
    console.log('cluster agreed on this command');
  }
});

Command options are:

  • timeout: maximum time waiting to replicate to a majority. Defaults to node options.commandTimeout, which defaults to to 3000 (3 seconds).
  • waitForNode: node id to wait to commit to. This may be useful to enforce read-your-writes on proxying clients. Defaults to undefined.

.peerMeta(url)

Returns the peer metadata if the peer is known.

Events

A node emits the following events that may or not be interesting to you:

  • error(error) - when an unexpected error occurs.
  • state(stateName) - when a new state transition occurs. Possible values for stateName are: idle, follower, candidate, leader.
  • loaded() - when a node has loaded configuration from persistence provider.
  • election timeout() - when an election timeout occurs.
  • applied log(logIndex) - when a node applies a log entry to the state machine

Plugins

Skiff if failry high-level and doesn't implement the network transport or the persistence layers. Instead, you have to provide an implementation for these.

Transport provider API

The node transport option accepts a provider object that implements the following interface:

  • connect(localNodeId, options) — for connecting to the peer. returns a connection object. The localNodeId argument contains the local node id.
  • listen(localNodeId, options, fn) — for listening to incoming connection requests. The fn argument is a function with the signaure function (peerId, connection) that gets invoked when there is a connection request, passing in a connection object that implements the Connection API (see below). The localNodeId argument contains the local node id.

Connection API

The connection API implements the following interface:

  • send(type, arguments, callback) — for making a remote call into the peer. The callback argument is a function with the signature function (err, result).
  • receive(fn) — listen for messages from the remote peer. The fn argument is a function with the signature function (type, args, cb). cb is a function that accepts the reply arguments.
  • close(callback) — for closing the connection. The callback argument is a function with the signature function (err).

The connection object is an EventEmitter, emitting the following events:

  • close - once the connection closes

Persistence provider API

The node persistence option accepts a provider object that implements the following interface:

  • saveMeta(nodeId, state, callback) — saves the raft engine metadata. nodeId is a string that represents the current node. state is an arbitrary object (hash map) and callback is a function with the signature function callback(err);
  • loadMeta(nodeId, callback) — loads the engine metadata state. callback is a function with the signature function callback(err, state);
  • applyCommand(nodeId, commitIndex, command, callback) - applies a command to the node state machine.
    • Persistence layer should save the commitIndex if it wants to make sure that log entries are not repeated.
    • Saving this should be atomic: the commitIndex and the log application to the state machine should be successful or fail entirely.
    • If the commitIndex has already been applied in the past, just callback with success. callback is a function with the following signature: function callback(err).
  • lastAppliedCommitIndex(nodeId, callback) - returns the last commitIndex that was successfully applied to the node state machine.
    • is asynchronous: callback is a function invoked once the result is ready
    • callback is a function with the following signature: function(err, commitIndex) - if operation resulted in error, err contains an error object. Otherwise, commitIndex may contain an integer with the index of the latest applied commitIndex if there was one.
  • saveCommitIndex(nodeId, commitIndex, callback) - saves only the commit index
  • createReadStream(nodeId) - returns a read stream that streams all the state machine data.
  • createWriteStream(nodeId) - resets the state machine and returns a write stream to overwrite all the state machine data.
  • removeAllState(nodeId, callback) - remove all state for the given node

Cluster Setup

Setting up a Skiff cluster can be kind of tricky. To avoid partitions you will need to start with a node that will become leader and then add the followers in the standby mode. Mind you that you can only send join commands to a leader node (to avoid partitions — it's all explained in detail in the Raft paper). Once this is done and persisted you should never need to do this again since the nodes will know each other and elect a leader at random if leader goes down.

So typically the bootstrap code for the leader would be something like:

var Node = require('skiff');
var leader = Node({
  transport: transport,
  persistence: persistence
});

leader.listen(address);

/// wait for the leader node to actually become a leader of it's one node
leader.once('leader', function() {
  leader.join('node1');
  leader.join('node2');
});

leader.on('joined', function(peer) {
  console.log('leader joined %s', peer.id);
});

The follower bootstrapping code would look something like this:

var Node = require('skiff');
var node = Node({
  transport: transport,
  persistence: persistence,
  standby: true // important
});

node.listen(address);

This makes the follower start in the standby mode.

As mentioned, once the cluster enters stationary mode you just need to bootstrap all the nodes in the same way:

var Node = require('skiff');
var node = Node({
  transport: transport,
  persistence: persistence,
});

node.listen(address);

License

ISC

© Pedro Teixeira

More Repositories

1

fugue

Unicorn for node.js
JavaScript
397
star
2

alfred

Node is your mansion, Alfred is your butler. Node.js key-value store
JavaScript
149
star
3

carrier

Evented stream line reader for node.js
JavaScript
127
star
4

konphyg

Cascading configuration files made easy in Node.js.
JavaScript
105
star
5

level-jobs

Job Queue in LevelDB
JavaScript
84
star
6

node-openni

OpenNI bindings for Node.js
C++
79
star
7

simple-redis-safe-work-queue

Node.js Redis-based simple and safe work queue
JavaScript
77
star
8

handson_nodejs_source_code

Source code for the Hands-on Node.js book
JavaScript
74
star
9

banzai

Document processing framework for Node
JavaScript
69
star
10

node-patterns-code

Code for the Node Patterns Book Series
JavaScript
66
star
11

moving-average

Moving Average
JavaScript
60
star
12

node-openni-browser

Kinect on the browser
JavaScript
34
star
13

pipeline

Build stream pipe chains
JavaScript
21
star
14

procmon

Process Monitor UI
JavaScript
20
star
15

styled_objects

Simplify and organize stylesheet development on your Rails project
Ruby
17
star
16

dribbledb

MVCC database written in javascript
JavaScript
17
star
17

nodetuts_26

Node Tuts episode 26
JavaScript
17
star
18

pouch-stream-server

PouchDB Remote Server Stream
JavaScript
16
star
19

sweepy

Distributed and scalable file cache expiration in Rails
Ruby
14
star
20

level-vectorclock

Vector Clocks in LevelDB
JavaScript
14
star
21

duplex-emitter

Turns a duplex streams into an event emitter.
JavaScript
14
star
22

flowbench

HTTP traffic generator. Supports user flows with alternative paths. Stores stats on latency.
JavaScript
14
star
23

acts_as_pingable

Rails plugin for remote HTTP pinging
Ruby
13
star
24

node_tuts_episode_13

Node Tuts episode 13
JavaScript
11
star
25

verbose

Remote peer-to-peer event synchronization
JavaScript
9
star
26

cyclops

Controlling remote browser session with a pure javascript solution
JavaScript
8
star
27

pipe-channels

Channels as streams inside a stream, negotiated.
JavaScript
8
star
28

woosh

Streaming composable templates - IN CONSTRUCTION
JavaScript
8
star
29

nodetuts_code

Some code for the nodetuts screencasts
JavaScript
8
star
30

ipfs-iiif-db-demo

IPFS IIIF DB Demo
JavaScript
7
star
31

async-function-queue

async functionqueue for Node.js and Browser
JavaScript
6
star
32

banzai-redis

Redis queueing plugin module for Banzai
JavaScript
6
star
33

level-writestream

LevelUP writable stream compatible with streams2
JavaScript
6
star
34

nodetuts_website

Nodetuts website
Ruby
6
star
35

js-sparse-array

Sparse array implementation in JS with no dependencies
JavaScript
5
star
36

node-workshop

Node Workshop
JavaScript
5
star
37

fake-queue

Simple in-memory queue for Node.js
JavaScript
5
star
38

bubble

Domains for the poor man
JavaScript
5
star
39

requirelx-201506-reusable-node-streams

Presentation
JavaScript
5
star
40

sombrero

Dynamo-like Data Storage System for Node.js Using LevelDB
JavaScript
5
star
41

flutter-dp3t

Exposes the DP3T SDK API in Flutter
Kotlin
4
star
42

skiff-level

LevelDB persistence provider for Skiff
JavaScript
3
star
43

banzai-couchdb-store

CouchDB Doc Store for Banzai
JavaScript
3
star
44

presentation-2018-04-17-CRDTs

Madeira JS Meetup presentation about CRDTs
JavaScript
3
star
45

frequency-meter

Measures event frequency
3
star
46

nubstep

JavaScript
3
star
47

abstract-skiff-transport

Abstract Transport Layer for Skiff
JavaScript
2
star
48

banzai-statestore-mem

Banzai state store in memory
JavaScript
2
star
49

node-procmon-agent

Procmon Agent for Node.js
JavaScript
2
star
50

websockets-modular-approach-article-code

JavaScript
2
star
51

node-trumpet

parse and transform streaming html using css selectors
JavaScript
2
star
52

rpc-stream-article-code

2
star
53

boxed-emitter

Scoped events
JavaScript
2
star
54

nodetuts

Nodetuts.com
JavaScript
2
star
55

mozfest-decentralized-editor

Editor for Mozfest decentralised workshop
JavaScript
2
star
56

y-ipfs-store

Yjs store over IPFS
JavaScript
2
star
57

nodetuts_ep12

Node Tuts episode 12
JavaScript
2
star
58

opti.pt

OPTi.pt app
JavaScript
1
star
59

skroll

Framework for class trainings.
JavaScript
1
star
60

node-binary-querystring

node-binary-querystring
JavaScript
1
star
61

document-driven-transactions-presentation

Document-driven Transactions presentation
1
star
62

node_js_deep_dive_presentation

Slides for my "node.js - a deep dive" presentation
1
star
63

nodeinteractive-europe-2016-presentation

1
star
64

switch-emitter

Events with recipient address.
JavaScript
1
star
65

level-net-client

Node.js client for level-net-server
1
star
66

domain-observer

Observe events happening inside a domain
JavaScript
1
star
67

batch-write-stream

Batch Object Write Stream
JavaScript
1
star
68

The-process-module

1
star
69

y-ipfs-poc

Y.js over IPFS PoC
JavaScript
1
star
70

node-buzzard

Buzzard Protocol
JavaScript
1
star
71

middle

Combining two streams
JavaScript
1
star
72

pouchdb-ws

PouchDB over websockets
JavaScript
1
star
73

pull-batch

transform input into equally-sized chunks as output
JavaScript
1
star
74

flatware-session

Session Middleware for Flatiron.js
JavaScript
1
star
75

wring

I'm not gonna tell you just yet
JavaScript
1
star
76

gdf2013

Google Dev Fest 2013 Workshop
JavaScript
1
star
77

level-net-server

LevelDB TCP Server
JavaScript
1
star
78

madeiranature_wp_import

1
star
79

flatware-cookie-parser

Cookie Parser middleware for Flatiron.js
1
star
80

lxjs-kinect

LXJS Kinect Photo booth hack
Processing
1
star
81

skiff-tcp-nlsjson

New-line separated JSON over TCP transport layer for Skiff
JavaScript
1
star
82

humanize-deep-diff

Human (English) description of a deep-diff output
JavaScript
1
star
83

roar

Node Sound for Mac
C++
1
star
84

json-duplex-stream

JSON duplex stream
JavaScript
1
star
85

pgte.github.com

1
star
86

video_example

JavaScript
1
star
87

applied-websockets-article-code

JavaScript
1
star
88

essential

Streaming all the way - Under construction
JavaScript
1
star