Akka, an actor framework written in Scala (that also supports Java) provides you with all the benefits commonly found in actor frameworks, but without the kinks. This presentation will explore actor based concurrency using Akka, and dwell on some of Akka's stregths, culminating in the equation "Transactional Memory + Actors = Transactors".
4. What is Akka?
• A actor-based concurrency framework
• Provides solutions for non blocking concurrency
• Written in Scala, also works in Java
• Open source (APL)
• Now releasing 1.0 after 2 years in development
• Lead developer and founder: Jonas Boner
• JRockit, AspectWerkz, AspectJ, Terracotta
27. Excerpt from "Hello World" in SPL
Romeo, a young man with a remarkable patience.
Juliet, a likewise young woman of remarkable grace.
Scene II: The praising of Juliet.
[Enter Juliet]
Romeo:
Thou art as sweet as the sum of the sum
of Hamlet and his horse and his black
cat! Speak thy mind!
[Exit Juliet]
29. Actors
• Each actor has a message queue
• Actors accept and choose what to do with
messages
• Lightweight & asynchronous
30. Actors
• Each actor has a message queue
• Actors accept and choose what to do with
messages
• Lightweight & asynchronous
31. Actors
• Each actor has a message queue
• Actors accept and choose what to do with
messages
• Lightweight & asynchronous
32. Actors
• Each actor has a message queue
• Actors accept and choose what to do with
messages
• Lightweight & asynchronous
33. Actors
• Each actor has a message queue
• Actors accept and choose what to do with
messages
• Lightweight & asynchronous
34. Actors
• Each actor has a message queue
• Actors accept and choose what to do with
messages
• Lightweight & asynchronous
35. Actors
~4 threads
4 cores
• Actors tend to remain bound to a single thread
• Actors rarely block, thread can remain active for a Actors
long duration
• Minimizes context switches – throughput X millions
• Akka actors occupy 650 bytes
36. Benchmark
• Several actor implementations for Scala – Akka is considered the fastest
37. Akka Actors
// Java // Scala
public class GreetingActor extends class GreetingActor extends Actor {
UntypedActor {
private var counter = 0
private int counter = 0;
def receive = {
public void onReceive(Object message)
throws Exception { case message => {
counter++; counter += 1
// 1) Hello, Juliet // 1) Hello, Juliet
log.info( log.info(
counter + ") Hello, " + message); counter + ") Hello, " + message)
} }
} }
}
39. Akka Actors
• Once instantiated, actors can be retrieved by id or uuid
• uuid - generated by runtime, immutable, unique
• id - user assigned, by default that's the class name
class Romeo extend GreetingActor {
self.id = "Romeo"
}
actorOf[Romeo].start
val romeo = actorsFor("Romeo").head
romeo ! "Juliet"
41. Message Passing
• Let's build a bank with one actor per account, We’ll be able to :
• Check our balance
• Deposit money
• Withdraw money, but only if we have it (balance remains >= 0)
• We'll start by defining immutable message types:
case class CheckBalance()
case class Deposit(amount: Int)
case class Withdraw(amount: Int)
44. Message Passing
class BankAccount(private var balance: Int = 0) extends Actor {
def receive = {
// …
case Withdraw(amount) =>
balance = (balance - amount) ensuring (_ >= 0)
// …
}
}
45. Message Passing
• Now let’s make a deposit:
val account = actorOf[BankAccount].start
account ! Deposit(100)
• But how do we check the account balance?
46. Bang! Bang Bang!
• actorRef ! message - fire and forget
• actorRef !! message - send and block (optional timeout) for response
• actorRef !!! message - send, reply using future
...Jones Boner promised to stop at "!!!"
Java equivalents:
• ! = sendOneWay
• !! = sendRequestReply
• !!! = sendRequestReplyFuture
47. Getting Account Balance
val balance = (account !! CheckBalance) match {
// do stuff with result
}
// or:
val balanceFuture = account !!! CheckBalance // does not block
// ... go do some other stuff ... later:
val balance = balanceFuture.await.result match {
// do stuff with result
}
69. High Availability
• You can’t have a highly available
system on a single computer
• Luckily Akka supports near-seamless
remote actors
70. High Availability
• Server managed remote actors:
// on host1
RemoteNode.start("host1", 9000)
// register an actor
RemoteNode.register(“romeo", actorOf[GreetingActor])
// on host2
val romeo = RemoteClient.actorFor(“romeo", "host1", 9000)
romero ! “juliet"
• RemoteClient handles the connection lifecycle for us
• Clients can also manage server actors, but enabling this might pose a security
risk
72. High scalability Assumes state travels
Hgh availability along the message
Fast flow
Etc… Hostile towards shared
state.
Minds not easily rewired
for this!
81. Transactors
class BankAccount extends Transactor {
private val balanceRef = Ref(0)
def atomically = {
// ...
case CheckBalance => self reply_? balance.get
// ...
}
}
82. Transactors
class BankAccount extends Transactor {
private val balanceRef = Ref(0)
def atomically = {
// ...
case Deposit(amount) =>
balance alter (_ + amount)
// ...
}
}
83. Transactors
class BankAccount extends Transactor {
private val balanceRef = Ref(0)
def atomically = {
// ...
case Withdraw(amount) =>
balance alter (_ - amount) ensuring (_.get >= 0)
// ...
}
}
84. Transactors
Performing a money transfer transactionally:
val tx = Coordinated()
val fromBalance = (from !! tx(CheckBalance())) match {
balance: Int => balance
}
if (fromBalance >= 50) {
from ! tx(Withdraw(50))
to ! tx(Deposit(50))
}
85. Coordinated Transactions
class Bank extends Actor {
private val accounts =
TransactionalVector[BankAccount]
def receive = {
// ...
case tx @ Coordinated(Join) => {
tx atomic {
accounts += self.sender.get
}
}
// ...
}
86. Coordinated Transactions
class Bank extends Actor {
private val accounts = TransactionalVector[BankAccount]
def receive = {
// ...
case tx @ Coordinated(Sum) => {
val futures = for (account <- accounts) yield
account !!! tx(CheckBalance)
val allTheMoney = futures map (_.await.result) sum
self reply_? allTheMoney
}
// ...
} …and then: println (myBank !! Coordinated(Sum))
94. Typed Actors in Java
• In Java we will usually avoid “untyped” actors, and use POJOs instead:
interface BankAccount {
Future<Integer> balance();
void deposit(int amount);
void withdraw(int amount);
}
class BankAccountImpl extends TypedActor implements BankAccount {
// Almost a regular POJO
public Future<Integer> balance() {
return future(balance);
}
// ...
}