Remoting (Scala)
Loading

Remoting (Scala)

For an introduction of remoting capabilities of Akka please see Location Transparency.

Preparing your ActorSystem for Remoting

The Akka remoting is a separate jar file. Make sure that you have the following dependency in your project:

  1. "com.typesafe.akka" %% "akka-remote" % "2.1.4"

To enable remote capabilities in your Akka project you should, at a minimum, add the following changes to your application.conf file:

  1. akka {
  2. actor {
  3. provider = "akka.remote.RemoteActorRefProvider"
  4. }
  5. remote {
  6. transport = "akka.remote.netty.NettyRemoteTransport"
  7. netty {
  8. hostname = "127.0.0.1"
  9. port = 2552
  10. }
  11. }
  12. }

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
  • 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

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.

Remote Configuration

The example above only illustrates the bare minimum of properties you have to add to enable remoting. There are lots of more properties that are related to remoting in Akka. We refer to the following reference file for more information:

  1. #####################################
  2. # Akka Remote Reference Config File #
  3. #####################################
  4.  
  5. # This is the reference config file that contains all the default settings.
  6. # Make your edits/overrides in your application.conf.
  7.  
  8. # comments about akka.actor settings left out where they are already in akka-
  9. # actor.jar, because otherwise they would be repeated in config rendering.
  10.  
  11. akka {
  12.  
  13. actor {
  14.  
  15. serializers {
  16. proto = "akka.remote.serialization.ProtobufSerializer"
  17. daemon-create = "akka.remote.serialization.DaemonMsgCreateSerializer"
  18. }
  19.  
  20.  
  21. serialization-bindings {
  22. # Since com.google.protobuf.Message does not extend Serializable but
  23. # GeneratedMessage does, need to use the more specific one here in order
  24. # to avoid ambiguity
  25. "com.google.protobuf.GeneratedMessage" = proto
  26. "akka.remote.DaemonMsgCreate" = daemon-create
  27. }
  28.  
  29. deployment {
  30.  
  31. default {
  32.  
  33. # if this is set to a valid remote address, the named actor will be
  34. # deployed at that node e.g. "akka://sys@host:port"
  35. remote = ""
  36.  
  37. target {
  38.  
  39. # A list of hostnames and ports for instantiating the children of a
  40. # router
  41. # The format should be on "akka://sys@host:port", where:
  42. # - sys is the remote actor system name
  43. # - hostname can be either hostname or IP address the remote actor
  44. # should connect to
  45. # - port should be the port for the remote server on the other node
  46. # The number of actor instances to be spawned is still taken from the
  47. # nr-of-instances setting as for local routers; the instances will be
  48. # distributed round-robin among the given nodes.
  49. nodes = []
  50.  
  51. }
  52. }
  53. }
  54. }
  55.  
  56. remote {
  57.  
  58. # Which implementation of akka.remote.RemoteTransport to use
  59. # default is a TCP-based remote transport based on Netty
  60. transport = "akka.remote.netty.NettyRemoteTransport"
  61.  
  62. # Enable untrusted mode for full security of server managed actors, prevents
  63. # system messages to be send by clients, e.g. messages like 'Create',
  64. # 'Suspend', 'Resume', 'Terminate', 'Supervise', 'Link' etc.
  65. untrusted-mode = off
  66.  
  67. # Timeout for ACK of cluster operations, like checking actor out etc.
  68. remote-daemon-ack-timeout = 30s
  69.  
  70. # If this is "on", Akka will log all inbound messages at DEBUG level,
  71. # if off then they are not logged
  72. log-received-messages = off
  73.  
  74. # If this is "on", Akka will log all outbound messages at DEBUG level,
  75. # if off then they are not logged
  76. log-sent-messages = off
  77.  
  78. # If this is "on", Akka will log all RemoteLifeCycleEvents at the level
  79. # defined for each, if off then they are not logged Failures to deserialize
  80. # received messages also fall under this flag.
  81. log-remote-lifecycle-events = on
  82.  
  83. # Each property is annotated with (I) or (O) or (I&O), where I stands for
  84. # “inbound” and O for “outbound” connections. The NettyRemoteTransport always
  85. # starts the server role to allow inbound connections, and it starts active
  86. # client connections whenever sending to a destination which is not yet
  87. # connected; if configured it reuses inbound connections for replies, which
  88. # is called a passive client connection (i.e. from server to client).
  89. netty {
  90.  
  91. # (O) In case of increased latency / overflow how long should we wait
  92. # (blocking the sender) until we deem the send to be cancelled?
  93. # 0 means "never backoff", any positive number will indicate the time to
  94. # block at most.
  95. backoff-timeout = 0ms
  96.  
  97. # (I&O) Generate your own with the script availbale in
  98. # '$AKKA_HOME/scripts/generate_config_with_secure_cookie.sh' or using
  99. # 'akka.util.Crypt.generateSecureCookie'
  100. secure-cookie = ""
  101.  
  102. # (I) Should the remote server require that its peers share the same
  103. # secure-cookie (defined in the 'remote' section)?
  104. require-cookie = off
  105.  
  106. # (I) Reuse inbound connections for outbound messages
  107. use-passive-connections = on
  108.  
  109. # (I) EXPERIMENTAL If "<id.of.dispatcher>" then the specified dispatcher
  110. # will be used to accept inbound connections, and perform IO. If "" then
  111. # dedicated threads will be used.
  112. #
  113. # CAUTION: This might lead to the used dispatcher not shutting down properly!
  114. # - may prevent the JVM from shutting down normally
  115. # - may leak threads when shutting down an ActorSystem
  116. #
  117. use-dispatcher-for-io = ""
  118.  
  119. # (I) The hostname or ip to bind the remoting to,
  120. # InetAddress.getLocalHost.getHostAddress is used if empty
  121. hostname = ""
  122.  
  123. # (I) The default remote server port clients should connect to.
  124. # Default is 2552 (AKKA), use 0 if you want a random available port
  125. # This port needs to be unique for each actor system on the same machine.
  126. port = 2552
  127.  
  128. # (O) The address of a local network interface (IP Address) to bind to when
  129. # creating outbound connections. Set to "" or "auto" for automatic selection
  130. # of local address.
  131. outbound-local-address = "auto"
  132.  
  133. # (I&O) Increase this if you want to be able to send messages with large
  134. # payloads
  135. message-frame-size = 1 MiB
  136.  
  137. # (O) Sets the connectTimeoutMillis of all outbound connections,
  138. # i.e. how long a connect may take until it is timed out
  139. connection-timeout = 120s
  140.  
  141. # (I) Sets the size of the connection backlog
  142. backlog = 4096
  143.  
  144. # (I) Sets the SO_REUSE_ADDR flag, valid values are "on", "off" and "off-for-windows"
  145. # due to the following Windows bug: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4476378
  146. # "off-for-windows" of course means that it's "on" for all other platforms
  147. reuse-address = off-for-windows
  148.  
  149. # (I) Length in akka.time-unit how long core threads will be kept alive if
  150. # idling
  151. execution-pool-keepalive = 60s
  152.  
  153. # (I) Size in number of threads of the core pool of the remote execution
  154. # unit.
  155. # A value of 0 will turn this off, which is can lead to deadlocks under
  156. # some configurations!
  157. execution-pool-size = 4
  158.  
  159. # (I) Maximum channel size, 0 for off
  160. max-channel-memory-size = 0b
  161.  
  162. # (I) Maximum total size of all channels, 0 for off
  163. max-total-memory-size = 0b
  164.  
  165. # (I&O) Sets the high water mark for the in and outbound sockets,
  166. # set to 0b for platform default
  167. write-buffer-high-water-mark = 0b
  168.  
  169. # (I&O) Sets the low water mark for the in and outbound sockets,
  170. # set to 0b for platform default
  171. write-buffer-low-water-mark = 0b
  172.  
  173. # (I&O) Sets the send buffer size of the Sockets,
  174. # set to 0b for platform default
  175. send-buffer-size = 0b
  176.  
  177. # (I&O) Sets the receive buffer size of the Sockets,
  178. # set to 0b for platform default
  179. receive-buffer-size = 0b
  180.  
  181. # (O) Time between reconnect attempts for active clients
  182. reconnect-delay = 5s
  183.  
  184. # (O) Read inactivity period (lowest resolution is seconds)
  185. # after which active client connection is shutdown;
  186. # will be re-established in case of new communication requests.
  187. # A value of 0 will turn this feature off
  188. read-timeout = 0s
  189.  
  190. # (O) Write inactivity period (lowest resolution is seconds)
  191. # after which a heartbeat is sent across the wire.
  192. # A value of 0 will turn this feature off
  193. write-timeout = 10s
  194.  
  195. # (O) Inactivity period of both reads and writes (lowest resolution is
  196. # seconds) after which active client connection is shutdown; will be
  197. # re-established in case of new communication requests.
  198. # A value of 0 will turn this feature off
  199. all-timeout = 0s
  200.  
  201. # (O) Maximum time window that a client should try to reconnect for
  202. reconnection-time-window = 600s
  203.  
  204. ssl {
  205. # (I&O) Enable SSL/TLS encryption.
  206. # This must be enabled on both the client and server to work.
  207. enable = off
  208.  
  209. # (I) This is the Java Key Store used by the server connection
  210. key-store = "keystore"
  211.  
  212. # This password is used for decrypting the key store
  213. key-store-password = "changeme"
  214.  
  215. # (O) This is the Java Key Store used by the client connection
  216. trust-store = "truststore"
  217.  
  218. # This password is used for decrypting the trust store
  219. trust-store-password = "changeme"
  220.  
  221. # (I&O) Protocol to use for SSL encryption, choose from:
  222. # Java 6 & 7:
  223. # 'SSLv3', 'TLSv1'
  224. # Java 7:
  225. # 'TLSv1.1', 'TLSv1.2'
  226. protocol = "TLSv1"
  227.  
  228. # Example: ["TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_CBC_SHA"]
  229. # You need to install the JCE Unlimited Strength Jurisdiction Policy
  230. # Files to use AES 256.
  231. # More info here:
  232. # http://docs.oracle.com/javase/7/docs/technotes/guides/security/SunProviders.html#SunJCEProvider
  233. enabled-algorithms = ["TLS_RSA_WITH_AES_128_CBC_SHA"]
  234.  
  235. # Using /dev/./urandom is only necessary when using SHA1PRNG on Linux to
  236. # prevent blocking. It is NOT as secure because it reuses the seed.
  237. # '' => defaults to /dev/random or whatever is set in java.security for
  238. # example: securerandom.source=file:/dev/random
  239. # '/dev/./urandom' => NOT '/dev/urandom' as that doesn't work according
  240. # to: http://bugs.sun.com/view_bug.do?bug_id=6202721
  241. sha1prng-random-source = ""
  242.  
  243. # There are three options, in increasing order of security:
  244. # "" or SecureRandom => (default)
  245. # "SHA1PRNG" => Can be slow because of blocking issues on Linux
  246. # "AES128CounterSecureRNG" => fastest startup and based on AES encryption
  247. # algorithm
  248. # "AES256CounterSecureRNG"
  249. # The following use one of 3 possible seed sources, depending on
  250. # availability: /dev/random, random.org and SecureRandom (provided by Java)
  251. # "AES128CounterInetRNG"
  252. # "AES256CounterInetRNG" (Install JCE Unlimited Strength Jurisdiction
  253. # Policy Files first)
  254. # Setting a value here may require you to supply the appropriate cipher
  255. # suite (see enabled-algorithms section above)
  256. random-number-generator = ""
  257. }
  258.  
  259. # (I&O) Used to configure the number of I/O worker threads on server sockets
  260. server-socket-worker-pool {
  261. # Min number of threads to cap factor-based number to
  262. pool-size-min = 2
  263.  
  264. # The pool size factor is used to determine thread pool size
  265. # using the following formula: ceil(available processors * factor).
  266. # Resulting size is then bounded by the pool-size-min and
  267. # pool-size-max values.
  268. pool-size-factor = 1.0
  269.  
  270. # Max number of threads to cap factor-based number to
  271. pool-size-max = 8
  272. }
  273.  
  274. # (I&O) Used to configure the number of I/O worker threads on client sockets
  275. client-socket-worker-pool {
  276. # Min number of threads to cap factor-based number to
  277. pool-size-min = 2
  278.  
  279. # The pool size factor is used to determine thread pool size
  280. # using the following formula: ceil(available processors * factor).
  281. # Resulting size is then bounded by the pool-size-min and
  282. # pool-size-max values.
  283. pool-size-factor = 1.0
  284.  
  285. # Max number of threads to cap factor-based number to
  286. pool-size-max = 8
  287. }
  288. }
  289. }
  290. }

Note

Setting properties like the listening IP and port number programmatically is best done by using something like the following:

  1. ConfigFactory.parseString("akka.remote.netty.hostname=\"1.2.3.4\"")
  2. .withFallback(ConfigFactory.load());

Types of Remote Interaction

Akka has two ways of using remoting:

  • Lookup : used to look up an actor on a remote node with actorFor(path)
  • Creation : used to create an actor on a remote node with actorOf(Props(...), actorName)

In the next sections the two alternatives are described in detail.

Looking up Remote Actors

actorFor(path) will obtain an ActorRef to an Actor on a remote node, e.g.:

  1. val actor = context.actorFor("akka://actorSystemName@10.0.0.1:2552/user/actorName")

As you can see from the example above the following pattern is used to find an ActorRef on a remote node:

  1. akka://<actor system>@<hostname>:<port>/<actor path>

Once you obtained a reference to the actor you can interact with it they same way you would with a local actor, e.g.:

  1. actor ! "Pretty awesome feature"

Note

For more details on how actor addresses and paths are formed and used, please refer to Actor References, Paths and Addresses.

Creating Actors Remotely

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):

  1. akka {
  2. actor {
  3. deployment {
  4. /sampleActor {
  5. remote = "akka://sampleActorSystem@127.0.0.1:2553"
  6. }
  7. }
  8. }
  9. }

The configuration above instructs Akka to react when an actor with path /sampleActor is created, i.e. using system.actorOf(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.

Once you have configured the properties above you would do the following in code:

  1. val actor = system.actorOf(Props[SampleActor], "sampleActor")
  2. actor ! "Pretty slick"

The actor class SampleActor has to be available to the runtimes using it, i.e. the classloader of the actor systems has to have a JAR containing the class.

Note

In order to ensure serializability of Props when passing constructor arguments to the actor being created, do not make the factory an inner class: this will inherently capture a reference to its enclosing object, which in most cases is not serializable. It is best to create a factory method in the companion object of the actor’s class.

Note

You can use asterisks as wildcard matches for the actor paths, 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.

Warning

Caveat: Remote deployment ties both systems together in a tight fashion, where it may become impossible to shut down one system after the other has become unreachable. This is due to a missing feature—which will be part of the clustering support—that hooks up network failure detection with DeathWatch. If you want to avoid this strong coupling, do not remote-deploy but send Props to a remotely looked-up actor and have that create a child, returning the resulting actor reference.

Warning

Caveat: Akka Remoting does not trigger Death Watch for lost connections.

Programmatic Remote Deployment

To allow dynamically deployed systems, it is also possible to include deployment configuration in the 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:

  1. import akka.actor.{ Props, Deploy, Address, AddressFromURIString }
  2. import akka.remote.RemoteScope

and a remote address like this:

  1. val one = AddressFromURIString("akka://sys@host:1234")
  2. val two = Address("akka", "sys", "host", 1234) // this gives the same

you can advise the system to create a child on that remote node like so:

  1. val ref = system.actorOf(Props[SampleActor].
  2. withDeploy(Deploy(scope = RemoteScope(address))))

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 Serialization (Scala)

Routers with Remote Destinations

It is absolutely feasible to combine remoting with Routing (Scala). This is also done via configuration:

  1. akka {
  2. actor {
  3. deployment {
  4. /serviceA/aggregation {
  5. router = "round-robin"
  6. nr-of-instances = 10
  7. target {
  8. nodes = ["akka://app@10.0.0.2:2552", "akka://app@10.0.0.3:2552"]
  9. }
  10. }
  11. }
  12. }
  13. }

This configuration setting will clone the actor “aggregation” 10 times and deploy it evenly distributed across the two given target nodes.

Description of the Remoting Sample

There is a more extensive remote example that comes with the Akka distribution. Please have a look here for more information: Remote Sample 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):

  1. akka {
  2.  
  3. actor {
  4. provider = "akka.remote.RemoteActorRefProvider"
  5. }
  6.  
  7. remote {
  8. netty {
  9. hostname = "127.0.0.1"
  10. }
  11. }
  12. }

This enables the remoting by installing the 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

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):

  1. calculator {
  2. include "common"
  3.  
  4. akka {
  5. remote.netty.port = 2552
  6. }
  7. }

Then the actor must be created. For all code which follows, assume these imports:

  1. import com.typesafe.config.ConfigFactory
  2. import akka.actor.{ ActorRef, Props, Actor, ActorSystem }

The actor doing the work will be this one:

  1. class SimpleCalculatorActor extends Actor {
  2. def receive = {
  3. case Add(n1, n2)
  4. println("Calculating %d + %d".format(n1, n2))
  5. sender ! AddResult(n1, n2, n1 + n2)
  6. case Subtract(n1, n2)
  7. println("Calculating %d - %d".format(n1, n2))
  8. sender ! SubtractResult(n1, n2, n1 - n2)
  9. }
  10. }

and we start it within an actor system using the above configuration

  1. val system = ActorSystem("CalculatorApplication",
  2. ConfigFactory.load.getConfig("calculator"))
  3. val actor = system.actorOf(Props[SimpleCalculatorActor], "simpleCalculator")

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).

  1. remotelookup {
  2. include "common"
  3.  
  4. akka {
  5. remote.netty.port = 2553
  6. }
  7. }

The actor which will query the calculator is a quite simple one for demonstration purposes

  1. class LookupActor extends Actor {
  2. def receive = {
  3. case (actor: ActorRef, op: MathOp) actor ! op
  4. case result: MathResult result match {
  5. case AddResult(n1, n2, r)
  6. println("Add result: %d + %d = %d".format(n1, n2, r))
  7. case SubtractResult(n1, n2, r)
  8. println("Sub result: %d - %d = %d".format(n1, n2, r))
  9. }
  10. }
  11. }

and it is created from an actor system using the aforementioned client’s config.

  1. val system =
  2. ActorSystem("LookupApplication", ConfigFactory.load.getConfig("remotelookup"))
  3. val actor = system.actorOf(Props[LookupActor], "lookupActor")
  4. val remoteActor = system.actorFor(
  5. "akka://CalculatorApplication@127.0.0.1:2552/user/simpleCalculator")
  6.  
  7. def doSomething(op: MathOp) = {
  8. actor ! (remoteActor, op)
  9. }

Requests which come in via doSomething will be sent to the client actor along with the reference which was looked up earlier. Observe how the actor system name using in actorFor matches the remote system’s name, as do IP 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):

  1. remotecreation {
  2. include "common"
  3.  
  4. akka {
  5. actor {
  6. deployment {
  7. /advancedCalculator {
  8. remote = "akka://CalculatorApplication@127.0.0.1:2552"
  9. }
  10. }
  11. }
  12.  
  13. remote.netty.port = 2554
  14. }
  15. }

For all code which follows, assume these imports:

  1. import com.typesafe.config.ConfigFactory
  2. import akka.actor.{ ActorRef, Props, Actor, ActorSystem }

The client actor looks like in the previous example

  1. class CreationActor extends Actor {
  2. def receive = {
  3. case (actor: ActorRef, op: MathOp) actor ! op
  4. case result: MathResult result match {
  5. case MultiplicationResult(n1, n2, r)
  6. println("Mul result: %d * %d = %d".format(n1, n2, r))
  7. case DivisionResult(n1, n2, r)
  8. println("Div result: %.0f / %d = %.2f".format(n1, n2, r))
  9. }
  10. }
  11. }

but the setup uses only actorOf:

  1. val system =
  2. ActorSystem("RemoteCreation", ConfigFactory.load.getConfig("remotecreation"))
  3. val localActor = system.actorOf(Props[CreationActor], "creationActor")
  4. val remoteActor =
  5. system.actorOf(Props[AdvancedCalculatorActor], "advancedCalculator")
  6.  
  7. def doSomething(op: MathOp) = {
  8. localActor ! (remoteActor, op)
  9. }

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.

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

To subscribe to any outbound-related events, subscribe to RemoteClientLifeCycleEvent To subscribe to any inbound-related events, subscribe to RemoteServerLifeCycleEvent To subscribe to any remote events, subscribe to RemoteLifeCycleEvent

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

In order to switch off the logging, set akka.remote.log-remote-lifecycle-events = off in your application.conf.

To intercept when an outbound connection is disconnected, you listen to RemoteClientDisconnected which holds the transport used (RemoteTransport) and the outbound address that was disconnected (Address).

To intercept when an outbound connection is connected, you listen to RemoteClientConnected which holds the transport used (RemoteTransport) and the outbound address that was connected to (Address).

To intercept when an outbound client is started you listen to RemoteClientStarted which holds the transport used (RemoteTransport) and the outbound address that it is connected to (Address).

To intercept when an outbound client is shut down you listen to RemoteClientShutdown which holds the transport used (RemoteTransport) and the outbound address that it was connected to (Address).

For general outbound-related errors, that do not classify as any of the others, you can listen to RemoteClientError, which holds the cause (Throwable), the transport used (RemoteTransport) and the outbound address (Address).

To intercept when an inbound server is started (typically only once) you listen to RemoteServerStarted which holds the transport that it will use (RemoteTransport).

To intercept when an inbound server is shut down (typically only once) you listen to RemoteServerShutdown which holds the transport that it used (RemoteTransport).

To intercept when an inbound connection has been established you listen to RemoteServerClientConnected which holds the transport used (RemoteTransport) and optionally the address that connected (Option[Address]).

To intercept when an inbound connection has been disconnected you listen to RemoteServerClientDisconnected which holds the transport used (RemoteTransport) and optionally the address that disconnected (Option[Address]).

To intercept when an inbound remote client has been closed you listen to RemoteServerClientClosed which holds the transport used (RemoteTransport) and optionally the address of the remote client that was closed (Option[Address]).

Remote Security

Akka provides a couple of ways to enhance security between remote nodes (client/server):

  • Untrusted Mode
  • Security Cookie Handshake

Untrusted Mode

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 PoisonPill to the system guardian, shutting that system down. This is not always desired, and it can be disabled with the following setting:

  1. akka.remote.untrusted-mode = on

This disallows sending of system messages (actor life-cycle commands, DeathWatch, etc.) and any message extending 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). PossiblyHarmful covers the predefined messages like PoisonPill and Kill, but it can also be added as a marker trait to user-defined messages.

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(), PoisonPill, Kill
  • sending any message which extends from the PossiblyHarmful marker interface, which includes 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 ActorRef (they can be exchanged safely between actor systems within the same JVM), you can restrict the messages on this interface by marking them PossiblyHarmful so that a client cannot forge them.

SSL

SSL can be used for the remote transport by activating the akka.remote.netty.ssl configuration section. See description of the settings in the Remote Configuration.

The SSL support is implemented with Java Secure Socket Extension, please consult the offical Java Secure Socket Extension documentation and related resources for troubleshooting.

Note

When using SHA1PRNG on Linux it's recommended specify -Djava.security.egd=file:/dev/./urandom as argument to the JVM to prevent blocking. It is NOT as secure because it reuses the seed. Use '/dev/./urandom', not '/dev/urandom' as that doesn't work according to Bug ID: 6202721.