Introducing Akka
Markus Jura
About me
- Trainer @Typesafe
- Living in Hamburg
- Co-Founder of testmunk
- 3 years Scala, 10 years Java background
Akka (Áhkká)
The name comes from the goddess in the Sami (Native swedes) mythology that represents all the wisdom and beauty in the world.
Akka (Áhkká)
It is also the name of a beautiful mountain in Laponia in the north part of Sweden.
What is Akka?
Akka is a toolkit and runtime for building highly concurrent, distributed, and fault tolerant event-driven applications on the JVM.
akka.io
Akka's Value Proposition
A single unified programming model for
- simpler concurrency
- simpler distribution
- simpler fault tolerance
Program at Higher Level I
- Never think about
- Shared state
- Threads
- Locks
- Low level concurrency becomes simple
- Think how messages flow in the system
Program at Higher Level II
- High CPU utilization
- Low latency
- High troughput
- Scalability
Distributable by Design I
- Everything in Akka is distributed by default
- Going from local to remote by configuration
Distributable by Design II
- Perfect Programming Model for the Cloud
- Elastic & dynamic
- Fault-tolerant & self-healing
- Load-Balancing & cluster rebalancing
- Loosly coupled and dynamic systems that can change and adapt at runtime
Selection of Akka Production Users
Carl Hewitt's definition?
- The fundamental unit of computation that embodies:
- Processing
- Storage
- Communication
- Akka:
- Processing → Behavior
- Storage → State
What is an Actor?
- Java / Scala Class
- With a mailbox (Queue)
- Receives messages
- Only one message at a time is handled
- Extremely lightweight (400 Bytes / 2.7 Million per GB)
Now - if we replace
Everthing will still hold for both local and distributed Actors
What can I use Actors for?
- Can be an alternative to:
- Thread
- Object instance or component
- Callback or listener
- Singleton or service
What can I use Actors for?
- Can be an alternative to:
- Router, load-Balancer or pool
- Java EE Session Bean or Message-Driven Bean
- Finite State Machine (FSM)
Actor in Java
// Message Protocol
public static class Greeting implements Serializable {
public final String who;
public Greeting(String who) { this.who = who; }
}
public class GreetingActor extends UntypedActor {
// Put mutable state in here..
public void onReceive(Object message) {
if(message instanceof Greeting)
System.out.println("Hello " + ((Greeting) message).who);
}
}
Actor in Scala
// Message Protocol
case class Greeting(who: String)
class GreetingActor extends Actor {
// Put mutable state in here..
def receive = {
// Define the behavior here..
case Greeting(who) => println(s"Hello $who")
}
}
4 Core Actor Operations
- When an Actor handles a Message, it can
- Create → Create new Actors
- Send → Send messages to other Actors
- Become → Change the behavior for handling the next message
- Supervise → Manage another Actors failure
1. Create
- Each Actor is repesented by an ActorRef
- You never get access to an Actor instance
- An Actor reference let's you send messages to an Actor
Create an Actor (Java)
// Creates an Actor system
final ActorSystem system = ActorSystem.create("MySystem");
final ActorRef greeter =
system.actorOf(new Props(GreetingActor.class), "greeter");
// ^^ Create ^^ Actor configuration ^^ Actor name
Actors can form hierarchies
Actors can form hierarchies
Send Message (Java / Scala)
Java
greeter.tell(new Greeting("Charlie"), ActorRef.noSender());
Scala
greeter ! Greeting("Charlie")
Reply (Java)
class SomeActor extends UntypedActor {
public void onReceive(Object msg) {
if(msg instanceof User) {
User user = (User) msg;
// Reply to sender
getSender().tell("Hi " + user.name, getSelf());
}
}
}
Reply (Scala)
class SomeActor extends Actor {
def receive = {
// Reply to sender
case User(name) => sender ! (s"Hi $name")
}
}
Remote Deployment
akka {
actor {
# Configure Remote Provider
provider = akka.remote.RemoteActorRefProvider
deployment {
/greeter {
# Define Remote Path
remote = akka://MySystem@machine1:2552
}
}
}
}
- Just feed the ActorSystem with this configuration → Zero code changes
- You can configure the remote deployment programmatically as well
3. Become
- Dynamically redefining Actors behavior
- Triggered by receiving a message
- Will now react differently to the messages it receives
Why would I want to do that?
- Implement a Finite State Machine (FSM)
- Let a highly contended Actor adaptively transform himself into an Actor Pool or a Router
- Implement graceful degradation (Fehlertoleranz)
- Spawn up (empty) generic Worker Actors that can become whatever the Master currently needs
Become (Java)
Procedure<Object> happy = new Procedure<Object>() {
public void apply(Object msg) {
if(msg instanceof HappyMessage) {
HappyMessage happyMsg = (HappyMessage) msg;
...
}
}
});
public void onReceive(Object msg) {
if(msg instanceof HappyMessage)
getContext.become(happy);
}
Become (Scala)
def happy: Receive = {
case HappyMessage => ...
}
def receive = {
case HappyMessage => context become(happy)
}
Routers (Java)
Programmatically
int nrOfInstances = 5;
ActorRef router =
system.actorOf(new Props(SomeActor)
.withRouter(new RoundRobinRouter(nrOfInstances)));
Routers (Java)
Configuration
akka.actor.deployment {
/myRouter {
router = round-robin
nr-of-instances = 5
}
}
Java
ActorRef router =
system.actorOf(new Props(SomeActor)
.withRouter(new FromConfig(), "myRouter");
Router with Resizer (Java)
int lowerBound = 2;
int upperBound = 15;
DefaultResizer resizer = new DefaultResizer(lowerBound, upperBound);
ActorRef routerWithResizer = system.actorOf(
new Props(SomeActor.class)
.withRouter(new RoundRobinRouter(resizer)));
Resizer can be definied in configuration file as well
Failure Management in Java/C/C# etc.
Failure Management in Java/C/C# etc.
- Caller handles the failure
- This leads to defensive programming with:
- Error handling tangled with business logic
-
Scattered all over the code base
Failure Management in Akka
- Supervisor handles failure
- Actor throws exception → Supervisor react on failure
- Callers need not care (they can't anyway)
- Clean separation of processing and error handling
Let's take a standard OO application
Which components have critical important state and explicit error handling?
Override Supervisor Strategy (Java)
public class Supervisor extends UntypedActor {
private static SupervisorStrategy strategy =
new OneForOneStrategy(10, Duration.create("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 Supervisor Strategy (Java)
...
@Override
public SupervisorStrategy supervisorStrategy() {
return strategy;
}
}
Override Supervisor Strategy (Scala)
class Supervisor extends Actor {
override val supervisorStrategy = OneForOneStrategy(
maxNrOfRetries = 10, withinTimeRange = 1 minute) {
case _: ArithmeticException => Resume
case _: NullPointerException => Restart
case _: Exception => Escalate
}
}
This was
Akka
Well.. it's a start..