This document introduces the actor model and Akka framework. It discusses that concurrency is the next revolution in software and the actor model provides a unified approach for concurrency and parallelism. It then demonstrates how to model ticket booking as actors that communicate asynchronously through message passing. Finally, it discusses additional Akka capabilities like persistence, clustering, and fault tolerance.
2. Goals
• A problem (one of them) and traditional solutions
• Actor Model (since 1973)
• Akka Actors
• The rest of Akka goodies
• To choose, or not to choose (Akka)
4. [1] Herb Sutter. The Free Lunch Is Over: A Fundamental Turn Toward Concurrency in Software, 2005. –
http://www.gotw.ca/publications/concurrency-ddj.htm
Concurrency is the
next major revolution
in how we write
software [1].
5.
6.
7.
8.
9. More CPUs —
more threads
Your code:
if (check (seat, row))
book (seat, row)
10. More CPUs — more threads
check (1, 10)
book (1, 10)
check (1, 10)
book (1, 10)
check (1, 10)
check (1, 10)
book (1, 10)
book (1, 10)
:-(
13. • Managing shared state requires synchronisation;
• Which leads to keeping the threads busy waiting;
• The granularity control is limited;
• There are different solutions to the problem:
• synchronized,
• database,
• something else?
14. – Carl Hewitt
“An actor is the fundamental unit of
computation which embodies the 3 things –
processing, storage and communications – that
are essential to computation.”
15.
16. What an actor is not…
Future Thread Actor
Processing + + +
Storage + +
Communication +
17. What an actor can do?
• Designate how to handle the next message it
receives;
• Create new actors;
• Send messages to actors it knows.
18. Messages
• Processed one at a time;
• May be not delivered in the same order as sent;
• At-most-once delivery guarantee.
19. Why actors are interesting?
• Unified model for concurrency and parallelism;
• Out-of-the box multi-server support.
24. object TicketDeskActor {
case class BookTicket(eventId: String,
row: Int,
seat: Int)
case class TicketBooked(ticketId: Long)
}
class TicketDeskActor extends Actor {
override def receive: Receive = {
case BookTicket(eventId, row, seat) => ???
}
}
25. val mySystem = ActorSystem("TheatreApp")
val myProps: Props = Props[TicketDeskActor]
val myActor: ActorRef = mySystem.
actorOf(myProps, "ticket-desk")
print(s"Created ${myActor.path}")
// Created akka://TheatreApp/user/ticket-desk
mySystem.terminate()
Actor recipe
Actor path
Actor ref
26. val result: Future[Any] = myActor ? BookTicket(…)
myActor ! BookTicket(…)
Tell (a.k.a. “fire and forget”)
Ask
30. class TicketDeskActor extends Actor {
override def receive: Receive = {
case msg @ BookTicket(eventId, _, _) =>
val evtActorName = s"event-$eventId"
val evtActorProps = Props(new
EventActor(eventId))
val eventActorRef =
context.child(evtActorName).getOrElse {
context.actorOf(evtActorProps,
evtActorName)
}
eventActorRef forward msg
}
}
31.
32. class EventActor(eventId: String) extends Actor with ActorLogging {
override def preStart(): Unit = {
log.info(s"Starting an event actor for $eventId")
}
override def receive: Receive = {
case BookTicket(_, seat, row) =>
log.info("Updating the state with the newly booked ticket")
}
}
[INFO] [04/03/2016 20:17:57.907] [TheatreApp-akka.actor.default-
dispatcher-3] [akka://TheatreApp/user/ticket-desk/event-
JustinBieber] Starting an event actor for JustinBieber
Actor path
Logging trait
34. object DelayedEventActor {
case object SaleIsNotStartedYet
case object StartSale
}
class DelayedEventActor(eventId: String, saleStarts: LocalDateTime)
extends EventActor(eventId) with ActorLogging {
var cancellable: Option[Cancellable] = None
override def preStart(): Unit = {
super.preStart()
val delay = Duration.between(saleStarts, LocalDateTime.now())
import context.dispatcher
cancellable = Some(
context.system.scheduler.scheduleOnce(delay.toNanos nanos, self, StartSale)
)
}
override def postStop(): Unit = {
super.postStop()
cancellable.foreach(_.cancel())
}
override def receive: Receive = {
case StartSale =>
context.become(super.receive)
case msg: BookTicket =>
log.warning(s"Trying to book a ticket too early")
sender() ! SaleIsNotStartedYet
}
}
Scheduling a message to self
Changing the behaviour
Extends the normal EventActor
35. Lifecycle: stopping
• Actors can be terminated by stop() or PoisonPill
message;
• postStop() method is called;
• The rest of the messages is sent to the dead
letters;
• If an actor is terminated, all its children are
terminated as well.
36. Lifecycle: fault tolerance
• Supervision by parent actors;
• On exception: Resume, Restart, Stop, or
Escalate, based on the supervision strategy;
39. Clustering
• Actor model is very good for clustering;
• Akka has very good clustering support:
• Sharding;
• Cluster singleton;
• Other stuff. Check it out.
40. Is Akka a good choice for
you?
Paul Chiusano: Actors are
overly nondeterminstic :-(
Roland Kuhn: …they are the
essence of concurrency and
therefore by nature as non-
deterministic as they can be.
Actors are overly nondeterminstic, Paul Chiusano's blog, 2013 — http://pchiusano.blogspot.nl/2013/09/actors-are-
overly-nondeterminstic.html
41. How to start?
• Find a task where the advantage is obvious!
• Micro service Pet-project scale first?
• The structure and lifecycle is important!