Concurrency in Scala - the Akka way

30
Yardena Meymann Sr. Software Architect at VMware February 2013 CONCURRENCY IN SCALA THE AKKA WAY

description

 

Transcript of Concurrency in Scala - the Akka way

Page 1: Concurrency in Scala - the Akka way

Yardena Meymann

Sr. Software Architect at VMware

February 2013

CONCURRENCY IN SCALA THE AKKA WAY

Page 2: Concurrency in Scala - the Akka way

SCALABILITY

• The amount of work grows – BIG.*

Page 3: Concurrency in Scala - the Akka way

SCALABILITY

• Scale up and out without breaking down

Page 4: Concurrency in Scala - the Akka way

SCALA

• Programming language for JVM

• Functional and Object-Oriented

• Type-safe

• Powerful

• Concise

• Extensible

• Interoperable with Java

Page 5: Concurrency in Scala - the Akka way

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

Page 6: Concurrency in Scala - the Akka way

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

Page 7: Concurrency in Scala - the Akka way

ACTORS

• Elastic – grow and shrink on demand

• Lightweight (2.7 M per GB RAM)

• Hot deploy – change behavior at runtime

• Local or distributed

Page 8: Concurrency in Scala - the Akka way

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

Page 9: Concurrency in Scala - the Akka way

HOW IS THIS GOING TO WORK

• Actor per service

• Actor for the watchdog

Page 10: Concurrency in Scala - the Akka way

ACTOR HIERARCHY

Watchdog

Service 1 Service 3Service 2

Page 11: Concurrency in Scala - the Akka way

AKKA ACTOR HIERARCHY

Watchdog

Service 1 Service 3Service 2

user

root

system

systemactors

Page 12: Concurrency in Scala - the Akka way

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

Page 13: Concurrency in Scala - the Akka way

LET’S START WITH MESSAGES

• Service commands

• start

• stop

• is started?

• monitor/unmonitor

• Watchdog commands

• start

• add service

• do *** to a specified service

• …

Page 14: Concurrency in Scala - the Akka way

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

Page 15: Concurrency in Scala - the Akka way

WATCHDOG COMMANDS

case object StartWatching

case class AddService(config: ServiceConfig)

case class PerServiceCommand(

service: String,

command: ServiceCommand)

...

Page 16: Concurrency in Scala - the Akka way

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

Page 17: Concurrency in Scala - the Akka way

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

Page 18: Concurrency in Scala - the Akka way

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

Page 19: Concurrency in Scala - the Akka way

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

Page 20: Concurrency in Scala - the Akka way

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

Page 21: Concurrency in Scala - the Akka way

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

Page 22: Concurrency in Scala - the Akka way

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(_) => …

}

Page 23: Concurrency in Scala - the Akka way

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

Page 24: Concurrency in Scala - the Akka way

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)(_ && _)

}

Page 25: Concurrency in Scala - the Akka way

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

• …

Page 26: Concurrency in Scala - the Akka way

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)

Page 27: Concurrency in Scala - the Akka way

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…

Page 28: Concurrency in Scala - the Akka way

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

Page 30: Concurrency in Scala - the Akka way

THANK YOU