Build Cloud Applications with Akka
and Heroku
Havoc Pennington, Typesafe
@havocp
Safe Harbor
Safe harbor statement under the Private Securities Litigation Reform Act of 1995:
This presentation may contain forward-looking statements that involve risks, uncertainties, and assumptions. If any such uncertainties materialize or if
any of the assumptions proves incorrect, the results of salesforce.com, inc. could differ materially from the results expressed or implied by the forward-
looking statements we make. All statements other than statements of historical fact could be deemed forward-looking, including any projections of
product or service availability, subscriber growth, earnings, revenues, or other financial items and any statements regarding strategies or plans of
management for future operations, statements of belief, any statements concerning new, planned, or upgraded services or technology developments
and customer contracts or use of our services.
The risks and uncertainties referred to above include – but are not limited to – risks associated with developing and delivering new functionality for our
service, new products and services, our new business model, our past operating losses, possible fluctuations in our operating results and rate of growth,
interruptions or delays in our Web hosting, breach of our security measures, the outcome of intellectual property and other l itigation, risks associated
with possible mergers and acquisitions, the immature market in which we operate, our relatively limited operating history, our ability to expand, retain,
and motivate our employees and manage our growth, new releases of our service and successful customer deployment, our limited history reselling
non-salesforce.com products, and utilization and selling to larger enterprise customers. Further information on potential factors that could affect the
financial results of salesforce.com, inc. is included in our annual report on Form 10-Q for the most recent fiscal quarter ended July 31, 2012. This
documents and others containing important disclosures are available on the SEC Filings section of the Investor Information section of our Web site.
Any unreleased services or features referenced in this or other presentations, press releases or public statements are not currently available and may
not be delivered on time or at all. Customers who purchase our services should make the purchase decisions based upon features that are currently
available. Salesforce.com, inc. assumes no obligation and does not intend to update these forward-looking statements.
What does Typesafe do?
Modernizing development on the Java Virtual Machine
– Scala: practical, superior alternative to Java with incremental migration path
– Akka: proven Actor model gives horizontal scale for both Java and Scala,
without the pain points of explicit threads
– Play: popular Rails-style convention-over-configuration lightweight web
framework for both Java and Scala
– All supported on Heroku, a cloud platform with the same developer-friendly point
of view
3
Developer-friendly, horizontally scalable,
with a pragmatic path to adoption
This Talk
This talk introduces Akka, an actor-based middleware
– Will assume that you know Java
– What is Akka and when would you use it?
– Will briefly introduce the Heroku architecture and how it can combine with Akka
to build scalable applications
4
Getting to Know You
How many of you are already familiar with
– Actor model
– Akka
– Heroku
=> Any specific topics you hope to hear about in this talk?
5
Talk Overview
1. The high level: what's Akka / what are actors
2. Intro to the Akka API
3. A few best practices for Actors
4. Heroku-specific notes and a simple Heroku example
6
What is Akka?
• An application-organizing tool to simplify:
– concurrency
– fault tolerance
– scale-out / distribution
• An implementation of the “Actor model”
– The actor model is an alternative to explicit threads, originally used in the highly reliable Erlang
environment
• An API for both Java and Scala
– Many people use Akka but not Scala, even though Akka is written in Scala.
• Small
– core is just one no-dependencies jar
(More detail on all of these coming up...)
Selection of Akka Production Users
What is an “Actor”?
An object with state
Which receives one message at a time
(one thread at a time)
A Simple Code Example
public class HelloWorldActor extends UntypedActor {
public void onReceive(Object msg) {
getSender().tell(((String) msg) + “ World”);
}
}
class HelloWorldActor extends Actor {
def receive = {
case msg : String => sender ! (msg + “ World”)
}
}
... in Java:
... in Scala:
Actors can be seen as
Virtual Machines (nodes)
in Cloud Computing
Encapsulated and
decoupled black
boxes...
... managing their own
memory and behavior
Communicating with
asynchronous non-
blocking messages
Now if we replace
with Actor
EVERYTHING will STILL HOLD for both LOCAL and
DISTRIBUTED Actors
Actors and Servers
You can think of an actor as a network service...
...if you could implement a network service in a few lines of code and
have 2.7 million of them per gigabyte of RAM.
Actors ...
Actors may be new to many in the Java community, but they are a tried-and-
true concept (Hewitt 1973) used for many years in telecom systems with 9
nines uptime.
Like Java EE servlets and session beans, Actors is a model for organizing your
code that keeps many “policy decisions” separate from the business logic.
Unlike servlets and session beans, Actors are lightweight (< 300 bytes, no
thread-per) and dynamic (create/destroy them easily in code)
Actors can replace...
a thread
an object instance or component
a callback or listener
a singleton or service
a router, load-balancer, or pool
a Java EE Session Bean or Message-Driven Bean
Solution for Concurrent Programming
• Developer writes an object, called an Actor, which handles messages.
• Each actor instance runs in only one thread at a time, so no synchronization is
required for actor state.
• Akka dispatcher schedules actors on threads – or even on multiple machines
– as needed. Can have millions of actors, an actor does not “use up” a thread.
• Mutable state is safely single-threaded.
• Easier for programmers to create reliable concurrent processing.
• Many sources of contention, races, locking and dead-locks are removed.
• No need to use locks or java.util.concurrent – at all. Even though you're
using mutable state, it's encapsulated in actors.
19
Separation of Concerns
• “Business logic” does not concern itself with the
concurrency mechanism or scheduling. Just implement
what you'd like to happen in response to each message.
•Outside your business logic, configure for example: – Dispatch and execution (thread pool, event loop)
– Fault tolerance (what happens when an actor throws an exception?)
– Remoting
– Load balancing
20
So That's What Actors Are...
Next up, Akka details: assembling actors, messages, ActorRef, ActorSystem,
supervision, and remoting into an application.
Two questions about what you've seen so far?
public class HelloWorldActor extends UntypedActor {
public void onReceive(Object msg) {
getSender().tell(((String) msg) + “ World”);
}
}
class HelloWorldActor extends Actor {
def receive = {
case msg : String => sender ! (msg + “ World”)
}
}
Touring an Akka Application
All the code.
public class Greeting implements Serializable {
public final String who;
public Greeting(String who) { this.who = who; }
}
public class GreetingActor extends UntypedActor {
LoggingAdapter log = Logging.getLogger(getContext().system(), this);
public void onReceive(Object message) throws Exception {
if (message instanceof Greeting)
log.info("Hello " + ((Greeting) message).who);
}
}
}
ActorSystem system = ActorSystem.create("MySystem");
ActorRef greeter = system.actorOf(new Props(GreetingActor.class), "greeter");
greeter.tell(new Greeting("Charlie Parker"));
Explanation coming up...
The same in Scala...
case class Greeting(who: String)
class GreetingActor extends Actor with ActorLogging {
def receive = {
case Greeting(who) => log.info("Hello " + who)
}
}
val system = ActorSystem("MySystem")
val greeter = system.actorOf(Props[GreetingActor], name = "greeter")
greeter ! Greeting("Charlie Parker")
Explanation coming up...
ActorSystem
Every Akka application instantiates at least one ActorSystem
Akka has no global state; all state is associated with the ActorSystem
The ActorSystem includes:
• a configuration
• the dispatcher (thread pool)
• a hierarchical tree of actors
Unpacking Actor Creation
You may have noticed:
ActorRef greeter = system.actorOf(new Props(GreetingActor.class), "greeter");
• Props defines how to create an actor
• “greeter” is the name of the actor in the hierarchy
• ActorRef is a sort of “smart pointer” handle...
ActorRef
Because actors may be relocated in a cluster, or restarted if they fail,
you NEVER access the Actor itself.
Instead, actors are created inside an ActorRef, which always refers to
the same “conceptual” actor even if that actor is relocated or
restarted.
ActorRef ensures safety: you can send messages and that's all.
public class GreetingActor extends UntypedActor {
ActorRef contains an instance of this Actor subclass
Messages go through the ActorRef
ActorRef greeter = system.actorOf(new Props(GreetingActor.class), "greeter");
greeter.tell(new Greeting("Charlie Parker"));
val greeter = system.actorOf(Props[GreetingActor], name = "greeter")
greeter ! Greeting("Charlie Parker")
Messages
Should be immutable unless you want to have problems.
Should be serializable to enable remoting.
Can be any object. Strings for quick-and-dirty demos. Scala case
classes are perfect, in Java there's a little more work.
public class Greeting implements Serializable {
public final String who;
public Greeting(String who) { this.who = who; }
}
case class Greeting(who: String)
Hierarchy
A
B
Bar Foo
C
B E
A
D
C
/Foo
/Foo/A
/Foo/A/B
/Foo/A/D
Building Hierarchy
From inside one actor, you just create another actor. Use:
context.actorOf(..., “foo”)
Rather than:
system.actorOf(..., “foo”)
“context” is a field the Actor base class provides to its subclasses.
Best practice: avoid toplevel actors when possible.
Supervision
When actors create children, they become the fault handlers for
those children. (It's just like a real family!)
Parents are notified when their children fail, so they can take
action.
Why?
Handling Failure in Typical OO Code
Each thread has to handle errors and “keep itself alive”
No global organization of error handling ...
• defensive programming
• tangled with business logic
• scattered around the code
Which components have critically important state and
explicit error handling?
Supervision Factors Out Fault Handling
“Let it crash” philosophy; let the supervisor deal with it
Error
Kernel
class Supervisor extends UntypedActor {
private SupervisorStrategy strategy = new OneForOneStrategy(
10,
Duration.parse("1 minute"),
new Function<Throwable, Directive>() {
@Override public Directive apply(Throwable t) {
if (t instanceof ArithmeticException) return resume();
else if (t instanceof NullPointerException) return restart();
else return escalate();
}
});
@Override public SupervisorStrategy supervisorStrategy() {
return strategy;
}
ActorRef worker = context.actorOf(new Props(Worker.class));
public void onReceive(Object message) throws Exception {
if (message instanceof Integer) worker.forward(message);
}
}
Java Supervisor
class Supervisor extends Actor {
override val supervisorStrategy =
OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) {
case _: ArithmeticException => Resume
case _: NullPointerException => Restart
case _: Exception => Escalate
}
val worker = context.actorOf(Props[Worker])
def receive = {
case n: Int => worker forward n
}
}
Scala Supervisor
class Worker extends Actor {
...
override def preRestart(
reason: Throwable, message: Option[Any]) = {
... // clean up before restart
}
override def postRestart(reason: Throwable) = {
... // init after restart
}
}
Supervisee Hooks
Remoting
Remote actors have a different kind of ActorRef
(remember, ActorRef's job is to abstract the Actor instance and its location)
An actor can be made remote in config, with no code changes:
akka {
actor {
provider = akka.remote.RemoteActorRefProvider
deployment {
/Greeter {
remote = akka://MySystem@hostname1:2552
}
}
}
}
(also possible to do it in code)
Changing Behavior
When an actor gets a message, it may choose to change its behavior
(i.e. adopt a new message handler)
context.become(new Procedure[Object]() {
void apply(Object msg) {
// new body
if (msg instanceof NewMessage) {
NewMessage newMsg = (NewMessage)msg;
...
}
}
});
context become {
// new body
case NewMessage =>
...
}
Java
Scala
Why Change Behavior?
Ideas
1. State machine
2. Change to an actor pool or router on the fly according to load
3. Implement graceful degradation
4. ...
Quick Note: Akka Futures
• Not the main gist of this talk, but Akka 2.0 includes an incredibly useful Future
class. In Scala 2.10 / Akka 2.1, this class moves to the Scala standard library.
• Unlike Java Future, Akka Future is nonblocking: it has a callback/listener
model.
• Akka includes utilities for converting Future to a message to an actor and
vice-versa.
• Check out http://doc.akka.io/docs/akka/2.0.1/scala/futures.html and
http://doc.akka.io/docs/akka/2.0.1/java/futures.html
Some Akka Best Practices
Create Lots of Actors
Actors are not heavy like threads, they are tiny like objects
Create an actor for every request? No problem
Create a transient actor inline just to handle a single message?
Go for it
Actor tree should be deep, not shallow
Actors Do Only One Thing
Single responsibility principle
Keeps code clear
Lets you add supervision / routing / distribution to any single
thing
Eases debugging
Supervision
Each non-leaf node will be supervising its children
Only supervise one type of child (create intermediate actors to
group children by type)
Don't mix supervision with other actor tasks
No Blocking!
It ties up a thread and causes MASSIVE WASTE of system
resources
If you must block to use some API, give the blocking code a
separate thread pool and isolate it behind an Actor or Future
Name Your Actors
If nothing else, anonymous actors means inscrutable logs
Actors can be referred to by name
Akka on Heroku
How Heroku Works
(super-short version)
You tell it how to start a process (in this case the Java Virtual
Machine)
It automatically runs N copies of the process, one per virtual Linux
instance (the Linux instances are called Dynos)
When the process crashes, automatically creates a new dyno
Apps must be web apps (must listen on HTTP port) though they
can have background jobs
No way to listen on other ports
Services such as databases are available but don't run on dynos...
they are services available to the dynos
Some Akka/Heroku Similarities
Design for scale out
“Let it crash” (just restart the Dyno or the Actor)
Ease of use
Akka Just Works on Heroku
Within each dyno, just create actors!
https://github.com/havocp/dreamforce-akka-example
Demo
Let's see Akka on Heroku in action.
One Important Caveat
• Remoting/Clustering doesn't work on dynos, because they can only listen on
HTTP.
• i.e. you need to use Heroku clustering, not Akka clustering.
• You can communicate among nodes using many data store and message
queue services available as Heroku add-ons.
– RabbitMQ
– MongoDB
– ...
Some Recap
• Akka is an implementation of the Actor model for both Java and Scala.
• Actors encapsulate mutable state with the guarantee of one message at a time.
• Actor instances don't need to do any locking or think about threads, eliminating a whole
class of bugs and mental overhead.
• The magic comes from the dispatcher, which (by default) combines an event-driven loop
with a thread pool for scalability.
• A single JVM can host millions of actors – far more actors than threads.
• Akka actor jar is small, no dependencies, easy to embed
• Akka comes with a complete toolkit for distributed, fault-tolerant computing, built on actors
as a base.
Akka in Summary
• A way to structure an application
• Three problems addressed
– Concurrency
– Fault Tolerance
– Distribution / Remoting
• Small, easy-to-embed, no-dependencies library
• Follow us @Typesafe on Twitter, or typesafe.com
• Check out the extensive docs on http://akka.io
• Try writing some Akka code!