First part of usage doc for cluster, see #1916
* Sample app, akka-sample-cluster * Preparing Your Project for Clustering * A Simple Cluster Example * Automatic vs. Manual Joining * Automatic vs. Manual Downing * Configuration
This commit is contained in:
parent
f6079de381
commit
a237058b64
4 changed files with 208 additions and 7 deletions
196
akka-docs/cluster/cluster-usage.rst
Normal file
196
akka-docs/cluster/cluster-usage.rst
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
|
||||
.. _cluster_usage:
|
||||
|
||||
###############
|
||||
Cluster Usage
|
||||
###############
|
||||
|
||||
.. note:: This document describes how to use the features implemented so far of the
|
||||
new clustering coming in Akka Coltrane and is not available in the latest stable release.
|
||||
The API might change before it is released.
|
||||
|
||||
For introduction to the Akka Cluster concepts please see :ref:`cluster`.
|
||||
|
||||
Preparing Your Project for Clustering
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The Akka cluster is a separate jar file. Make sure that you have the following dependency in your project::
|
||||
|
||||
"com.typesafe.akka" % "akka-cluster" % "2.1-SNAPSHOT"
|
||||
|
||||
Instead of 2.1-SNAPSHOT you should pick a timestamped Akka version from `<http://repo.typesafe.com/typesafe/snapshots/com/typesafe/akka/akka-cluster/>`_.
|
||||
|
||||
The following sbt build file illustrates what to use with Scala 2.10.0-M7 and Akka 2.1-SNAPSHOT
|
||||
|
||||
import sbt._
|
||||
import sbt.Keys._
|
||||
|
||||
object ProjectBuild extends Build {
|
||||
|
||||
lazy val root = Project(
|
||||
id = "root",
|
||||
base = file("."),
|
||||
settings = Project.defaultSettings ++ Seq(
|
||||
name := "Akka Cluster Example",
|
||||
organization := "org.test",
|
||||
version := "0.1-SNAPSHOT",
|
||||
scalaVersion := "2.10.0-M7",
|
||||
|
||||
resolvers += "Sonatype Releases Repo" at "https://oss.sonatype.org/content/repositories/releases/",
|
||||
resolvers += "Sonatype Snapshot Repo" at "https://oss.sonatype.org/content/repositories/snapshots/",
|
||||
resolvers += "Typesafe Releases" at "http://repo.typesafe.com/typesafe/releases",
|
||||
resolvers += "Typesafe Snapshots" at "http://repo.typesafe.com/typesafe/snapshots/",
|
||||
|
||||
|
||||
libraryDependencies ++= Seq(
|
||||
"com.typesafe.akka" % "akka-cluster" % "2.1-20120822-000942")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
Pick a timestamped Akka version from `<http://repo.typesafe.com/typesafe/snapshots/com/typesafe/akka/akka-cluster/>`_.
|
||||
|
||||
|
||||
A Simple Cluster Example
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The following small program together with its configuration starts an ``ActorSystem``
|
||||
with the Cluster extension enabled. It joins the cluster and logs some membership events.
|
||||
|
||||
Try it out:
|
||||
|
||||
1. Add the following ``application.conf`` in your project, place it in ``src/main/resources``:
|
||||
|
||||
|
||||
.. literalinclude:: ../../akka-samples/akka-sample-cluster/src/main/resources/application.conf
|
||||
:language: none
|
||||
|
||||
To enable cluster capabilities in your Akka project you should, at a minimum, add the :ref:`remoting-scala`
|
||||
settings and the ``akka.cluster.seed-nodes`` to your ``application.conf`` file:
|
||||
|
||||
.. literalinclude:: ../../akka-samples/akka-sample-remote/src/main/resources/common.conf
|
||||
:language: none
|
||||
|
||||
The seed nodes are configured contact points for initial, automatic, join of the cluster.
|
||||
|
||||
Note that if you are going to starting the nodes on different machines you need to specify the
|
||||
ip-addresses or host names of the machines in ``application.conf`` instead of ``127.0.0.1``
|
||||
|
||||
2. Add the following main program to your project, place it in ``src/main/scala``:
|
||||
|
||||
.. literalinclude:: ../../akka-samples/akka-sample-cluster/src/main/scala/sample/cluster/ClusterApp.scala
|
||||
:language: scala
|
||||
|
||||
|
||||
3. Start the first seed node. Open a sbt session in one terminal window and run::
|
||||
|
||||
run-main sample.cluster.ClusterApp 2551
|
||||
|
||||
2551 corresponds to the port of the first seed-nodes element in the configuration.
|
||||
In the log output you see that the cluster node has been started and changed status to Up.
|
||||
|
||||
4. Start the second seed node. Open a sbt session in another terminal window and run::
|
||||
|
||||
run-main sample.cluster.ClusterApp 2552
|
||||
|
||||
|
||||
2552 corresponds to the port of the first seed-nodes element in the configuration.
|
||||
In the log output you see that the cluster node has been started and joins the other seed node
|
||||
and becomes a member of the cluster. It's status changed to Up.
|
||||
|
||||
Switch over to the first terminal window and see in the log output that the member joined.
|
||||
|
||||
5. Start another node. Open a sbt session in yet another terminal window and run::
|
||||
|
||||
run-main sample.cluster.ClusterApp
|
||||
|
||||
Now you don't need to specify the port number, and it will use a random available port.
|
||||
It joins one of the configured seed nodes. Look at the log output in the different terminal
|
||||
windows.
|
||||
|
||||
Start even more nodes in the same way, if you like.
|
||||
|
||||
6. Shut down one of the nodes by pressing 'ctrl-c' in one of the terminal windows.
|
||||
The other nodes will detect the failure after a while, which you can see in the log
|
||||
output in the other terminals.
|
||||
|
||||
Look at the source code of the program again. What it does is to create an actor
|
||||
and register it as subscriber of certain cluster events. It gets notified with
|
||||
an snapshot event, 'CurrentClusterState' that holds full state information of
|
||||
the cluster. After that it receives events for changes that happen in the cluster.
|
||||
|
||||
Automatic vs. Manual Joining
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
You may decide if joining to the cluster should be done automatically or manually.
|
||||
By default it is automatic and you need to define the seed nodes in configuration
|
||||
so that a new node has an initial contact point. When a new node is started it
|
||||
sends a message to all seed nodes and then sends join command to the one that
|
||||
answers first. If no one of the seed nodes replied (might not be started yet)
|
||||
it retries this procedure until successful or shutdown.
|
||||
|
||||
There is one thing to be aware of regarding the seed node configured as the
|
||||
first element in the ``seed-nodes`` configuration list.
|
||||
The seed nodes can be started in any order and it is not necessary to have all
|
||||
seed nodes running, but the first seed node must be started when initially
|
||||
starting a cluster, otherwise the other seed-nodes will not become initialized
|
||||
and no other node can join the cluster. Once more than two seed nodes have been
|
||||
started it is no problem to shut down the first seed node. If it goes down it
|
||||
must be manually joined to the cluster again.
|
||||
Automatic joining of the first seed node is not possible, it would only join
|
||||
itself. It is only the first seed node that has this restriction.
|
||||
|
||||
You can disable automatic joining with configuration:
|
||||
|
||||
akka.cluster.auto-join = off
|
||||
|
||||
Then you need to join manually, using JMX or the provided script.
|
||||
You can join to any node in the cluster. It doesn't have to be configured as
|
||||
seed node. If you are not using auto-join there is no need to configure
|
||||
seed nodes at all.
|
||||
|
||||
Joining can also be performed programatically with ``Cluster(system).join``.
|
||||
|
||||
|
||||
Automatic vs. Manual Downing
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
When a member is considered by the failure detector to be unreachable the
|
||||
leader is not allowed to perform its duties, such as changing status of
|
||||
new joining members to Up. The status of the unreachable member must be
|
||||
changed to Down. This can be performed automatically or manually. By
|
||||
default it must be done manually, using using JMX or the provided script.
|
||||
|
||||
It can also be performed programatically with ``Cluster(system).down``.
|
||||
|
||||
You can enable automatic downing with configuration:
|
||||
|
||||
akka.cluster.auto-down = on
|
||||
|
||||
Be aware of that using auto-down implies that two separate clusters will
|
||||
automatically be formed in case of network partition. That might be
|
||||
desired by some applications but not by others.
|
||||
|
||||
Configuration
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
There are several configuration properties for the cluster. We refer to the following
|
||||
reference file for more information:
|
||||
|
||||
|
||||
.. literalinclude:: ../../akka-cluster/src/main/resources/reference.conf
|
||||
:language: none
|
||||
|
||||
It is recommended that you change the ``tick-duration`` to 33 ms or less
|
||||
of the default scheduler when using cluster, if you don't need to have it
|
||||
configured to a longer duration for other reasons. If you don't do this
|
||||
a dedicated scheduler will be used for periodic tasks of the cluster, which
|
||||
introduce the extra overhead of another thread.
|
||||
|
||||
::
|
||||
|
||||
# shorter tick-duration of default scheduler when using cluster
|
||||
akka.scheduler.tick-duration.tick-duration = 33ms
|
||||
|
||||
|
||||
|
||||
|
|
@ -5,3 +5,4 @@ Cluster
|
|||
:maxdepth: 2
|
||||
|
||||
cluster
|
||||
cluster-usage
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ akka {
|
|||
extensions = ["akka.cluster.Cluster$"]
|
||||
|
||||
cluster {
|
||||
seed-nodes = ["akka://ClusterSystem@127.0.0.1:2551", "akka://ClusterSystem@127.0.0.1:2552"]
|
||||
seed-nodes = [
|
||||
"akka://ClusterSystem@127.0.0.1:2551",
|
||||
"akka://ClusterSystem@127.0.0.1:2552"]
|
||||
}
|
||||
}
|
||||
|
|
@ -8,24 +8,26 @@ object ClusterApp {
|
|||
|
||||
def main(args: Array[String]): Unit = {
|
||||
|
||||
// Override the configuration of the port
|
||||
// when specified as program argument
|
||||
if (args.nonEmpty) System.setProperty("akka.remote.netty.port", args(0))
|
||||
|
||||
// Create an Akka system
|
||||
val system = ActorSystem("ClusterSystem")
|
||||
val clusterListener = system.actorOf(Props(new Actor {
|
||||
val clusterListener = system.actorOf(Props(new Actor with ActorLogging {
|
||||
def receive = {
|
||||
case state: CurrentClusterState ⇒
|
||||
println("Current members: " + state.members)
|
||||
log.info("Current members: {}", state.members)
|
||||
case MemberJoined(member) ⇒
|
||||
println("Member joined: " + member)
|
||||
log.info("Member joined: {}", member)
|
||||
case MemberUp(member) ⇒
|
||||
println("Member is Up: " + member)
|
||||
log.info("Member is Up: {}", member)
|
||||
case MemberUnreachable(member) ⇒
|
||||
println("Member detected as unreachable: " + member)
|
||||
log.info("Member detected as unreachable: {}", member)
|
||||
case _ ⇒ // ignore
|
||||
|
||||
}
|
||||
}))
|
||||
}), name = "clusterListener")
|
||||
|
||||
Cluster(system).subscribe(clusterListener, classOf[ClusterDomainEvent])
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue