Post on 15-Jan-2015
description
Yardena Meymann
Sr. Software Architect at VMware
February 2013
CONCURRENCY IN SCALA THE AKKA WAY
SCALABILITY
• The amount of work grows – BIG.*
SCALABILITY
• Scale up and out without breaking down
SCALA
• Programming language for JVM
• Functional and Object-Oriented
• Type-safe
• Powerful
• Concise
• Extensible
• Interoperable with Java
AKKA
• Akka is a toolkit and runtime for building highly concurrent, distributed, and fault tolerant event-driven applications on the JVM
• Provides unified programming model for concurrency, distribution and fault-tolerance
ACTORS
Actor is a fundamental unit of computation
(Carl Hewitt 1973)
• Local state, isolated from the world
• Sends messages to other actors
• Reacts to received messages
• Actors usually come in systems
ACTORS
• Elastic – grow and shrink on demand
• Lightweight (2.7 M per GB RAM)
• Hot deploy – change behavior at runtime
• Local or distributed
EXAMPLE - SCOTCHDOG
• Inspired by Monit
http://mmonit.com/monit/
• Cross-platform,
JVM-based (Scala+Akka)
• Configured with list of services
• Starts and stops services
• Ensures that monitored services are up: checks periodically and starts if necessary
HOW IS THIS GOING TO WORK
• Actor per service
• Actor for the watchdog
ACTOR HIERARCHY
Watchdog
Service 1 Service 3Service 2
AKKA ACTOR HIERARCHY
Watchdog
Service 1 Service 3Service 2
user
root
system
systemactors
WHY THE HIERARCHY IS IMPORTANT
• Fault-tolerance
• “Let it crash”
• Supervisor can resume, restart, terminate the subordinate; it can also escalate the failure
• One-for-one and one-for-all strategies
LET’S START WITH MESSAGES
• Service commands
• start
• stop
• is started?
• monitor/unmonitor
• Watchdog commands
• start
• add service
• do *** to a specified service
• …
SERVICE COMMANDS
sealed trait ServiceCommand
case object Start extends ServiceCommand
case object Stop extends ServiceCommand
case object IsStarted extends ServiceCommand
…
• Commands need to be immutable objects
• Case classes and objects make excellent messages
WATCHDOG COMMANDS
case object StartWatching
case class AddService(config: ServiceConfig)
case class PerServiceCommand(
service: String,
command: ServiceCommand)
...
SENDING MESSAGES
• tell (a.k.a bang, or ! operator) sends a message asynchronously and return immediately
service ! Start
• ask (a.k.a ? operator) sends a message asynchronously and returns a Future representing a possible reply
service ? IsStarted
HANDLING MESSAGES
• Define actor class
class Service(config: ServiceConfig) extends Actor …
• Actor gives us • ability to create other actors
• access to self
• access to sender of last message
• lifecycle hooks
HANDLING MESSAGES
Define receive method within Actor class def receive = {
case Start => //perform start action
case Stop => //perform stop action
case IsStarted => {
//call isStarted action and capture the result
sender ! result //reply - return the result to sender
}
}
Heavily uses Scala’s pattern matching
CREATING ACTORS
• class Watchdog extends Actor …
• val system = ActorSystem(“Scotchdog”)
• val watchdog = system.actorOf( Props[Watchdog], name = “watchdog”)
• watchdog is an ActorRef
• we used default constructor
• Props allows customizations of actor behavior, such as the dispatcher (execution strategy). We used the default one
HANDLING MESSAGES - WATCHDOG
def receive = {
case AddService(config) => {
val service = context.actorOf(Props(new Service(config)),
config.name)
service ! Monitor
}
case PerServiceCommand(service, command) =>
context.actorFor(service) forward command
…
ACTOR REFERENCES
• Top level actors are created with system, child actors are created with parent actor’s context
• Existing actors can be found with context/system actorFor
• ActorRef can be sent to another actor
FUTURES
val future = watchdog ?
PerServiceCommand(“myserver", IsStarted)
There are several ways to obtain the value:
• val result = Await.result(future, 5 seconds). asInstanceOf[Boolean]
• future onComplete {
case Success(value: Boolean) => …
case Failure(_) => …
}
MORE ADVANCED EXAMPLE
• We want the watchdog to return a combined status of all services – “up” if all services are up, otherwise “down”• We will define:
val services =
new scala.collection.mutable.HashSet[String]
within Watchdog class
• It is safe to have mutable state within an actor!
• When adding services: services += config.name
MORE ADVANCED EXAMPLE
def receive = {
case Status => {
val responses =
for (child <- services;
serviceActor = context.actorFor(child));
future = serviceActor ? IsStarted)
yield future.asInstanceOf[Future[Boolean]]
sender ! Future.reduce(responses)(_ && _)
}
…
SCHEDULER
• We want to check periodically if a service is up, and report the status at any time
• For this purpose we can use Akka’s built-in scheduler
• …
SCHEDULER EXAMPLE
class ServiceMonitor(config: ServiceConfig) extends Actor with ActorLogging {
var status = false
var polling: Option[Cancellable] = None
def receive = {
case IsStarted => sender ! status
case Monitor =>
polling = Some(scheduler.schedule(Duration.Zero, config.interval, self, Tick))
case Tick =>
sender ? config.isStarted onSuccess { case res: Boolean => status = res }
case UnMonitor => polling.foreach(_.cancel)
…
FURTHER IMPROVEMENTS
• In practice, the service actor is more complex: for example, we don’t want to start a service again if it is already started or is starting up now
• To address this we use Akka’s Finite State Machine actors, a.k.a FSM
• This is a topic for a longer talk, so for now…
CONCLUSIONS
• Akka makes concurrency (and distribution, which we didn’t cover) easier
• Programming with actors require a paradigm shift, may be challenging at first, but worth it
• There is more to Akka then we’ve covered
• If you like Akka, but want to program in Java, you can use Java API
• Akka integrates with tools like Spring, Apache Camel and ZeroMQ
RESOURCES
• http://www.scala-lang.org
• http://akka.io
• http://typesafe.com
• http://letitcrash.com
• http://www.manning.com/roestenburg/
• http://www.cakesolutions.net/teamblogs/2012/07/03/akka-patterns/
• Coming soon https://github.com/yardena/scotchdog
THANK YOU