2011-12-15 18:19:40 +01:00
|
|
|
|
|
|
|
|
|
|
.. _routing-scala:
|
|
|
|
|
|
|
2013-04-19 13:21:15 +02:00
|
|
|
|
Routing
|
2013-09-19 08:00:05 +02:00
|
|
|
|
=======
|
2011-05-06 10:09:16 +02:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
Messages can be sent via a router to efficiently route them to destination actors, known as
|
|
|
|
|
|
its *routees*. A ``Router`` can be used inside or outside of an actor, and you can manage the
|
|
|
|
|
|
routees yourselves or use a self contained router actor with configuration capabilities.
|
2011-04-09 19:55:46 -06:00
|
|
|
|
|
2013-01-31 21:48:03 +13:00
|
|
|
|
Different routing strategies can be used, according to your application's needs. Akka comes with
|
|
|
|
|
|
several useful routing strategies right out of the box. But, as you will see in this chapter, it is
|
|
|
|
|
|
also possible to :ref:`create your own <custom-router-scala>`.
|
|
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. _simple-router-scala:
|
2011-04-09 19:55:46 -06:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
A Simple Router
|
|
|
|
|
|
^^^^^^^^^^^^^^^
|
2011-04-09 19:55:46 -06:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
The following example illustrates how to use a ``Router`` and manage the routees from within an actor.
|
2012-01-05 17:59:19 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#router-in-actor
|
2013-01-31 21:48:03 +13:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
We create a ``Router`` and specify that it should use ``RoundRobinRoutingLogic`` when routing the
|
|
|
|
|
|
messages to the routees.
|
2013-01-31 21:48:03 +13:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
The routing logic shipped with Akka are:
|
2013-01-31 21:48:03 +13:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
* ``akka.routing.RoundRobinRoutingLogic``
|
|
|
|
|
|
* ``akka.routing.RandomRoutingLogic``
|
|
|
|
|
|
* ``akka.routing.SmallestMailboxRoutingLogic``
|
|
|
|
|
|
* ``akka.routing.BroadcastRoutingLogic``
|
|
|
|
|
|
* ``akka.routing.ScatterGatherFirstCompletedRoutingLogic``
|
2014-06-05 21:56:05 +02:00
|
|
|
|
* ``akka.routing.TailChoppingRoutingLogic``
|
2013-09-19 08:00:05 +02:00
|
|
|
|
* ``akka.routing.ConsistentHashingRoutingLogic``
|
2013-01-31 21:48:03 +13:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
We create the routees as ordinary child actors wrapped in ``ActorRefRoutee``. We watch
|
|
|
|
|
|
the routees to be able to replace them if they are terminated.
|
2013-01-31 21:48:03 +13:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
Sending messages via the router is done with the ``route`` method, as is done for the ``Work`` messages
|
|
|
|
|
|
in the example above.
|
2013-01-31 21:48:03 +13:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
The ``Router`` is immutable and the ``RoutingLogic`` is thread safe; meaning that they can also be used
|
|
|
|
|
|
outside of actors.
|
2013-01-31 21:48:03 +13:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. note::
|
2013-01-31 21:48:03 +13:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
In general, any message sent to a router will be sent onwards to its routees, but there is one exception.
|
2016-07-18 17:33:09 +09:00
|
|
|
|
The special :ref:`broadcast-messages-scala` will send to *all* of a router's routees.
|
|
|
|
|
|
However, do not use :ref:`broadcast-messages-scala` when you use :ref:`balancing-pool-scala` for routees
|
|
|
|
|
|
as described in :ref:`router-special-messages-scala`.
|
|
|
|
|
|
|
2012-01-05 17:59:19 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
A Router Actor
|
|
|
|
|
|
^^^^^^^^^^^^^^
|
2012-01-05 17:59:19 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
A router can also be created as a self contained actor that manages the routees itself and
|
|
|
|
|
|
loads routing logic and other settings from configuration.
|
2012-01-05 17:59:19 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
This type of router actor comes in two distinct flavors:
|
2012-01-05 17:59:19 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
* Pool - The router creates routees as child actors and removes them from the router if they
|
|
|
|
|
|
terminate.
|
|
|
|
|
|
|
|
|
|
|
|
* Group - The routee actors are created externally to the router and the router sends
|
|
|
|
|
|
messages to the specified path using actor selection, without watching for termination.
|
2012-01-05 17:59:19 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
The settings for a router actor can be defined in configuration or programmatically.
|
|
|
|
|
|
Although router actors can be defined in the configuration file, they must still be created
|
|
|
|
|
|
programmatically, i.e. you cannot make a router through external configuration alone.
|
|
|
|
|
|
If you define the router actor in the configuration file then these settings will be used
|
|
|
|
|
|
instead of any programmatically provided parameters.
|
2013-01-31 21:48:03 +13:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
You send messages to the routees via the router actor in the same way as for ordinary actors,
|
|
|
|
|
|
i.e. via its ``ActorRef``. The router actor forwards messages onto its routees without changing
|
|
|
|
|
|
the original sender. When a routee replies to a routed message, the reply will be sent to the
|
|
|
|
|
|
original sender, not to the router actor.
|
2012-01-05 17:59:19 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. note::
|
2012-01-05 17:59:19 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
In general, any message sent to a router will be sent onwards to its routees, but there are a
|
|
|
|
|
|
few exceptions. These are documented in the :ref:`router-special-messages-scala` section below.
|
2012-07-13 11:50:46 +02:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
Pool
|
|
|
|
|
|
----
|
2012-07-13 11:50:46 +02:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
The following code and configuration snippets show how to create a :ref:`round-robin
|
|
|
|
|
|
<round-robin-router-scala>` router that forwards messages to five ``Worker`` routees. The
|
|
|
|
|
|
routees will be created as the router's children.
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#config-round-robin-pool
|
2012-05-22 13:07:05 +02:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#round-robin-pool-1
|
|
|
|
|
|
|
|
|
|
|
|
Here is the same example, but with the router configuration provided programmatically instead of
|
|
|
|
|
|
from configuration.
|
2012-01-05 17:59:19 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#round-robin-pool-2
|
2012-01-05 17:59:19 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
Remote Deployed Routees
|
|
|
|
|
|
***********************
|
2012-01-05 17:59:19 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
In addition to being able to create local actors as routees, you can instruct the router to
|
|
|
|
|
|
deploy its created children on a set of remote hosts. Routees will be deployed in round-robin
|
|
|
|
|
|
fashion. In order to deploy routees remotely, wrap the router configuration in a
|
|
|
|
|
|
``RemoteRouterConfig``, attaching the remote addresses of the nodes to deploy to. Remote
|
|
|
|
|
|
deployment requires the ``akka-remote`` module to be included in the classpath.
|
2012-01-05 17:59:19 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#remoteRoutees
|
2012-01-05 17:59:19 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
Senders
|
|
|
|
|
|
*******
|
2011-04-09 19:55:46 -06:00
|
|
|
|
|
2013-01-31 21:48:03 +13:00
|
|
|
|
By default, when a routee sends a message, it will :ref:`implicitly set itself as the sender
|
|
|
|
|
|
<actors-tell-sender-scala>`.
|
2012-02-21 15:37:51 +01:00
|
|
|
|
|
2013-01-31 21:48:03 +13:00
|
|
|
|
.. includecode:: code/docs/actor/ActorDocSpec.scala#reply-without-sender
|
2012-02-21 15:37:51 +01:00
|
|
|
|
|
2013-01-31 21:48:03 +13:00
|
|
|
|
However, it is often useful for routees to set the *router* as a sender. For example, you might want
|
|
|
|
|
|
to set the router as the sender if you want to hide the details of the routees behind the router.
|
|
|
|
|
|
The following code snippet shows how to set the parent router as sender.
|
2012-02-21 15:37:51 +01:00
|
|
|
|
|
2013-01-31 21:48:03 +13:00
|
|
|
|
.. includecode:: code/docs/actor/ActorDocSpec.scala#reply-with-sender
|
2012-02-06 12:18:08 +01:00
|
|
|
|
|
|
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
Supervision
|
|
|
|
|
|
***********
|
2012-02-06 12:18:08 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
Routees that are created by a pool router will be created as the router's children. The router is
|
|
|
|
|
|
therefore also the children's supervisor.
|
2012-02-06 12:18:08 +01:00
|
|
|
|
|
2013-01-31 21:48:03 +13:00
|
|
|
|
The supervision strategy of the router actor can be configured with the
|
2013-09-19 08:00:05 +02:00
|
|
|
|
``supervisorStrategy`` property of the Pool. If no configuration is provided, routers default
|
2013-01-31 21:48:03 +13:00
|
|
|
|
to a strategy of “always escalate”. This means that errors are passed up to the router's supervisor
|
|
|
|
|
|
for handling. The router's supervisor will decide what to do about any errors.
|
2012-02-06 12:18:08 +01:00
|
|
|
|
|
2013-01-31 21:48:03 +13:00
|
|
|
|
Note the router's supervisor will treat the error as an error with the router itself. Therefore a
|
|
|
|
|
|
directive to stop or restart will cause the router *itself* to stop or restart. The router, in
|
|
|
|
|
|
turn, will cause its children to stop and restart.
|
2012-02-18 22:15:39 +01:00
|
|
|
|
|
2013-01-31 21:48:03 +13:00
|
|
|
|
It should be mentioned that the router's restart behavior has been overridden so that a restart,
|
|
|
|
|
|
while still re-creating the children, will still preserve the same number of actors in the pool.
|
2012-02-18 22:15:39 +01:00
|
|
|
|
|
2013-07-01 15:44:01 +02:00
|
|
|
|
This means that if you have not specified :meth:`supervisorStrategy` of the router or its parent a
|
|
|
|
|
|
failure in a routee will escalate to the parent of the router, which will by default restart the router,
|
|
|
|
|
|
which will restart all routees (it uses Escalate and does not stop routees during restart). The reason
|
|
|
|
|
|
is to make the default behave such that adding :meth:`.withRouter` to a child’s definition does not
|
|
|
|
|
|
change the supervision strategy applied to the child. This might be an inefficiency that you can avoid
|
|
|
|
|
|
by specifying the strategy when defining the router.
|
|
|
|
|
|
|
2012-02-18 22:15:39 +01:00
|
|
|
|
Setting the strategy is easily done:
|
|
|
|
|
|
|
2012-09-21 10:47:58 +02:00
|
|
|
|
.. includecode:: ../../../akka-actor-tests/src/test/scala/akka/routing/RoutingSpec.scala#supervision
|
2012-02-18 22:15:39 +01:00
|
|
|
|
|
2013-01-31 21:48:03 +13:00
|
|
|
|
.. _note-router-terminated-children-scala:
|
|
|
|
|
|
|
2012-04-25 11:56:41 +02:00
|
|
|
|
.. note::
|
|
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
If the child of a pool router terminates, the pool router will not automatically spawn
|
|
|
|
|
|
a new child. In the event that all children of a pool router have terminated the
|
2013-04-08 13:19:44 +02:00
|
|
|
|
router will terminate itself unless it is a dynamic router, e.g. using
|
|
|
|
|
|
a resizer.
|
2012-04-25 11:56:41 +02:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
Group
|
|
|
|
|
|
-----
|
|
|
|
|
|
|
|
|
|
|
|
Sometimes, rather than having the router actor create its routees, it is desirable to create routees
|
|
|
|
|
|
separately and provide them to the router for its use. You can do this by passing an
|
|
|
|
|
|
paths of the routees to the router's configuration. Messages will be sent with ``ActorSelection``
|
|
|
|
|
|
to these paths.
|
|
|
|
|
|
|
|
|
|
|
|
The example below shows how to create a router by providing it with the path strings of three
|
|
|
|
|
|
routee actors.
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#config-round-robin-group
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#round-robin-group-1
|
|
|
|
|
|
|
|
|
|
|
|
Here is the same example, but with the router configuration provided programmatically instead of
|
|
|
|
|
|
from configuration.
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#round-robin-group-2
|
|
|
|
|
|
|
|
|
|
|
|
The routee actors are created externally from the router:
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#create-workers
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#create-worker-actors
|
|
|
|
|
|
|
|
|
|
|
|
The paths may contain protocol and address information for actors running on remote hosts.
|
|
|
|
|
|
Remoting requires the ``akka-remote`` module to be included in the classpath.
|
|
|
|
|
|
|
2014-02-11 14:48:24 +01:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#config-remote-round-robin-group
|
|
|
|
|
|
|
2011-12-15 15:28:21 +01:00
|
|
|
|
Router usage
|
|
|
|
|
|
^^^^^^^^^^^^
|
2011-04-09 19:55:46 -06:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
In this section we will describe how to create the different types of router actors.
|
2011-04-09 19:55:46 -06:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
The router actors in this section are created from within a top level actor named ``parent``.
|
|
|
|
|
|
Note that deployment paths in the configuration starts with ``/parent/`` followed by the name
|
|
|
|
|
|
of the router actor.
|
2011-04-09 19:55:46 -06:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#create-parent
|
2011-04-09 19:55:46 -06:00
|
|
|
|
|
2013-01-31 21:48:03 +13:00
|
|
|
|
.. _round-robin-router-scala:
|
2011-04-09 19:55:46 -06:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
RoundRobinPool and RoundRobinGroup
|
|
|
|
|
|
----------------------------------
|
|
|
|
|
|
|
2011-12-15 15:28:21 +01:00
|
|
|
|
Routes in a `round-robin <http://en.wikipedia.org/wiki/Round-robin>`_ fashion to its routees.
|
|
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
RoundRobinPool defined in configuration:
|
2011-12-15 15:28:21 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#config-round-robin-pool
|
2011-12-15 15:28:21 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#round-robin-pool-1
|
2011-04-09 19:55:46 -06:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
RoundRobinPool defined in code:
|
2011-04-09 19:55:46 -06:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#round-robin-pool-2
|
2011-04-09 19:55:46 -06:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
RoundRobinGroup defined in configuration:
|
2012-09-11 15:10:33 +02:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#config-round-robin-group
|
2012-09-11 15:10:33 +02:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#round-robin-group-1
|
|
|
|
|
|
|
|
|
|
|
|
RoundRobinGroup defined in code:
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala
|
|
|
|
|
|
:include: paths,round-robin-group-2
|
2011-04-09 19:55:46 -06:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
RandomPool and RandomGroup
|
|
|
|
|
|
--------------------------
|
2011-12-15 15:28:21 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
This router type selects one of its routees randomly for each message.
|
2011-04-09 19:55:46 -06:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
RandomPool defined in configuration:
|
2011-04-09 19:55:46 -06:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#config-random-pool
|
2011-12-15 15:28:21 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#random-pool-1
|
2011-12-15 15:28:21 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
RandomPool defined in code:
|
2012-09-11 15:10:33 +02:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#random-pool-2
|
2012-09-11 15:10:33 +02:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
RandomGroup defined in configuration:
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#config-random-group
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#random-group-1
|
|
|
|
|
|
|
|
|
|
|
|
RandomGroup defined in code:
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala
|
|
|
|
|
|
:include: paths,random-group-2
|
|
|
|
|
|
|
2014-01-10 17:14:10 +01:00
|
|
|
|
.. _balancing-pool-scala:
|
|
|
|
|
|
|
|
|
|
|
|
BalancingPool
|
|
|
|
|
|
-------------
|
|
|
|
|
|
|
|
|
|
|
|
A Router that will try to redistribute work from busy routees to idle routees.
|
|
|
|
|
|
All routees share the same mailbox.
|
|
|
|
|
|
|
2016-03-09 21:49:38 +01:00
|
|
|
|
.. note::
|
|
|
|
|
|
|
|
|
|
|
|
The BalancingPool has the property that its routees do not have truly distinct
|
|
|
|
|
|
identity: they have different names, but talking to them will not end up at the
|
|
|
|
|
|
right actor in most cases. Therefore you cannot use it for workflows that
|
|
|
|
|
|
require state to be kept within the routee, you would in this case have to
|
|
|
|
|
|
include the whole state in the messages.
|
|
|
|
|
|
|
|
|
|
|
|
With a `SmallestMailboxPool`_ you can have a vertically scaling service that
|
|
|
|
|
|
can interact in a stateful fashion with other services in the back-end before
|
|
|
|
|
|
replying to the original client. The other advantage is that it does not place
|
|
|
|
|
|
a restriction on the message queue implementation as BalancingPool does.
|
|
|
|
|
|
|
2016-07-18 17:33:09 +09:00
|
|
|
|
.. note::
|
|
|
|
|
|
Do not use :ref:`broadcast-messages-scala` when you use :ref:`balancing-pool-scala` for routers.
|
|
|
|
|
|
as described in :ref:`router-special-messages-scala`,
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-01-10 17:14:10 +01:00
|
|
|
|
BalancingPool defined in configuration:
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#config-balancing-pool
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#balancing-pool-1
|
|
|
|
|
|
|
|
|
|
|
|
BalancingPool defined in code:
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#balancing-pool-2
|
|
|
|
|
|
|
|
|
|
|
|
Addition configuration for the balancing dispatcher, which is used by the pool,
|
|
|
|
|
|
can be configured in the ``pool-dispatcher`` section of the router deployment
|
|
|
|
|
|
configuration.
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#config-balancing-pool2
|
|
|
|
|
|
|
2015-06-03 13:14:57 +02:00
|
|
|
|
The ``BalancingPool`` automatically uses a special ``BalancingDispatcher`` for its
|
2015-11-04 13:49:30 +01:00
|
|
|
|
routees - disregarding any dispatcher that is set on the routee Props object.
|
2015-06-03 13:14:57 +02:00
|
|
|
|
This is needed in order to implement the balancing semantics via
|
|
|
|
|
|
sharing the same mailbox by all the routees.
|
|
|
|
|
|
|
|
|
|
|
|
While it is not possible to change the dispatcher used by the routees, it is possible
|
|
|
|
|
|
to fine tune the used *executor*. By default the ``fork-join-dispatcher`` is used and
|
|
|
|
|
|
can be configured as explained in :ref:`dispatchers-scala`. In situations where the
|
|
|
|
|
|
routees are expected to perform blocking operations it may be useful to replace it
|
|
|
|
|
|
with a ``thread-pool-executor`` hinting the number of allocated threads explicitly:
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#config-balancing-pool3
|
|
|
|
|
|
|
2014-01-10 17:14:10 +01:00
|
|
|
|
There is no Group variant of the BalancingPool.
|
2013-09-19 08:00:05 +02:00
|
|
|
|
|
|
|
|
|
|
SmallestMailboxPool
|
|
|
|
|
|
-------------------
|
|
|
|
|
|
|
|
|
|
|
|
A Router that tries to send to the non-suspended child routee with fewest messages in mailbox.
|
2012-01-11 13:56:38 +01:00
|
|
|
|
The selection is done in this order:
|
|
|
|
|
|
|
|
|
|
|
|
* pick any idle routee (not processing message) with empty mailbox
|
|
|
|
|
|
* pick any routee with empty mailbox
|
|
|
|
|
|
* pick routee with fewest pending messages in mailbox
|
|
|
|
|
|
* pick any remote routee, remote actors are consider lowest priority,
|
|
|
|
|
|
since their mailbox size is unknown
|
|
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
SmallestMailboxPool defined in configuration:
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#config-smallest-mailbox-pool
|
2012-01-11 13:56:38 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#smallest-mailbox-pool-1
|
2012-01-11 13:56:38 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
SmallestMailboxPool defined in code:
|
2012-09-11 15:10:33 +02:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#smallest-mailbox-pool-2
|
2012-09-11 15:10:33 +02:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
There is no Group variant of the SmallestMailboxPool because the size of the mailbox
|
|
|
|
|
|
and the internal dispatching state of the actor is not practically available from the paths
|
|
|
|
|
|
of the routees.
|
|
|
|
|
|
|
|
|
|
|
|
BroadcastPool and BroadcastGroup
|
|
|
|
|
|
--------------------------------
|
2012-09-11 15:10:33 +02:00
|
|
|
|
|
2011-12-15 15:28:21 +01:00
|
|
|
|
A broadcast router forwards the message it receives to *all* its routees.
|
2011-04-09 19:55:46 -06:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
BroadcastPool defined in configuration:
|
2011-04-09 19:55:46 -06:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#config-broadcast-pool
|
2011-04-09 19:55:46 -06:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#broadcast-pool-1
|
2011-12-15 15:28:21 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
BroadcastPool defined in code:
|
2011-04-09 19:55:46 -06:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#broadcast-pool-2
|
2011-04-09 19:55:46 -06:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
BroadcastGroup defined in configuration:
|
2012-09-11 15:10:33 +02:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#config-broadcast-group
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#broadcast-group-1
|
|
|
|
|
|
|
|
|
|
|
|
BroadcastGroup defined in code:
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala
|
|
|
|
|
|
:include: paths,broadcast-group-2
|
2012-09-11 15:10:33 +02:00
|
|
|
|
|
2013-01-31 21:48:03 +13:00
|
|
|
|
.. note::
|
|
|
|
|
|
|
|
|
|
|
|
Broadcast routers always broadcast *every* message to their routees. If you do not want to
|
|
|
|
|
|
broadcast every message, then you can use a non-broadcasting router and use
|
|
|
|
|
|
:ref:`broadcast-messages-scala` as needed.
|
|
|
|
|
|
|
2012-09-11 15:10:33 +02:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
ScatterGatherFirstCompletedPool and ScatterGatherFirstCompletedGroup
|
|
|
|
|
|
--------------------------------------------------------------------
|
2011-04-09 19:55:46 -06:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
The ScatterGatherFirstCompletedRouter will send the message on to all its routees.
|
|
|
|
|
|
It then waits for first reply it gets back. This result will be sent back to original sender.
|
|
|
|
|
|
Other replies are discarded.
|
2011-04-09 19:55:46 -06:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
It is expecting at least one reply within a configured duration, otherwise it will reply with
|
|
|
|
|
|
``akka.pattern.AskTimeoutException`` in a ``akka.actor.Status.Failure``.
|
2011-04-09 19:55:46 -06:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
ScatterGatherFirstCompletedPool defined in configuration:
|
2011-04-09 19:55:46 -06:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#config-scatter-gather-pool
|
2011-12-15 15:28:21 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#scatter-gather-pool-1
|
2011-04-09 19:55:46 -06:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
ScatterGatherFirstCompletedPool defined in code:
|
2012-09-11 15:10:33 +02:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#scatter-gather-pool-2
|
2012-09-11 15:10:33 +02:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
ScatterGatherFirstCompletedGroup defined in configuration:
|
2012-09-11 15:10:33 +02:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#config-scatter-gather-group
|
2012-09-11 15:10:33 +02:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#scatter-gather-group-1
|
|
|
|
|
|
|
|
|
|
|
|
ScatterGatherFirstCompletedGroup defined in code:
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala
|
|
|
|
|
|
:include: paths,scatter-gather-group-2
|
|
|
|
|
|
|
2014-06-05 21:56:05 +02:00
|
|
|
|
TailChoppingPool and TailChoppingGroup
|
|
|
|
|
|
--------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
The TailChoppingRouter will first send the message to one, randomly picked, routee
|
2015-11-04 13:49:30 +01:00
|
|
|
|
and then after a small delay to a second routee (picked randomly from the remaining routees) and so on.
|
2014-06-05 21:56:05 +02:00
|
|
|
|
It waits for first reply it gets back and forwards it back to original sender. Other replies are discarded.
|
|
|
|
|
|
|
|
|
|
|
|
The goal of this router is to decrease latency by performing redundant queries to multiple routees, assuming that
|
|
|
|
|
|
one of the other actors may still be faster to respond than the initial one.
|
|
|
|
|
|
|
|
|
|
|
|
This optimisation was described nicely in a blog post by Peter Bailis:
|
|
|
|
|
|
`Doing redundant work to speed up distributed queries <http://www.bailis.org/blog/doing-redundant-work-to-speed-up-distributed-queries/>`_.
|
|
|
|
|
|
|
|
|
|
|
|
TailChoppingPool defined in configuration:
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#config-tail-chopping-pool
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#tail-chopping-pool-1
|
|
|
|
|
|
|
|
|
|
|
|
TailChoppingPool defined in code:
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#tail-chopping-pool-2
|
|
|
|
|
|
|
|
|
|
|
|
TailChoppingGroup defined in configuration:
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#config-tail-chopping-group
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#tail-chopping-group-1
|
|
|
|
|
|
|
|
|
|
|
|
TailChoppingGroup defined in code:
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala
|
|
|
|
|
|
:include: paths,tail-chopping-group-2
|
|
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
ConsistentHashingPool and ConsistentHashingGroup
|
|
|
|
|
|
------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
The ConsistentHashingPool uses `consistent hashing <http://en.wikipedia.org/wiki/Consistent_hashing>`_
|
|
|
|
|
|
to select a routee based on the sent message. This
|
2012-09-11 15:10:33 +02:00
|
|
|
|
`article <http://weblogs.java.net/blog/tomwhite/archive/2007/11/consistent_hash.html>`_ gives good
|
|
|
|
|
|
insight into how consistent hashing is implemented.
|
|
|
|
|
|
|
2012-09-14 13:47:58 +02:00
|
|
|
|
There is 3 ways to define what data to use for the consistent hash key.
|
|
|
|
|
|
|
2012-09-17 13:24:13 +02:00
|
|
|
|
* You can define ``hashMapping`` of the router to map incoming
|
2012-09-17 11:40:06 +02:00
|
|
|
|
messages to their consistent hash key. This makes the decision
|
2012-09-14 13:47:58 +02:00
|
|
|
|
transparent for the sender.
|
|
|
|
|
|
|
2012-09-17 11:40:06 +02:00
|
|
|
|
* The messages may implement ``akka.routing.ConsistentHashingRouter.ConsistentHashable``.
|
2012-09-14 13:47:58 +02:00
|
|
|
|
The key is part of the message and it's convenient to define it together
|
|
|
|
|
|
with the message definition.
|
|
|
|
|
|
|
2015-11-04 13:49:30 +01:00
|
|
|
|
* The messages can be wrapped in a ``akka.routing.ConsistentHashingRouter.ConsistentHashableEnvelope``
|
2012-09-14 13:47:58 +02:00
|
|
|
|
to define what data to use for the consistent hash key. The sender knows
|
|
|
|
|
|
the key to use.
|
|
|
|
|
|
|
|
|
|
|
|
These ways to define the consistent hash key can be use together and at
|
2012-09-17 13:24:13 +02:00
|
|
|
|
the same time for one router. The ``hashMapping`` is tried first.
|
2012-09-11 15:10:33 +02:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
|
2012-09-11 15:10:33 +02:00
|
|
|
|
Code example:
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/ConsistentHashingRouterDocSpec.scala#cache-actor
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/ConsistentHashingRouterDocSpec.scala#consistent-hashing-router
|
|
|
|
|
|
|
|
|
|
|
|
In the above example you see that the ``Get`` message implements ``ConsistentHashable`` itself,
|
2012-09-14 14:28:47 +02:00
|
|
|
|
while the ``Entry`` message is wrapped in a ``ConsistentHashableEnvelope``. The ``Evict``
|
2012-09-17 13:24:13 +02:00
|
|
|
|
message is handled by the ``hashMapping`` partial function.
|
2012-09-11 15:10:33 +02:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
ConsistentHashingPool defined in configuration:
|
2012-09-11 15:10:33 +02:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#config-consistent-hashing-pool
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#consistent-hashing-pool-1
|
|
|
|
|
|
|
|
|
|
|
|
ConsistentHashingPool defined in code:
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#consistent-hashing-pool-2
|
|
|
|
|
|
|
|
|
|
|
|
ConsistentHashingGroup defined in configuration:
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#config-consistent-hashing-group
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#consistent-hashing-group-1
|
|
|
|
|
|
|
|
|
|
|
|
ConsistentHashingGroup defined in code:
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala
|
|
|
|
|
|
:include: paths,consistent-hashing-group-2
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
``virtual-nodes-factor`` is the number of virtual nodes per routee that is used in the
|
|
|
|
|
|
consistent hash node ring to make the distribution more uniform.
|
2012-09-11 15:10:33 +02:00
|
|
|
|
|
2013-01-31 21:48:03 +13:00
|
|
|
|
.. _router-special-messages-scala:
|
|
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
Specially Handled Messages
|
|
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
2013-01-31 21:48:03 +13:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
Most messages sent to router actors will be forwarded according to the routers' routing logic.
|
2013-01-31 21:48:03 +13:00
|
|
|
|
However there are a few types of messages that have special behavior.
|
|
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
Note that these special messages, except for the ``Broadcast`` message, are only handled by
|
|
|
|
|
|
self contained router actors and not by the ``akka.routing.Router`` component described
|
|
|
|
|
|
in :ref:`simple-router-scala`.
|
|
|
|
|
|
|
2013-01-31 21:48:03 +13:00
|
|
|
|
.. _broadcast-messages-scala:
|
2012-09-11 15:10:33 +02:00
|
|
|
|
|
2011-12-15 15:28:21 +01:00
|
|
|
|
Broadcast Messages
|
2013-09-19 08:00:05 +02:00
|
|
|
|
------------------
|
2011-12-15 15:28:21 +01:00
|
|
|
|
|
2013-01-31 21:48:03 +13:00
|
|
|
|
A ``Broadcast`` message can be used to send a message to *all* of a router's routees. When a router
|
|
|
|
|
|
receives a ``Broadcast`` message, it will broadcast that message's *payload* to all routees, no
|
|
|
|
|
|
matter how that router would normally route its messages.
|
2011-04-09 19:55:46 -06:00
|
|
|
|
|
2013-01-31 21:48:03 +13:00
|
|
|
|
The example below shows how you would use a ``Broadcast`` message to send a very important message
|
|
|
|
|
|
to every routee of a router.
|
|
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#broadcastDavyJonesWarning
|
2013-01-31 21:48:03 +13:00
|
|
|
|
|
|
|
|
|
|
In this example the router receives the ``Broadcast`` message, extracts its payload
|
|
|
|
|
|
(``"Watch out for Davy Jones' locker"``), and then sends the payload on to all of the router's
|
2015-11-04 13:49:30 +01:00
|
|
|
|
routees. It is up to each routee actor to handle the received payload message.
|
2013-01-31 21:48:03 +13:00
|
|
|
|
|
2016-07-18 17:33:09 +09:00
|
|
|
|
.. note::
|
|
|
|
|
|
Do not use :ref:`broadcast-messages-scala` when you use :ref:`balancing-pool-scala` for routers.
|
|
|
|
|
|
Routees on :ref:`balancing-pool-scala` shares the same mailbox instance, thus some routees can
|
|
|
|
|
|
possibly get the broadcast message multiple times, while other routees get no broadcast message.
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-01-31 21:48:03 +13:00
|
|
|
|
PoisonPill Messages
|
2013-09-19 08:00:05 +02:00
|
|
|
|
-------------------
|
2013-01-31 21:48:03 +13:00
|
|
|
|
|
|
|
|
|
|
A ``PoisonPill`` message has special handling for all actors, including for routers. When any actor
|
|
|
|
|
|
receives a ``PoisonPill`` message, that actor will be stopped. See the :ref:`poison-pill-scala`
|
|
|
|
|
|
documentation for details.
|
|
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#poisonPill
|
2013-01-31 21:48:03 +13:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
For a router, which normally passes on messages to routees, it is important to realise that
|
2013-01-31 21:48:03 +13:00
|
|
|
|
``PoisonPill`` messages are processed by the router only. ``PoisonPill`` messages sent to a router
|
|
|
|
|
|
will *not* be sent on to routees.
|
|
|
|
|
|
|
|
|
|
|
|
However, a ``PoisonPill`` message sent to a router may still affect its routees, because it will
|
|
|
|
|
|
stop the router and when the router stops it also stops its children. Stopping children is normal
|
|
|
|
|
|
actor behavior. The router will stop routees that it has created as children. Each child will
|
2013-09-19 08:00:05 +02:00
|
|
|
|
process its current message and then stop. This may lead to some messages being unprocessed.
|
2013-01-31 21:48:03 +13:00
|
|
|
|
See the documentation on :ref:`stopping-actors-scala` for more information.
|
|
|
|
|
|
|
|
|
|
|
|
If you wish to stop a router and its routees, but you would like the routees to first process all
|
|
|
|
|
|
the messages currently in their mailboxes, then you should not send a ``PoisonPill`` message to the
|
2013-09-19 08:00:05 +02:00
|
|
|
|
router. Instead you should wrap a ``PoisonPill`` message inside a ``Broadcast`` message so that each
|
|
|
|
|
|
routee will receive the ``PoisonPill`` message. Note that this will stop all routees, even if the
|
2013-01-31 21:48:03 +13:00
|
|
|
|
routees aren't children of the router, i.e. even routees programmatically provided to the router.
|
|
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#broadcastPoisonPill
|
2013-01-31 21:48:03 +13:00
|
|
|
|
|
|
|
|
|
|
With the code shown above, each routee will receive a ``PoisonPill`` message. Each routee will
|
|
|
|
|
|
continue to process its messages as normal, eventually processing the ``PoisonPill``. This will
|
|
|
|
|
|
cause the routee to stop. After all routees have stopped the router will itself be :ref:`stopped
|
2013-04-08 13:19:44 +02:00
|
|
|
|
automatically <note-router-terminated-children-scala>` unless it is a dynamic router, e.g. using
|
|
|
|
|
|
a resizer.
|
2013-01-31 21:48:03 +13:00
|
|
|
|
|
|
|
|
|
|
.. note::
|
|
|
|
|
|
|
|
|
|
|
|
Brendan W McAdams' excellent blog post `Distributing Akka Workloads - And Shutting Down Afterwards
|
2016-02-29 12:37:17 -06:00
|
|
|
|
<http://bytes.codes/2013/01/17/Distributing_Akka_Workloads_And_Shutting_Down_After/>`_
|
2013-01-31 21:48:03 +13:00
|
|
|
|
discusses in more detail how ``PoisonPill`` messages can be used to shut down routers and routees.
|
2011-04-09 19:55:46 -06:00
|
|
|
|
|
2013-01-31 21:48:03 +13:00
|
|
|
|
Kill Messages
|
2013-09-19 08:00:05 +02:00
|
|
|
|
-------------
|
2011-12-15 15:28:21 +01:00
|
|
|
|
|
2013-01-31 21:48:03 +13:00
|
|
|
|
``Kill`` messages are another type of message that has special handling. See
|
|
|
|
|
|
:ref:`killing-actors-scala` for general information about how actors handle ``Kill`` messages.
|
|
|
|
|
|
|
|
|
|
|
|
When a ``Kill`` message is sent to a router the router processes the message internally, and does
|
2013-09-19 08:00:05 +02:00
|
|
|
|
*not* send it on to its routees. The router will throw an ``ActorKilledException`` and fail. It
|
2013-01-31 21:48:03 +13:00
|
|
|
|
will then be either resumed, restarted or terminated, depending how it is supervised.
|
|
|
|
|
|
|
|
|
|
|
|
Routees that are children of the router will also be suspended, and will be affected by the
|
|
|
|
|
|
supervision directive that is applied to the router. Routees that are not the routers children, i.e.
|
|
|
|
|
|
those that were created externally to the router, will not be affected.
|
|
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#kill
|
2013-01-31 21:48:03 +13:00
|
|
|
|
|
|
|
|
|
|
As with the ``PoisonPill`` message, there is a distinction between killing a router, which
|
|
|
|
|
|
indirectly kills its children (who happen to be routees), and killing routees directly (some of whom
|
|
|
|
|
|
may not be children.) To kill routees directly the router should be sent a ``Kill`` message wrapped
|
|
|
|
|
|
in a ``Broadcast`` message.
|
|
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#broadcastKill
|
|
|
|
|
|
|
2014-07-07 03:30:23 +06:00
|
|
|
|
Management Messages
|
|
|
|
|
|
-------------------
|
2013-09-19 08:00:05 +02:00
|
|
|
|
|
|
|
|
|
|
* Sending ``akka.routing.GetRoutees`` to a router actor will make it send back its currently used routees
|
|
|
|
|
|
in a ``akka.routing.Routees`` message.
|
|
|
|
|
|
* Sending ``akka.routing.AddRoutee`` to a router actor will add that routee to its collection of routees.
|
|
|
|
|
|
* Sending ``akka.routing.RemoveRoutee`` to a router actor will remove that routee to its collection of routees.
|
|
|
|
|
|
* Sending ``akka.routing.AdjustPoolSize`` to a pool router actor will add or remove that number of routees to
|
|
|
|
|
|
its collection of routees.
|
|
|
|
|
|
|
2015-10-14 14:42:35 +02:00
|
|
|
|
These management messages may be handled after other messages, so if you send ``AddRoutee`` immediately followed by
|
2013-09-19 08:00:05 +02:00
|
|
|
|
an ordinary message you are not guaranteed that the routees have been changed when the ordinary message
|
|
|
|
|
|
is routed. If you need to know when the change has been applied you can send ``AddRoutee`` followed by ``GetRoutees``
|
2014-06-26 17:35:46 +02:00
|
|
|
|
and when you receive the ``Routees`` reply you know that the preceding change has been applied.
|
2013-01-31 21:48:03 +13:00
|
|
|
|
|
|
|
|
|
|
.. _resizable-routers-scala:
|
2011-12-15 15:28:21 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
Dynamically Resizable Pool
|
|
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
2012-01-10 15:53:27 +01:00
|
|
|
|
|
2014-01-10 17:14:10 +01:00
|
|
|
|
Most pools can be used with a fixed number of routees or with a resize strategy to adjust the number
|
2012-01-10 15:53:27 +01:00
|
|
|
|
of routees dynamically.
|
|
|
|
|
|
|
2015-08-21 21:03:57 -04:00
|
|
|
|
There are two types of resizers: the default ``Resizer`` and the ``OptimalSizeExploringResizer``.
|
|
|
|
|
|
|
|
|
|
|
|
Default Resizer
|
|
|
|
|
|
---------------
|
|
|
|
|
|
|
|
|
|
|
|
The default resizer ramps up and down pool size based on pressure, measured by the percentage of busy routees
|
|
|
|
|
|
in the pool. It ramps up pool size if the pressure is higher than a certain threshold and backs off if the
|
|
|
|
|
|
pressure is lower than certain threshold. Both thresholds are configurable.
|
|
|
|
|
|
|
|
|
|
|
|
Pool with default resizer defined in configuration:
|
2012-01-10 15:53:27 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#config-resize-pool
|
2012-01-10 15:53:27 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#resize-pool-1
|
2012-01-10 15:53:27 +01:00
|
|
|
|
|
2012-02-14 19:50:01 +07:00
|
|
|
|
Several more configuration options are available and described in ``akka.actor.deployment.default.resizer``
|
2012-01-10 15:53:27 +01:00
|
|
|
|
section of the reference :ref:`configuration`.
|
|
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
Pool with resizer defined in code:
|
2012-01-10 15:53:27 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#resize-pool-2
|
2012-01-10 15:53:27 +01:00
|
|
|
|
|
2012-01-10 17:50:17 +01:00
|
|
|
|
*It is also worth pointing out that if you define the ``router`` in the configuration file then this value
|
|
|
|
|
|
will be used instead of any programmatically sent parameters.*
|
2012-01-10 15:53:27 +01:00
|
|
|
|
|
2015-08-21 21:03:57 -04:00
|
|
|
|
|
|
|
|
|
|
Optimal Size Exploring Resizer
|
|
|
|
|
|
------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
The ``OptimalSizeExploringResizer`` resizes the pool to an optimal size that provides the most message throughput.
|
|
|
|
|
|
|
|
|
|
|
|
This resizer works best when you expect the pool size to performance function to be a convex function.
|
|
|
|
|
|
For example, when you have a CPU bound tasks, the optimal size is bound to the number of CPU cores.
|
|
|
|
|
|
When your task is IO bound, the optimal size is bound to optimal number of concurrent connections to that IO service -
|
|
|
|
|
|
e.g. a 4 node elastic search cluster may handle 4-8 concurrent requests at optimal speed.
|
|
|
|
|
|
|
|
|
|
|
|
It achieves this by keeping track of message throughput at each pool size and performing the following
|
|
|
|
|
|
three resizing operations (one at a time) periodically:
|
|
|
|
|
|
|
|
|
|
|
|
* Downsize if it hasn't seen all routees ever fully utilized for a period of time.
|
|
|
|
|
|
* Explore to a random nearby pool size to try and collect throughput metrics.
|
|
|
|
|
|
* Optimize to a nearby pool size with a better (than any other nearby sizes) throughput metrics.
|
|
|
|
|
|
|
|
|
|
|
|
When the pool is fully-utilized (i.e. all routees are busy), it randomly choose between exploring and optimizing.
|
|
|
|
|
|
When the pool has not been fully-utilized for a period of time, it will downsize the pool to the last seen max
|
|
|
|
|
|
utilization multiplied by a configurable ratio.
|
|
|
|
|
|
|
|
|
|
|
|
By constantly exploring and optimizing, the resizer will eventually walk to the optimal size and
|
|
|
|
|
|
remain nearby. When the optimal size changes it will start walking towards the new one.
|
|
|
|
|
|
|
|
|
|
|
|
It keeps a performance log so it's stateful as well as having a larger memory footprint than the default ``Resizer``.
|
|
|
|
|
|
The memory usage is O(n) where n is the number of sizes you allow, i.e. upperBound - lowerBound.
|
|
|
|
|
|
|
|
|
|
|
|
Pool with ``OptimalSizeExploringResizer`` defined in configuration:
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#config-optimal-size-exploring-resize-pool
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#optimal-size-exploring-resize-pool
|
|
|
|
|
|
|
|
|
|
|
|
Several more configuration options are available and described in ``akka.actor.deployment.default.optimal-size-exploring-resizer``
|
|
|
|
|
|
section of the reference :ref:`configuration`.
|
|
|
|
|
|
|
2012-02-10 14:13:40 +01:00
|
|
|
|
.. note::
|
|
|
|
|
|
|
|
|
|
|
|
Resizing is triggered by sending messages to the actor pool, but it is not
|
|
|
|
|
|
completed synchronously; instead a message is sent to the “head”
|
2013-09-19 08:00:05 +02:00
|
|
|
|
``RouterActor`` to perform the size change. Thus you cannot rely on resizing
|
2012-02-10 14:13:40 +01:00
|
|
|
|
to instantaneously create new workers when all others are busy, because the
|
|
|
|
|
|
message just sent will be queued to the mailbox of a busy actor. To remedy
|
|
|
|
|
|
this, configure the pool to use a balancing dispatcher, see `Configuring
|
|
|
|
|
|
Dispatchers`_ for more information.
|
|
|
|
|
|
|
2015-08-21 21:03:57 -04:00
|
|
|
|
|
2013-01-31 21:48:03 +13:00
|
|
|
|
.. _router-design-scala:
|
|
|
|
|
|
|
|
|
|
|
|
How Routing is Designed within Akka
|
|
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
|
|
|
|
|
|
|
On the surface routers look like normal actors, but they are actually implemented differently.
|
|
|
|
|
|
Routers are designed to be extremely efficient at receiving messages and passing them quickly on to
|
|
|
|
|
|
routees.
|
|
|
|
|
|
|
|
|
|
|
|
A normal actor can be used for routing messages, but an actor's single-threaded processing can
|
|
|
|
|
|
become a bottleneck. Routers can achieve much higher throughput with an optimization to the usual
|
|
|
|
|
|
message-processing pipeline that allows concurrent routing. This is achieved by embedding routers'
|
2013-09-19 08:00:05 +02:00
|
|
|
|
routing logic directly in their ``ActorRef`` rather than in the router actor. Messages sent to
|
|
|
|
|
|
a router's ``ActorRef`` can be immediately routed to the routee, bypassing the single-threaded
|
2013-01-31 21:48:03 +13:00
|
|
|
|
router actor entirely.
|
|
|
|
|
|
|
|
|
|
|
|
The cost to this is, of course, that the internals of routing code are more complicated than if
|
|
|
|
|
|
routers were implemented with normal actors. Fortunately all of this complexity is invisible to
|
|
|
|
|
|
consumers of the routing API. However, it is something to be aware of when implementing your own
|
|
|
|
|
|
routers.
|
|
|
|
|
|
|
|
|
|
|
|
.. _custom-router-scala:
|
|
|
|
|
|
|
2011-12-15 15:28:21 +01:00
|
|
|
|
Custom Router
|
|
|
|
|
|
^^^^^^^^^^^^^
|
|
|
|
|
|
|
2013-01-31 21:48:03 +13:00
|
|
|
|
You can create your own router should you not find any of the ones provided by Akka sufficient for your needs.
|
2011-12-15 15:28:21 +01:00
|
|
|
|
In order to roll your own router you have to fulfill certain criteria which are explained in this section.
|
|
|
|
|
|
|
2013-01-31 21:48:03 +13:00
|
|
|
|
Before creating your own router you should consider whether a normal actor with router-like
|
|
|
|
|
|
behavior might do the job just as well as a full-blown router. As explained
|
|
|
|
|
|
:ref:`above <router-design-scala>`, the primary benefit of routers over normal actors is their
|
|
|
|
|
|
higher performance. But they are somewhat more complicated to write than normal actors. Therefore if
|
|
|
|
|
|
lower maximum throughput is acceptable in your application you may wish to stick with traditional
|
|
|
|
|
|
actors. This section, however, assumes that you wish to get maximum performance and so demonstrates
|
|
|
|
|
|
how you can create your own router.
|
|
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
The router created in this example is replicating each message to a few destinations.
|
2011-12-15 15:28:21 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
Start with the routing logic:
|
2011-12-15 15:28:21 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/CustomRouterDocSpec.scala#routing-logic
|
2011-12-15 15:28:21 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
``select`` will be called for each message and in this example pick a few destinations by round-robin,
|
|
|
|
|
|
by reusing the existing ``RoundRobinRoutingLogic`` and wrap the result in a ``SeveralRoutees``
|
2015-05-23 19:16:41 -07:00
|
|
|
|
instance. ``SeveralRoutees`` will send the message to all of the supplied routes.
|
2011-12-15 15:28:21 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
The implementation of the routing logic must be thread safe, since it might be used outside of actors.
|
2011-12-15 15:28:21 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
A unit test of the routing logic:
|
2011-12-15 15:28:21 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/CustomRouterDocSpec.scala#unit-test-logic
|
2011-12-15 15:28:21 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
You could stop here and use the ``RedundancyRoutingLogic`` with a ``akka.routing.Router``
|
|
|
|
|
|
as described in :ref:`simple-router-scala`.
|
2011-12-15 15:28:21 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
Let us continue and make this into a self contained, configurable, router actor.
|
2011-12-15 15:28:21 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
Create a class that extends ``Pool``, ``Group`` or ``CustomRouterConfig``. That class is a factory
|
|
|
|
|
|
for the routing logic and holds the configuration for the router. Here we make it a ``Group``.
|
2011-12-15 15:28:21 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/CustomRouterDocSpec.scala#group
|
2011-12-15 15:28:21 +01:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
This can be used exactly as the router actors provided by Akka.
|
2011-04-09 19:55:46 -06:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/CustomRouterDocSpec.scala#usage-1
|
2012-05-11 18:31:20 +02:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
Note that we added a constructor in ``RedundancyGroup`` that takes a ``Config`` parameter.
|
|
|
|
|
|
That makes it possible to define it in configuration.
|
2012-05-11 18:31:20 +02:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/CustomRouterDocSpec.scala#config
|
2012-05-11 18:31:20 +02:00
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
Note the fully qualified class name in the ``router`` property. The router class must extend
|
|
|
|
|
|
``akka.routing.RouterConfig`` (``Pool``, ``Group`` or ``CustomRouterConfig``) and have
|
|
|
|
|
|
constructor with one ``com.typesafe.config.Config`` parameter.
|
2012-01-12 16:37:08 +01:00
|
|
|
|
The deployment section of the configuration is passed to the constructor.
|
|
|
|
|
|
|
2013-09-19 08:00:05 +02:00
|
|
|
|
.. includecode:: code/docs/routing/CustomRouterDocSpec.scala#usage-2
|
|
|
|
|
|
|
2012-02-10 14:13:40 +01:00
|
|
|
|
Configuring Dispatchers
|
|
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
|
|
2013-10-16 13:02:35 +02:00
|
|
|
|
The dispatcher for created children of the pool will be taken from
|
2014-01-10 17:14:10 +01:00
|
|
|
|
``Props`` as described in :ref:`dispatchers-scala`.
|
2012-02-10 14:13:40 +01:00
|
|
|
|
|
2013-10-16 13:02:35 +02:00
|
|
|
|
To make it easy to define the dispatcher of the routees of the pool you can
|
|
|
|
|
|
define the dispatcher inline in the deployment section of the config.
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#config-pool-dispatcher
|
|
|
|
|
|
|
|
|
|
|
|
That is the only thing you need to do enable a dedicated dispatcher for a
|
|
|
|
|
|
pool.
|
|
|
|
|
|
|
2012-05-09 13:55:20 +02:00
|
|
|
|
.. note::
|
|
|
|
|
|
|
2013-10-16 13:02:35 +02:00
|
|
|
|
If you use a group of actors and route to their paths, then they will still use the same dispatcher
|
2012-05-09 13:55:20 +02:00
|
|
|
|
that was configured for them in their ``Props``, it is not possible to change an actors dispatcher
|
|
|
|
|
|
after it has been created.
|
|
|
|
|
|
|
2012-05-28 10:33:59 +02:00
|
|
|
|
The “head” router cannot always run on the same dispatcher, because it
|
|
|
|
|
|
does not process the same type of messages, hence this special actor does
|
2013-09-19 08:00:05 +02:00
|
|
|
|
not use the dispatcher configured in ``Props``, but takes the
|
2012-02-10 14:13:40 +01:00
|
|
|
|
``routerDispatcher`` from the :class:`RouterConfig` instead, which defaults to
|
|
|
|
|
|
the actor system’s default dispatcher. All standard routers allow setting this
|
|
|
|
|
|
property in their constructor or factory method, custom routers have to
|
|
|
|
|
|
implement the method in a suitable way.
|
|
|
|
|
|
|
2012-05-24 22:23:36 +02:00
|
|
|
|
.. includecode:: code/docs/routing/RouterDocSpec.scala#dispatchers
|
2012-02-10 14:13:40 +01:00
|
|
|
|
|
2012-05-28 10:33:59 +02:00
|
|
|
|
.. note::
|
|
|
|
|
|
|
|
|
|
|
|
It is not allowed to configure the ``routerDispatcher`` to be a
|
2014-01-10 17:14:10 +01:00
|
|
|
|
:class:`akka.dispatch.BalancingDispatcherConfigurator` since the messages meant
|
|
|
|
|
|
for the special router actor cannot be processed by any other actor.
|