2011-12-15 18:05:24 +01:00
|
|
|
|
.. _remoting-java:
|
|
|
|
|
|
|
|
|
|
|
|
#####################
|
2013-04-19 13:21:15 +02:00
|
|
|
|
Remoting
|
2011-12-15 18:05:24 +01:00
|
|
|
|
#####################
|
|
|
|
|
|
|
2011-12-15 21:16:19 +01:00
|
|
|
|
For an introduction of remoting capabilities of Akka please see :ref:`remoting`.
|
|
|
|
|
|
|
|
|
|
|
|
Preparing your ActorSystem for Remoting
|
|
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
|
|
2012-01-05 09:31:21 +01:00
|
|
|
|
The Akka remoting is a separate jar file. Make sure that you have the following dependency in your project::
|
2011-12-15 21:16:19 +01:00
|
|
|
|
|
2012-01-05 09:31:21 +01:00
|
|
|
|
<dependency>
|
|
|
|
|
|
<groupId>com.typesafe.akka</groupId>
|
2012-09-21 10:47:58 +02:00
|
|
|
|
<artifactId>akka-remote_@binVersion@</artifactId>
|
|
|
|
|
|
<version>@version@</version>
|
2012-01-05 09:31:21 +01:00
|
|
|
|
</dependency>
|
2011-12-15 21:16:19 +01:00
|
|
|
|
|
2012-01-05 09:31:21 +01:00
|
|
|
|
To enable remote capabilities in your Akka project you should, at a minimum, add the following changes
|
|
|
|
|
|
to your ``application.conf`` file::
|
2011-12-15 21:16:19 +01:00
|
|
|
|
|
|
|
|
|
|
akka {
|
|
|
|
|
|
actor {
|
2012-01-05 09:31:21 +01:00
|
|
|
|
provider = "akka.remote.RemoteActorRefProvider"
|
2011-12-15 21:16:19 +01:00
|
|
|
|
}
|
2011-12-22 01:11:11 +01:00
|
|
|
|
remote {
|
2013-01-23 11:38:20 +01:00
|
|
|
|
enabled-transports = ["akka.remote.netty.tcp"]
|
|
|
|
|
|
netty.tcp {
|
2012-01-05 09:31:21 +01:00
|
|
|
|
hostname = "127.0.0.1"
|
2011-12-22 01:11:11 +01:00
|
|
|
|
port = 2552
|
|
|
|
|
|
}
|
2012-01-05 09:31:21 +01:00
|
|
|
|
}
|
2011-12-15 21:16:19 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2012-01-05 09:31:21 +01:00
|
|
|
|
As you can see in the example above there are four things you need to add to get started:
|
|
|
|
|
|
|
|
|
|
|
|
* Change provider from ``akka.actor.LocalActorRefProvider`` to ``akka.remote.RemoteActorRefProvider``
|
2012-02-02 09:40:17 +01:00
|
|
|
|
* Add host name - the machine you want to run the actor system on; this host
|
|
|
|
|
|
name is exactly what is passed to remote systems in order to identify this
|
|
|
|
|
|
system and consequently used for connecting back to this system if need be,
|
|
|
|
|
|
hence set it to a reachable IP address or resolvable name in case you want to
|
|
|
|
|
|
communicate across the network.
|
|
|
|
|
|
* Add port number - the port the actor system should listen on, set to 0 to have it chosen automatically
|
2012-01-05 09:31:21 +01:00
|
|
|
|
|
2012-08-16 17:00:06 +02:00
|
|
|
|
.. note::
|
|
|
|
|
|
The port number needs to be unique for each actor system on the same machine even if the actor
|
|
|
|
|
|
systems have different names. This is because each actor system has its own network subsystem
|
|
|
|
|
|
listening for connections and handling messages as not to interfere with other actor systems.
|
|
|
|
|
|
|
2012-01-05 09:31:21 +01:00
|
|
|
|
The example above only illustrates the bare minimum of properties you have to add to enable remoting.
|
2013-04-15 09:26:51 +02:00
|
|
|
|
All settings are described in :ref:`remote-configuration-java`.
|
2012-10-05 11:56:59 -07:00
|
|
|
|
|
2011-12-22 01:11:11 +01:00
|
|
|
|
Looking up Remote Actors
|
|
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
|
|
2013-03-26 18:17:50 +01:00
|
|
|
|
``actorSelection(path)`` will obtain an ``ActorSelection`` to an Actor on a remote node::
|
2011-12-22 01:11:11 +01:00
|
|
|
|
|
2013-03-26 18:17:50 +01:00
|
|
|
|
ActorSelection selection =
|
|
|
|
|
|
context.actorSelection("akka.tcp://app@10.0.0.1:2552/user/serviceA/worker");
|
2011-12-22 01:11:11 +01:00
|
|
|
|
|
2013-03-26 18:17:50 +01:00
|
|
|
|
As you can see from the example above the following pattern is used to find an actor on a remote node::
|
2011-12-22 01:11:11 +01:00
|
|
|
|
|
2013-01-23 11:38:20 +01:00
|
|
|
|
akka.<protocol>://<actorsystemname>@<hostname>:<port>/<actor path>
|
2011-12-22 01:11:11 +01:00
|
|
|
|
|
2013-03-26 18:17:50 +01:00
|
|
|
|
Once you obtained a selection to the actor you can interact with it they same way you would with a local actor, e.g.::
|
2012-08-17 12:12:14 +02:00
|
|
|
|
|
2013-03-26 18:17:50 +01:00
|
|
|
|
selection.tell("Pretty awesome feature", getSelf());
|
|
|
|
|
|
|
|
|
|
|
|
To acquire an :class:`ActorRef` for an :class:`ActorSelection` you need to
|
|
|
|
|
|
send a message to the selection and use the ``getSender`` reference of the reply from
|
|
|
|
|
|
the actor. There is a built-in ``Identify`` message that all Actors will understand
|
|
|
|
|
|
and automatically reply to with a ``ActorIdentity`` message containing the
|
|
|
|
|
|
:class:`ActorRef`.
|
2012-08-17 12:12:14 +02:00
|
|
|
|
|
2012-08-14 20:42:54 +02:00
|
|
|
|
.. note::
|
|
|
|
|
|
|
|
|
|
|
|
For more details on how actor addresses and paths are formed and used, please refer to :ref:`addressing`.
|
2011-12-26 18:39:42 +01:00
|
|
|
|
|
2011-12-22 01:11:11 +01:00
|
|
|
|
Creating Actors Remotely
|
|
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
2011-12-15 21:16:19 +01:00
|
|
|
|
|
2012-09-21 15:08:56 +02:00
|
|
|
|
If you want to use the creation functionality in Akka remoting you have to further amend the
|
|
|
|
|
|
``application.conf`` file in the following way (only showing deployment section)::
|
2011-12-15 21:16:19 +01:00
|
|
|
|
|
|
|
|
|
|
akka {
|
|
|
|
|
|
actor {
|
|
|
|
|
|
deployment {
|
2012-09-21 15:08:56 +02:00
|
|
|
|
/sampleActor {
|
2013-01-23 11:38:20 +01:00
|
|
|
|
remote = "akka.tcp://sampleActorSystem@127.0.0.1:2553"
|
2011-12-15 21:16:19 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2012-09-21 15:08:56 +02:00
|
|
|
|
The configuration above instructs Akka to react when an actor with path ``/sampleActor`` is created, i.e.
|
|
|
|
|
|
using ``system.actorOf(new Props(...), "sampleActor")``. This specific actor will not be directly instantiated,
|
|
|
|
|
|
but instead the remote daemon of the remote system will be asked to create the actor,
|
|
|
|
|
|
which in this sample corresponds to ``sampleActorSystem@127.0.0.1:2553``.
|
2011-12-15 21:16:19 +01:00
|
|
|
|
|
2012-09-21 15:08:56 +02:00
|
|
|
|
Once you have configured the properties above you would do the following in code:
|
2011-12-15 21:16:19 +01:00
|
|
|
|
|
2012-09-21 15:08:56 +02:00
|
|
|
|
.. includecode:: code/docs/remoting/RemoteDeploymentDocTestBase.java#sample-actor
|
2011-12-15 21:16:19 +01:00
|
|
|
|
|
2012-09-21 17:08:36 +02:00
|
|
|
|
The actor class ``SampleActor`` has to be available to the runtimes using it, i.e. the classloader of the
|
2012-09-21 15:08:56 +02:00
|
|
|
|
actor systems has to have a JAR containing the class.
|
2011-12-15 21:16:19 +01:00
|
|
|
|
|
2012-06-04 23:10:03 +02:00
|
|
|
|
.. note::
|
|
|
|
|
|
|
|
|
|
|
|
In order to ensure serializability of ``Props`` when passing constructor
|
|
|
|
|
|
arguments to the actor being created, do not make the factory a non-static
|
|
|
|
|
|
inner class: this will inherently capture a reference to its enclosing
|
|
|
|
|
|
object, which in most cases is not serializable. It is best to make a static
|
|
|
|
|
|
inner class which implements :class:`UntypedActorFactory`.
|
|
|
|
|
|
|
2012-11-28 10:56:08 +01:00
|
|
|
|
.. note::
|
|
|
|
|
|
|
|
|
|
|
|
You can use asterisks as wildcard matches for the actor path sections, so you could specify:
|
|
|
|
|
|
``/*/sampleActor`` and that would match all ``sampleActor`` on that level in the hierarchy.
|
|
|
|
|
|
You can also use wildcard in the last position to match all actors at a certain level:
|
|
|
|
|
|
``/someParent/*``. Non-wildcard matches always have higher priority to match than wildcards, so:
|
|
|
|
|
|
``/foo/bar`` is considered **more specific** than ``/foo/*`` and only the highest priority match is used.
|
|
|
|
|
|
Please note that it **cannot** be used to partially match section, like this: ``/foo*/bar``, ``/f*o/bar`` etc.
|
|
|
|
|
|
|
2012-02-02 09:40:17 +01:00
|
|
|
|
Programmatic Remote Deployment
|
|
|
|
|
|
------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
To allow dynamically deployed systems, it is also possible to include
|
|
|
|
|
|
deployment configuration in the :class:`Props` which are used to create an
|
|
|
|
|
|
actor: this information is the equivalent of a deployment section from the
|
|
|
|
|
|
configuration file, and if both are given, the external configuration takes
|
|
|
|
|
|
precedence.
|
|
|
|
|
|
|
|
|
|
|
|
With these imports:
|
|
|
|
|
|
|
2012-05-24 22:23:36 +02:00
|
|
|
|
.. includecode:: code/docs/remoting/RemoteDeploymentDocTestBase.java#import
|
2012-02-02 09:40:17 +01:00
|
|
|
|
|
|
|
|
|
|
and a remote address like this:
|
|
|
|
|
|
|
2012-05-24 22:23:36 +02:00
|
|
|
|
.. includecode:: code/docs/remoting/RemoteDeploymentDocTestBase.java#make-address
|
2012-02-02 09:40:17 +01:00
|
|
|
|
|
|
|
|
|
|
you can advise the system to create a child on that remote node like so:
|
|
|
|
|
|
|
2012-05-24 22:23:36 +02:00
|
|
|
|
.. includecode:: code/docs/remoting/RemoteDeploymentDocTestBase.java#deploy
|
2012-02-02 09:40:17 +01:00
|
|
|
|
|
2013-04-15 09:26:51 +02:00
|
|
|
|
Watching Remote Actors
|
|
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
|
|
|
|
|
|
|
Watching a remote actor is not different than watching a local actor, as described in
|
|
|
|
|
|
:ref:`deathwatch-java`.
|
|
|
|
|
|
|
|
|
|
|
|
.. warning::
|
|
|
|
|
|
|
|
|
|
|
|
*Caveat:* Watching an ``ActorRef`` acquired with ``actorFor`` does not trigger
|
|
|
|
|
|
``Terminated`` for lost connections. ``actorFor`` is deprecated in favor of
|
|
|
|
|
|
``actorSelection``. Acquire the ``ActorRef`` to watch with ``Identify`` and
|
|
|
|
|
|
``ActorIdentity`` as described in :ref:`actorSelection-java`.
|
|
|
|
|
|
|
|
|
|
|
|
Failure Detector
|
|
|
|
|
|
----------------
|
|
|
|
|
|
|
|
|
|
|
|
Under the hood remote death watch uses heartbeat messages and a failure detector to generate ``Terminated``
|
|
|
|
|
|
message from network failures and JVM crashes, in addition to graceful termination of watched
|
|
|
|
|
|
actor.
|
|
|
|
|
|
|
|
|
|
|
|
The heartbeat arrival times is interpreted by an implementation of
|
|
|
|
|
|
`The Phi Accrual Failure Detector <http://ddg.jaist.ac.jp/pub/HDY+04.pdf>`_.
|
|
|
|
|
|
|
|
|
|
|
|
The suspicion level of failure is given by a value called *phi*.
|
|
|
|
|
|
The basic idea of the phi failure detector is to express the value of *phi* on a scale that
|
|
|
|
|
|
is dynamically adjusted to reflect current network conditions.
|
|
|
|
|
|
|
|
|
|
|
|
The value of *phi* is calculated as::
|
|
|
|
|
|
|
|
|
|
|
|
phi = -log10(1 - F(timeSinceLastHeartbeat))
|
|
|
|
|
|
|
|
|
|
|
|
where F is the cumulative distribution function of a normal distribution with mean
|
|
|
|
|
|
and standard deviation estimated from historical heartbeat inter-arrival times.
|
|
|
|
|
|
|
|
|
|
|
|
In the :ref:`remote-configuration-java` you can adjust the ``akka.remote.watch-failure-detector.threshold``
|
|
|
|
|
|
to define when a *phi* value is considered to be a failure.
|
|
|
|
|
|
|
|
|
|
|
|
A low ``threshold`` is prone to generate many false positives but ensures
|
|
|
|
|
|
a quick detection in the event of a real crash. Conversely, a high ``threshold``
|
|
|
|
|
|
generates fewer mistakes but needs more time to detect actual crashes. The
|
|
|
|
|
|
default ``threshold`` is 10 and is appropriate for most situations. However in
|
|
|
|
|
|
cloud environments, such as Amazon EC2, the value could be increased to 12 in
|
|
|
|
|
|
order to account for network issues that sometimes occur on such platforms.
|
|
|
|
|
|
|
|
|
|
|
|
The following chart illustrates how *phi* increase with increasing time since the
|
|
|
|
|
|
previous heartbeat.
|
|
|
|
|
|
|
2013-04-19 13:21:15 +02:00
|
|
|
|
.. image:: ../images/phi1.png
|
2013-04-15 09:26:51 +02:00
|
|
|
|
|
|
|
|
|
|
Phi is calculated from the mean and standard deviation of historical
|
|
|
|
|
|
inter arrival times. The previous chart is an example for standard deviation
|
|
|
|
|
|
of 200 ms. If the heartbeats arrive with less deviation the curve becomes steeper,
|
|
|
|
|
|
i.e. it is possible to determine failure more quickly. The curve looks like this for
|
|
|
|
|
|
a standard deviation of 100 ms.
|
|
|
|
|
|
|
2013-04-19 13:21:15 +02:00
|
|
|
|
.. image:: ../images/phi2.png
|
2013-04-15 09:26:51 +02:00
|
|
|
|
|
|
|
|
|
|
To be able to survive sudden abnormalities, such as garbage collection pauses and
|
|
|
|
|
|
transient network failures the failure detector is configured with a margin,
|
|
|
|
|
|
``akka.remote.watch-failure-detector.acceptable-heartbeat-pause``. You may want to
|
|
|
|
|
|
adjust the :ref:`remote-configuration-java` of this depending on you environment.
|
|
|
|
|
|
This is how the curve looks like for ``acceptable-heartbeat-pause`` configured to
|
|
|
|
|
|
3 seconds.
|
|
|
|
|
|
|
2013-04-19 13:21:15 +02:00
|
|
|
|
.. image:: ../images/phi3.png
|
2013-04-15 09:26:51 +02:00
|
|
|
|
|
2011-12-15 21:16:19 +01:00
|
|
|
|
Serialization
|
|
|
|
|
|
^^^^^^^^^^^^^
|
|
|
|
|
|
|
|
|
|
|
|
When using remoting for actors you must ensure that the ``props`` and ``messages`` used for
|
|
|
|
|
|
those actors are serializable. Failing to do so will cause the system to behave in an unintended way.
|
|
|
|
|
|
|
|
|
|
|
|
For more information please see :ref:`serialization-java`
|
|
|
|
|
|
|
|
|
|
|
|
Routers with Remote Destinations
|
|
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
|
|
2011-12-16 12:12:03 +13:00
|
|
|
|
It is absolutely feasible to combine remoting with :ref:`routing-java`.
|
2011-12-15 21:16:19 +01:00
|
|
|
|
This is also done via configuration::
|
|
|
|
|
|
|
|
|
|
|
|
akka {
|
|
|
|
|
|
actor {
|
|
|
|
|
|
deployment {
|
|
|
|
|
|
/serviceA/aggregation {
|
2012-01-17 08:44:46 +01:00
|
|
|
|
router = "round-robin"
|
2011-12-15 21:16:19 +01:00
|
|
|
|
nr-of-instances = 10
|
2012-01-17 08:44:46 +01:00
|
|
|
|
target {
|
2013-01-23 11:38:20 +01:00
|
|
|
|
nodes = ["akka.tcp://app@10.0.0.2:2552", "akka://app@10.0.0.3:2552"]
|
2011-12-15 21:16:19 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
This configuration setting will clone the actor “aggregation” 10 times and deploy it evenly distributed across
|
2011-12-16 12:12:03 +13:00
|
|
|
|
the two given target nodes.
|
2011-12-28 19:09:08 +01:00
|
|
|
|
|
|
|
|
|
|
Description of the Remoting Sample
|
|
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
|
|
2012-02-02 09:40:17 +01:00
|
|
|
|
There is a more extensive remote example that comes with the Akka distribution.
|
|
|
|
|
|
Please have a look here for more information: `Remote Sample
|
2012-10-22 11:14:22 +02:00
|
|
|
|
<@github@/akka-samples/akka-sample-remote>`_
|
2012-02-02 09:40:17 +01:00
|
|
|
|
This sample demonstrates both, remote deployment and look-up of remote actors.
|
|
|
|
|
|
First, let us have a look at the common setup for both scenarios (this is
|
|
|
|
|
|
``common.conf``):
|
2011-12-28 19:09:08 +01:00
|
|
|
|
|
2012-09-21 10:47:58 +02:00
|
|
|
|
.. includecode:: ../../../akka-samples/akka-sample-remote/src/main/resources/common.conf
|
2011-12-28 19:09:08 +01:00
|
|
|
|
|
|
|
|
|
|
This enables the remoting by installing the :class:`RemoteActorRefProvider` and
|
|
|
|
|
|
chooses the default remote transport. All other options will be set
|
|
|
|
|
|
specifically for each show case.
|
|
|
|
|
|
|
|
|
|
|
|
.. note::
|
|
|
|
|
|
|
|
|
|
|
|
Be sure to replace the default IP 127.0.0.1 with the real address the system
|
|
|
|
|
|
is reachable by if you deploy onto multiple machines!
|
|
|
|
|
|
|
|
|
|
|
|
.. _remote-lookup-sample-java:
|
|
|
|
|
|
|
|
|
|
|
|
Remote Lookup
|
|
|
|
|
|
-------------
|
|
|
|
|
|
|
|
|
|
|
|
In order to look up a remote actor, that one must be created first. For this
|
|
|
|
|
|
purpose, we configure an actor system to listen on port 2552 (this is a snippet
|
|
|
|
|
|
from ``application.conf``):
|
|
|
|
|
|
|
2012-09-21 10:47:58 +02:00
|
|
|
|
.. includecode:: ../../../akka-samples/akka-sample-remote/src/main/resources/application.conf
|
2011-12-28 19:09:08 +01:00
|
|
|
|
:include: calculator
|
|
|
|
|
|
|
|
|
|
|
|
Then the actor must be created. For all code which follows, assume these imports:
|
|
|
|
|
|
|
2012-09-21 10:47:58 +02:00
|
|
|
|
.. includecode:: ../../../akka-samples/akka-sample-remote/src/main/java/sample/remote/calculator/java/JLookupApplication.java
|
2011-12-28 19:09:08 +01:00
|
|
|
|
:include: imports
|
|
|
|
|
|
|
|
|
|
|
|
The actor doing the work will be this one:
|
|
|
|
|
|
|
2012-09-21 10:47:58 +02:00
|
|
|
|
.. includecode:: ../../../akka-samples/akka-sample-remote/src/main/java/sample/remote/calculator/java/JSimpleCalculatorActor.java
|
2011-12-28 19:09:08 +01:00
|
|
|
|
:include: actor
|
|
|
|
|
|
|
|
|
|
|
|
and we start it within an actor system using the above configuration
|
|
|
|
|
|
|
2012-09-21 10:47:58 +02:00
|
|
|
|
.. includecode:: ../../../akka-samples/akka-sample-remote/src/main/java/sample/remote/calculator/java/JCalculatorApplication.java
|
2011-12-28 19:09:08 +01:00
|
|
|
|
:include: setup
|
|
|
|
|
|
|
|
|
|
|
|
With the service actor up and running, we may look it up from another actor
|
|
|
|
|
|
system, which will be configured to use port 2553 (this is a snippet from
|
|
|
|
|
|
``application.conf``).
|
|
|
|
|
|
|
2012-09-21 10:47:58 +02:00
|
|
|
|
.. includecode:: ../../../akka-samples/akka-sample-remote/src/main/resources/application.conf
|
2011-12-28 19:09:08 +01:00
|
|
|
|
:include: remotelookup
|
|
|
|
|
|
|
|
|
|
|
|
The actor which will query the calculator is a quite simple one for demonstration purposes
|
|
|
|
|
|
|
2012-09-21 10:47:58 +02:00
|
|
|
|
.. includecode:: ../../../akka-samples/akka-sample-remote/src/main/java/sample/remote/calculator/java/JLookupActor.java
|
2011-12-28 19:09:08 +01:00
|
|
|
|
:include: actor
|
|
|
|
|
|
|
|
|
|
|
|
and it is created from an actor system using the aforementioned client’s config.
|
|
|
|
|
|
|
2012-09-21 10:47:58 +02:00
|
|
|
|
.. includecode:: ../../../akka-samples/akka-sample-remote/src/main/java/sample/remote/calculator/java/JLookupApplication.java
|
2011-12-28 19:09:08 +01:00
|
|
|
|
:include: setup
|
|
|
|
|
|
|
2013-03-26 18:17:50 +01:00
|
|
|
|
Requests which come in via ``doSomething`` will be sent to the client actor,
|
|
|
|
|
|
which will use the actor reference that was identified earlier. Observe how the actor
|
|
|
|
|
|
system name using in ``actorSelection`` matches the remote system’s name, as do IP
|
2011-12-28 19:09:08 +01:00
|
|
|
|
and port number. Top-level actors are always created below the ``"/user"``
|
|
|
|
|
|
guardian, which supervises them.
|
|
|
|
|
|
|
|
|
|
|
|
Remote Deployment
|
|
|
|
|
|
-----------------
|
|
|
|
|
|
|
|
|
|
|
|
Creating remote actors instead of looking them up is not visible in the source
|
|
|
|
|
|
code, only in the configuration file. This section is used in this scenario
|
|
|
|
|
|
(this is a snippet from ``application.conf``):
|
|
|
|
|
|
|
2012-09-21 10:47:58 +02:00
|
|
|
|
.. includecode:: ../../../akka-samples/akka-sample-remote/src/main/resources/application.conf
|
2011-12-28 19:09:08 +01:00
|
|
|
|
:include: remotecreation
|
|
|
|
|
|
|
|
|
|
|
|
For all code which follows, assume these imports:
|
|
|
|
|
|
|
2012-09-21 10:47:58 +02:00
|
|
|
|
.. includecode:: ../../../akka-samples/akka-sample-remote/src/main/java/sample/remote/calculator/java/JLookupApplication.java
|
2011-12-28 19:09:08 +01:00
|
|
|
|
:include: imports
|
|
|
|
|
|
|
|
|
|
|
|
The server actor can multiply or divide numbers:
|
|
|
|
|
|
|
2012-09-21 10:47:58 +02:00
|
|
|
|
.. includecode:: ../../../akka-samples/akka-sample-remote/src/main/java/sample/remote/calculator/java/JAdvancedCalculatorActor.java
|
2011-12-28 19:09:08 +01:00
|
|
|
|
:include: actor
|
|
|
|
|
|
|
|
|
|
|
|
The client actor looks like in the previous example
|
|
|
|
|
|
|
2012-09-21 10:47:58 +02:00
|
|
|
|
.. includecode:: ../../../akka-samples/akka-sample-remote/src/main/java/sample/remote/calculator/java/JCreationActor.java
|
2011-12-28 19:09:08 +01:00
|
|
|
|
:include: actor
|
|
|
|
|
|
|
|
|
|
|
|
but the setup uses only ``actorOf``:
|
|
|
|
|
|
|
2012-09-21 10:47:58 +02:00
|
|
|
|
.. includecode:: ../../../akka-samples/akka-sample-remote/src/main/java/sample/remote/calculator/java/JCreationApplication.java
|
2011-12-28 19:09:08 +01:00
|
|
|
|
:include: setup
|
|
|
|
|
|
|
|
|
|
|
|
Observe how the name of the server actor matches the deployment given in the
|
|
|
|
|
|
configuration file, which will transparently delegate the actor creation to the
|
|
|
|
|
|
remote node.
|
|
|
|
|
|
|
2013-01-23 11:38:20 +01:00
|
|
|
|
Pluggable transport support
|
|
|
|
|
|
---------------------------
|
|
|
|
|
|
|
|
|
|
|
|
Akka can be configured to use various transports to communicate with remote systems. The core
|
|
|
|
|
|
component of this feature is the :meth:`akka.remote.Transport` SPI. Transport implementations must extend this trait.
|
|
|
|
|
|
Transports can be loaded by setting the ``akka.remote.enabled-transports`` configuration key to point to one or
|
|
|
|
|
|
more configuration sections containing driver descriptions.
|
|
|
|
|
|
|
|
|
|
|
|
An example of setting up the default Netty based SSL driver as default::
|
|
|
|
|
|
|
|
|
|
|
|
akka {
|
|
|
|
|
|
remote {
|
|
|
|
|
|
enabled-transports = [akka.remote.netty.ssl]
|
|
|
|
|
|
|
2013-02-11 13:33:21 +01:00
|
|
|
|
netty.ssl.security {
|
2013-01-23 11:38:20 +01:00
|
|
|
|
key-store = "mykeystore"
|
|
|
|
|
|
trust-store = "mytruststore"
|
|
|
|
|
|
key-store-password = "changeme"
|
2013-04-11 13:14:48 +02:00
|
|
|
|
key-password = "changeme"
|
2013-01-23 11:38:20 +01:00
|
|
|
|
trust-store-password = "changeme"
|
|
|
|
|
|
protocol = "TLSv1"
|
|
|
|
|
|
random-number-generator = "AES128CounterSecureRNG"
|
|
|
|
|
|
enabled-algorithms = [TLS_RSA_WITH_AES_128_CBC_SHA]
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
An example of setting up a custom transport implementation::
|
|
|
|
|
|
|
|
|
|
|
|
akka {
|
|
|
|
|
|
remote {
|
|
|
|
|
|
applied-transports = ["akka.remote.mytransport"]
|
|
|
|
|
|
|
|
|
|
|
|
mytransport {
|
|
|
|
|
|
# The transport-class configuration entry is required, and
|
|
|
|
|
|
# it must contain the fully qualified name of the transport
|
|
|
|
|
|
# implementation
|
|
|
|
|
|
transport-class = "my.package.MyTransport"
|
|
|
|
|
|
|
|
|
|
|
|
# It is possible to decorate Transports with additional services.
|
|
|
|
|
|
# Adapters should be registered in the "adapters" sections to
|
|
|
|
|
|
# be able to apply them to transports
|
|
|
|
|
|
applied-adapters = []
|
|
|
|
|
|
|
|
|
|
|
|
# Driver specific configuration options has to be in the same
|
|
|
|
|
|
# section:
|
|
|
|
|
|
some-config = foo
|
|
|
|
|
|
another-config = bar
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-02-20 15:14:23 +01:00
|
|
|
|
Remote Events
|
|
|
|
|
|
-------------
|
|
|
|
|
|
|
|
|
|
|
|
It is possible to listen to events that occur in Akka Remote, and to subscribe/unsubscribe to there events,
|
|
|
|
|
|
you simply register as listener to the below described types in on the ``ActorSystem.eventStream``.
|
|
|
|
|
|
|
|
|
|
|
|
.. note::
|
2013-02-10 16:04:59 -05:00
|
|
|
|
|
|
|
|
|
|
To subscribe to any remote event, subscribe to
|
|
|
|
|
|
:meth:`RemotingLifecycleEvent`. To subscribe to events related only to the
|
|
|
|
|
|
lifecycle of associations, subscribe to
|
|
|
|
|
|
:meth:`akka.remote.AssociationEvent`.
|
2013-01-23 11:38:20 +01:00
|
|
|
|
|
|
|
|
|
|
.. note::
|
2013-02-10 16:04:59 -05:00
|
|
|
|
|
|
|
|
|
|
The use of term "Association" instead of "Connection" reflects that the
|
|
|
|
|
|
remoting subsystem may use connectionless transports, but an association
|
|
|
|
|
|
similar to transport layer connections is maintained between endpoints by
|
|
|
|
|
|
the Akka protocol.
|
2012-02-20 15:14:23 +01:00
|
|
|
|
|
2012-08-17 12:25:31 +02:00
|
|
|
|
By default an event listener is registered which logs all of the events
|
|
|
|
|
|
described below. This default was chosen to help setting up a system, but it is
|
|
|
|
|
|
quite common to switch this logging off once that phase of the project is
|
|
|
|
|
|
finished.
|
|
|
|
|
|
|
|
|
|
|
|
.. note::
|
2013-02-10 16:04:59 -05:00
|
|
|
|
|
2012-08-17 12:25:31 +02:00
|
|
|
|
In order to switch off the logging, set
|
|
|
|
|
|
``akka.remote.log-remote-lifecycle-events = off`` in your
|
|
|
|
|
|
``application.conf``.
|
|
|
|
|
|
|
2013-01-23 11:38:20 +01:00
|
|
|
|
To be notified when an association is over ("disconnected") listen to ``DisassociatedEvent`` which
|
|
|
|
|
|
holds the direction of the association (inbound or outbound) and the addresses of the involved parties.
|
2012-02-20 15:14:23 +01:00
|
|
|
|
|
2013-01-23 11:38:20 +01:00
|
|
|
|
To be notified when an association is successfully established ("connected") listen to ``AssociatedEvent`` which
|
|
|
|
|
|
holds the direction of the association (inbound or outbound) and the addresses of the involved parties.
|
2012-02-20 15:14:23 +01:00
|
|
|
|
|
2013-01-23 11:38:20 +01:00
|
|
|
|
To intercept errors directly related to associations, listen to ``AssociationErrorEvent`` which
|
|
|
|
|
|
holds the direction of the association (inbound or outbound), the addresses of the involved parties and the
|
|
|
|
|
|
``Throwable`` cause.
|
2012-02-20 15:14:23 +01:00
|
|
|
|
|
2013-01-23 11:38:20 +01:00
|
|
|
|
To be notified when the remoting subsystem is ready to accept associations, listen to ``RemotingListenEvent`` which
|
|
|
|
|
|
contains the addresses the remoting listens on.
|
2012-02-20 15:14:23 +01:00
|
|
|
|
|
2013-01-23 11:38:20 +01:00
|
|
|
|
To be notified when the remoting subsystem has been shut down, listen to ``RemotingShutdownEvent``.
|
2011-12-28 19:09:08 +01:00
|
|
|
|
|
2013-01-23 11:38:20 +01:00
|
|
|
|
To intercept generic remoting related errors, listen to ``RemotingErrorEvent`` which holds the ``Throwable`` cause.
|
2011-12-28 19:09:08 +01:00
|
|
|
|
|
2012-05-22 12:08:49 +02:00
|
|
|
|
Remote Security
|
|
|
|
|
|
^^^^^^^^^^^^^^^
|
|
|
|
|
|
|
|
|
|
|
|
Akka provides a couple of ways to enhance security between remote nodes (client/server):
|
|
|
|
|
|
|
|
|
|
|
|
* Untrusted Mode
|
|
|
|
|
|
* Security Cookie Handshake
|
|
|
|
|
|
|
|
|
|
|
|
Untrusted Mode
|
|
|
|
|
|
--------------
|
|
|
|
|
|
|
2012-10-04 16:50:49 -07:00
|
|
|
|
As soon as an actor system can connect to another remotely, it may in principle
|
|
|
|
|
|
send any possible message to any actor contained within that remote system. One
|
|
|
|
|
|
example may be sending a :class:`PoisonPill` to the system guardian, shutting
|
|
|
|
|
|
that system down. This is not always desired, and it can be disabled with the
|
|
|
|
|
|
following setting::
|
2012-05-22 12:08:49 +02:00
|
|
|
|
|
2012-10-04 16:50:49 -07:00
|
|
|
|
akka.remote.untrusted-mode = on
|
2012-05-22 12:08:49 +02:00
|
|
|
|
|
2012-10-04 16:50:49 -07:00
|
|
|
|
This disallows sending of system messages (actor life-cycle commands,
|
|
|
|
|
|
DeathWatch, etc.) and any message extending :class:`PossiblyHarmful` to the
|
|
|
|
|
|
system on which this flag is set. Should a client send them nonetheless they
|
|
|
|
|
|
are dropped and logged (at DEBUG level in order to reduce the possibilities for
|
|
|
|
|
|
a denial of service attack). :class:`PossiblyHarmful` covers the predefined
|
|
|
|
|
|
messages like :class:`PoisonPill` and :class:`Kill`, but it can also be added
|
|
|
|
|
|
as a marker trait to user-defined messages.
|
2012-05-22 12:08:49 +02:00
|
|
|
|
|
2012-10-04 16:50:49 -07:00
|
|
|
|
In summary, the following operations are ignored by a system configured in
|
|
|
|
|
|
untrusted mode when incoming via the remoting layer:
|
|
|
|
|
|
|
|
|
|
|
|
* remote deployment (which also means no remote supervision)
|
|
|
|
|
|
* remote DeathWatch
|
|
|
|
|
|
* ``system.stop()``, :class:`PoisonPill`, :class:`Kill`
|
|
|
|
|
|
* sending any message which extends from the :class:`PossiblyHarmful` marker
|
|
|
|
|
|
interface, which includes :class:`Terminated`
|
|
|
|
|
|
|
|
|
|
|
|
.. note::
|
|
|
|
|
|
|
|
|
|
|
|
Enabling the untrusted mode does not remove the capability of the client to
|
|
|
|
|
|
freely choose the target of its message sends, which means that messages not
|
|
|
|
|
|
prohibited by the above rules can be sent to any actor in the remote system.
|
|
|
|
|
|
It is good practice for a client-facing system to only contain a well-defined
|
|
|
|
|
|
set of entry point actors, which then forward requests (possibly after
|
|
|
|
|
|
performing validation) to another actor system containing the actual worker
|
|
|
|
|
|
actors. If messaging between these two server-side systems is done using
|
|
|
|
|
|
local :class:`ActorRef` (they can be exchanged safely between actor systems
|
|
|
|
|
|
within the same JVM), you can restrict the messages on this interface by
|
|
|
|
|
|
marking them :class:`PossiblyHarmful` so that a client cannot forge them.
|
2012-05-22 12:08:49 +02:00
|
|
|
|
|
|
|
|
|
|
Secure Cookie Handshake
|
|
|
|
|
|
-----------------------
|
|
|
|
|
|
|
|
|
|
|
|
Akka remoting also allows you to specify a secure cookie that will be exchanged and ensured to be identical
|
|
|
|
|
|
in the connection handshake between the client and the server. If they are not identical then the client
|
|
|
|
|
|
will be refused to connect to the server.
|
|
|
|
|
|
|
|
|
|
|
|
The secure cookie can be any kind of string. But the recommended approach is to generate a cryptographically
|
|
|
|
|
|
secure cookie using this script ``$AKKA_HOME/scripts/generate_config_with_secure_cookie.sh`` or from code
|
|
|
|
|
|
using the ``akka.util.Crypt.generateSecureCookie()`` utility method.
|
|
|
|
|
|
|
|
|
|
|
|
You have to ensure that both the connecting client and the server have the same secure cookie as well
|
|
|
|
|
|
as the ``require-cookie`` option turned on.
|
|
|
|
|
|
|
|
|
|
|
|
Here is an example config::
|
|
|
|
|
|
|
2013-01-23 11:38:20 +01:00
|
|
|
|
akka.remote {
|
2012-08-20 17:04:20 +02:00
|
|
|
|
secure-cookie = "090A030E0F0A05010900000A0C0E0C0B03050D05"
|
|
|
|
|
|
require-cookie = on
|
2012-05-22 12:08:49 +02:00
|
|
|
|
}
|
2012-08-20 17:04:20 +02:00
|
|
|
|
|
|
|
|
|
|
SSL
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2013-01-23 11:38:20 +01:00
|
|
|
|
SSL can be used as the remote transport by adding ``akka.remote.netty.ssl``
|
|
|
|
|
|
to the ``enabled-transport`` configuration section. See a description of the settings
|
2013-04-15 09:26:51 +02:00
|
|
|
|
in the :ref:`remote-configuration-java` section.
|
2012-08-21 10:04:15 +02:00
|
|
|
|
|
2013-03-26 18:17:50 +01:00
|
|
|
|
The SSL support is implemented with Java Secure Socket Extension, please consult the offical
|
2012-08-21 10:04:15 +02:00
|
|
|
|
`Java Secure Socket Extension documentation <http://docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/JSSERefGuide.html>`_
|
|
|
|
|
|
and related resources for troubleshooting.
|
2013-03-26 18:17:50 +01:00
|
|
|
|
|
2012-08-20 17:04:20 +02:00
|
|
|
|
.. note::
|
|
|
|
|
|
|
2013-03-26 18:17:50 +01:00
|
|
|
|
When using SHA1PRNG on Linux it's recommended specify ``-Djava.security.egd=file:/dev/./urandom`` as argument
|
2012-08-20 17:04:20 +02:00
|
|
|
|
to the JVM to prevent blocking. It is NOT as secure because it reuses the seed.
|
2013-03-26 18:17:50 +01:00
|
|
|
|
Use '/dev/./urandom', not '/dev/urandom' as that doesn't work according to
|
2012-08-21 10:04:15 +02:00
|
|
|
|
`Bug ID: 6202721 <http://bugs.sun.com/view_bug.do?bug_id=6202721>`_.
|
2013-03-26 18:17:50 +01:00
|
|
|
|
|
2013-04-15 09:26:51 +02:00
|
|
|
|
.. _remote-configuration-java:
|
|
|
|
|
|
|
|
|
|
|
|
Remote Configuration
|
|
|
|
|
|
^^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
|
|
|
|
|
|
|
There are lots of configuration properties that are related to remoting in Akka. We refer to the following
|
|
|
|
|
|
reference file for more information:
|
|
|
|
|
|
|
|
|
|
|
|
.. literalinclude:: ../../../akka-remote/src/main/resources/reference.conf
|
|
|
|
|
|
:language: none
|
|
|
|
|
|
|
|
|
|
|
|
.. note::
|
|
|
|
|
|
|
|
|
|
|
|
Setting properties like the listening IP and port number programmatically is
|
|
|
|
|
|
best done by using something like the following:
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/remoting/RemoteDeploymentDocTestBase.java#programmatic
|