Code Monkey home page Code Monkey logo

ckite's Introduction

CKite Build Status

Overview

A JVM implementation of the Raft distributed consensus algorithm written in Scala. CKite is a library to be used by distributed applications needing consensus agreement.

Status

CKite covers all the major topics of Raft including leader election, log replication, log compaction and cluster membership changes. The first release is comming soon. Checkout the latest published snapshot (0.1.2-SNAPSHOT) from Sonatype following the instructions detailed below to start playing with it. For development & testing purposes it contains an embedded key-value store app demonstrating the algorithm functioning trough simple puts and gets. It will be extracted soon from the CKite library as an example of use. Performance tests will be included soon.

Features

  • Leader Election
  • Log Replication
  • Cluster Membership Changes
  • Log Compaction
  • Finagle based RPC between members
  • REST admin console

Getting started (Scala)

SBT settings

The latest snapshot 0.1.2-SNAPSHOT is in Sonatype repo.

"Sonatype OSS" at "http://oss.sonatype.org/content/repositories/snapshots"
"Twitter repo" at "http://maven.twttr.com"

Add the following sbt dependency to your project settings:

libraryDependencies += "io.ckite" % "ckite" % "0.1.2-SNAPSHOT"

Getting started (Java)

Maven settings

Add the following repos to your settings:

<repository>
	<id>sonatype.oss.snapshots</id>
	<name>Sonatype OSS Snapshot Repository</name>
	<url>http://oss.sonatype.org/content/repositories/snapshots</url>
	<releases>
		<enabled>false</enabled>
	</releases>
	<snapshots>
		<enabled>true</enabled>
	</snapshots>
</repository>
<repository>
	<id>twitter.com</id>
	<name>Twitter Maven Repo</name>
	<url>http://maven.twttr.com</url>
	<releases>
		<enabled>true</enabled>
	</releases>
	<snapshots>
		<enabled>true</enabled>
	</snapshots>
</repository> 

Add the following maven dependency to your pom.xml:

<dependency>
	<groupId>io.ckite</groupId>
	<artifactId>ckite</artifactId>
	<version>0.1.2-SNAPSHOT</version>
</dependency>

Example

1) Define a StateMachine and its commands

//KVStore is a simple distributed Map accepting Puts and Gets
class KVStore extends StateMachine {

  val map = new ConcurrentHashMap[String, String]()

  //called when a consensus has been reached for a WriteCommand or when a ReadCommand was received
  override def apply(command: Command): Any = command match {
      case Put(key: String, value: String) => { 
        map.put(key, value)
        value
      }
      case Get(key: String) => map.get(key)
  }

  //called during Log replay on startup and upon installSnapshot requests
  override def deserialize(snapshotBytes: Array[Byte]) = {
	//some deserialization mechanism
  }
 
  //called when Log compaction is required
  override def serialize(): Array[Byte] = {
	//some serialization mechanism
  }

}

//WriteCommands are replicated under Raft rules
case class Put(key: String, value: String) extends WriteCommand

//ReadCommands are not replicated but forwarded to the Leader
case class Get(key: String) extends ReadCommand

2) Create a CKite instance using the builder

val ckite = CKiteBuilder().withLocalBinding("localhost:9091")
                          .withMembersBindings(Seq("localhost:9092","localhost:9093"))
                          .withMinElectionTimeout(1000).withMaxElectionTimeout(1500) //optional
                          .withHeartbeatsInterval(250) //optional
                          .withDataDir("/home/ckite/data") //dataDir for persistent state (log, terms, snapshots, etc...)
                          .withStateMachine(new KVStore()) //KVStore is an implementation of the StateMachine trait
                          .build
ckite.start()

3) Send a write command

//this Put command is forwarded to the Leader and applied under Raft rules
ckite.write(Put("key1","value1")) 

4) Send a consistent read command

//consistent read commands are forwarded to the Leader
val value = ckite.read[String](Get("key1")) 

5) Add a new Member

//as write commands, cluster membership changes are forwarded to the Leader
ckite.addMember("someHost:9094")

6) Remove a Member

//as write commands, cluster membership changes are forwarded to the Leader
ckite.removeMember("someHost:9094")

7) Send a local read command

//alternatively you can read from its local state machine allowing possible stale values
val value = ckite.readLocal[String](Get("key1")) 

8) Check leadership

//if necessary waits for elections to end
ckite.isLeader() 

9) Stop ckite

ckite.stop()

Rest admin console

CKite exposes an admin console showing its status and useful metrics. If the rpc port is 9091 then the admin console is exposed under http://localhost:10091/status by default.

Leader

{
	cluster: {
		term: 1,
		state: "Leader",
		stateInfo: {
			leaderUptime: "13.hours+4.minutes+47.seconds+214.milliseconds",
			followers: {
				localhost:9093: {
					lastHeartbeatACK: "11.milliseconds",
					nextIndex: 10
				},
				localhost:9092: {
					lastHeartbeatACK: "8.milliseconds",
					nextIndex: 10
				}
				localhost:9095: {
					lastHeartbeatACK: "10.milliseconds",
					nextIndex: 10
				}
				localhost:9094: {
					lastHeartbeatACK: "12.milliseconds",
					nextIndex: 10
				}
			}
		}
	},
	log: {
		length: 9,
		commitIndex: 9,
		lastEntry: {
			term: 1,
			index: 9,
			command: {
				key: "foo",
				value: "bar"
			}
		}
	}
}

Follower

{
	cluster: {
		term: 1,
		state: "Follower",
		stateInfo: {
			following: "Some(localhost:9091)"
		}
	},
	log: {
		length: 9,
		commitIndex: 9,
		lastEntry: {
			term: 1,
			index: 9,
			command: {
				key: "foo",
				value: "bar"
			}
		}
	}
}

Running KVStore example (3 members)

Run Member 1

sbt run -Dport=9091 -Dmembers=localhost:9092,localhost:9093 -DdataDir=/tmp/ckite/member1

Run Member 2

sbt run -Dport=9092 -Dmembers=localhost:9091,localhost:9093 -DdataDir=/tmp/ckite/member2

Run Member 3

sbt run -Dport=9093 -Dmembers=localhost:9092,localhost:9091 -DdataDir=/tmp/ckite/member3

Put a key-value on the leader member (take a look at the logs for election result)

curl http://localhost:10091/put/key1/value1

Get the value of key1 replicated in member 2

curl http://localhost:10092/get/key1

Checkout the admin console on any member to see the cluster status

curl http://localhost:10093/status

Add a new member (localhost:9094) to the Cluster

curl http://localhost:10091/changecluster/localhost:9091,localhost:9092,localhost:9093,localhost:9094

Run Member 4

sbt run -Dport=9094 -Dmembers=localhost:9092,localhost:9091,localhost:9093 -DdataDir=/tmp/ckite/member4

Implementation details

Contributions

Feel free to contribute to CKite!. Any kind of help will be very welcome. We are happy to receive pull requests, issues, discuss implementation details, analyze the raft algorithm and whatever it makes CKite a better library. The following is a list of known pendings to be solved in CKite. You can start from there!

Pendings/WorkToDo

  • Leader election
  • Log replication
  • Cluster Membership changes
  • Log persistence & compaction
  • Extract the key value store app from CKite
  • Metrics / monitoring
  • Akka
  • Improve REST admin console
  • Other things...

Importing the project into IntelliJ IDEA

To generate the necessary IDE config files first run the following command and then open the project as usual:

    sbt gen-idea

ckite's People

Contributors

pablosmedina avatar

Watchers

James Cloos avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.