Routing
An Akka router is used to route messages efficiently to destination actors. We can use different routing strategies which come in-built with Akka and create our own routing.
Routing can be done in Akka in two ways:
- Create a router which manages routees itself
- Use a self-contained router actor with configurable routing capabilities
How to use a simple router?
A simple router manages routees itself and has to do the following:
- Create a set of routees
- Define routing strategy
- Route messages to routees
- Optionally watch the routees and replace when any of the routees die
import akka.routing.{ ActorRefRoutee,RoundRobinRoutingLogic, Router }
class Master extends Actor {
var router = {
val routees = Vector.fill(5) {
val r = context.actorOf(Props[Worker])
context watch r
ActorRefRoutee(r)
}
Router(RoundRobinRoutingLogic(), routees)
}
def receive = {
case w: Work =>
router.route(w, sender())
case Terminated(a) =>
router = router.removeRoutee(a)
val r = context.actorOf(Props[Worker])
context watch r
router = router.addRoutee(r)
}
}
In this example,Masteractor creates 5 routees (Workeractors) and wraps them inActorRefRouteeand then creates a routerakka.routing.RouterwithRoundRobinRoutingLogic. It also watches the routees so that it can take appropriates action when any of the them fails.
Then it just sends the incoming messages of typeWorkto routees as per the routing logic (round robin here) usingroutemethod.
In case any of the routees is terminated, it will just create a new one and add it to routee set.
Which routing strategies are available in Akka?
Akka provides the following routing strategies:
RoundRobinRoutingLogic
Messages are routed in a round robin fashion.
RandomRoutingLogic
Each time a messages arrives, the router picks a routee at random and forwards the meesages.
SmallestMailBoxRoutingLogic
Messages are sent to actors with fewest messages in their mailbox.
BroadcastRoutingLogic
Messages are sent to all the routees.
ScatterGatherFirstCompletedRoutingLogic
Messages are sent to all the routees and the response from the first one to reply is used. Responses from all other routees are discarded.
TailChoppingRoutingLogic
It first sends a messages to one of the routees (randomly picked). Then after a small delay, it will send the message to another (again randomly picked) and so on. Response from the first one to reply is used. Responses from all other routees are discarded.
ConsistentHashingRoutingLogic
Messages are sent in consistent hashing fashion.
How to use self-contained router actor?
A self-contained router actor manages the routees itself (without user code, as in case of an explicit router above). It loads routing logic and other settings for configuration.
There are two types of router actors:
- Pool: The router actor creates routees as child actors. It also supervises the routees.
- Group: Routees are created externally and provided to router actor. The latter which uses actor selection to send messages to routees. Routees are not supervised.
How to create and use pool router?
A pool router is created just like a normal actor. We need to provide routing config while creating the router. The config can either be provided from config file (application.conf) or programmatically.
Suppose we want to create a router for actors of type Worker.
Load configuration in config file:
akka.actor.deployment {
/parent/router1 {
router = round-robin-pool
nr-of-instances = 5
}
}
val router1: ActorRef = context.actorOf(FromConfig.props(Props[Worker]), "router1")
It is mandatory to wrap props in FromConfig.props if we provide config externally.
Provide configuration in code:
val router1: ActorRef = context.actorOf(RoundRobinPool(5).props(Props[Worker]), "router1")
How to deploy routees on remote nodes?
We can instruct the pool router to deploy its children (routees) on remote nodes. For this, we need to provide a list of nodes.
import akka.actor.{ Address, AddressFromURIString }
import akka.remote.routing.RemoteRouterConfig
val addresses = Seq(
Address("akka.tcp", "remotesys", "otherhost", 1234),
AddressFromURIString("akka.tcp://othersys@anotherhost:1234"))
val routerRemote = system.actorOf(
RemoteRouterConfig(RoundRobinPool(5), addresses).props(Props[Echo]))
Router configuration is wrapped in RemoteRouterConfig Children will be deployed in round robin fashion.