GitXplorerGitXplorer
k

akka-raft

public
280 stars
42 forks
57 issues

Commits

List of commits on branch master.
Unverified
103e17f9441c49e22b8024c47203c5c8e8e1a7d9

Fixes LeaderElectionTest. Adds a new StateTransitionMonitoringActor that helps to manage cluster nodes fsm state transitions.

ddmitraver committed 8 years ago
Unverified
e416bb2209319c02b1298e9822ec77270b10793b

Removes TestActorRef from test code as it doesn't work with persistent actors by its nature. Rewrites FollowerTest to use event based behavioral testing. Adds a class for cleaning persistent journal after each test invocation.

ddmitraver committed 8 years ago
Unverified
e3ea9f25ea82074c18461e6e16edd00c1a7d2d28

Merge pull request #83 from dmitraver/master

kktoso committed 9 years ago
Unverified
9392518fd1108405dfdb47faa1168b416888faa8

Adds missing journal and snapshot storage declaration.

ddmitraver committed 9 years ago
Unverified
ee3d9b0fde700d3d491fa32870fb448e9055cee7

Adds persistence support for fsm. It ensures that important non-volatile state such as currentTerm or votedFor variables are persisted and can be recovered after actor crashed.

ddmitraver committed 9 years ago
Unverified
98e6d3434f139fe654a731b70d0b47f4008852b5

Removes ElectionMeta and LeaderMeta classes. Moves their

ddmitraver committed 9 years ago

README

The README file for this repository.

akka-raft

This is an akka based implementation of the Raft consensus algorithm. It is generic enough that you can build your own replicated state machines on top of it (with raft keeping track of the consensus part of it).

This implementation is akka-cluster aware, so it can be easily deployed on multiple machines. Implementation wise, all parts of the raft whitepaper are covered:

  • Leader election
  • Dynamic membership changes (with transitioning periods implemented as Joint Consensus)
  • Deployment across multiple nodes
  • Log compaction, via snapshotting

Disclaimer

💥 💥

This project is a side-project of mine and is still work in progress (treat it as EARLY PREVIEW) and has a number of known protocol bugs (see Issues). It is NOT recommended to be used in production, however it's a great project to play around with implementing and discussing the Raft protocol.

💥 💥

In other words: Use at own risk, best not on any production-like environments (for now).

Basic info

Raft is a distributed consensus algorithm, much like Paxos (but simpler). This implementation is fully akka (and akka-cluster) based, and can be used to deploy a replicated state machine on top of akka clusters.

THIS API IS STILL SUBJECT TO CHANGE

class WordConcatRaftActor extends RaftActor {

  type Command = Cmnd

  var words = Vector[String]()

  /** 
   * Called when a command is determined by Raft to be safe to apply; 
   * Application results are sent back to the client issuing the command.
   */
  def apply = { 
    case AppendWord(word) =>
      words +: word
      log.info("Applied command [{}], full words is: {}", command, words)

      word // will be sent back to original actor, who sent the AppendWord command

    case GetWords =>
      val res = words.toList
      log.info("Replying with {}", res)
      res
  }
}

// ...

val members = (1 to 3) map { i => system.actorOf(Props[WordConcatRaftActor], name = s"raft-member-$i") }
val clusterConfiguration = ClusterConfiguration(raftConfiguration.members + additionalActor) // 0, 1

members foreach { _ ! ChangeConfiguration(clusterConfiguration)

// todo implement re-routing if you send to a non-leader
// then send messages to it; the state machine will only be applied when consensus has been reached about a value
leader ! ClientRequest(AppendWord("I"))
leader ! ClientRequest(AppendWord("like"))
leader ! ClientRequest(AppendWord("capybaras"))

// ... after some time
leader ! GetWords

expectMsg(List("I", "like", "capybaras"))

And if you want to enable snapshotting support it's as simple as implementing one method and matching for InstallSnapshot in your Actor:

class SnapshottingWordConcatRaftActor extends RaftActor {

  type Command = Cmnd

  var words = Vector[String]()

  def apply = {
    case AppendWord(word) =>
      words +: word
      word

    case GetWords =>
      val res = words.toList
      log.info("Replying with {}", res)
      res

    case InstallSnapshot(snapshot) =>
      words = snapshot.data.asInstanceOf[Vector[String]]
  }

  override def prepareSnapshot(meta: RaftSnapshotMetadata) =
    Future.successful(Some(RaftSnapshot(meta, words)))
}

RaftClientActor

In the above examples, the client implementation is very naive, and assumes you have some way of finding out who the current Leader is (as this is a requirement to interact with any Raft cluster). Thankfully, you can use the provided RaftClientActor, which works like a proxy that forwards all your messages to the current Leader, or stashes them if the cluster has no Leader at the moment (is undergoing an election) and sends the messages once the Leader becomes available.

License

Simply: Apache 2.0

Issues, Pull Requests as well as Tweets and Emails are more than welcome!

Links & kudos

We have discussed this paper both in Kraków and London, on these awesome reading clubs (drop by if you're into CS papers!):

Bitdeli Badge