Download presentation
Presentation is loading. Please wait.
Published byErica Cummings Modified over 6 years ago
1
Advanced Topics in Concurrency and Reactive Programming: Actor Model & Akka
Majeed Kassis
2
Threads Threads are used to execute code concurrently
Threads contains resources that they are shared Synchronization help guarantee: Correct ordering Visibility Data consistency Problems? Hard to solve deadlocks Hard to maintain data consistency Hard to ensure liveness Locks Shared Memory Waits Thread Thread Dead Lock ! Shared Memory Waits Locks
3
Thread-Based Concurrency Issues
No fault tolerance by default Programmers need to think of all extreme failure cases! Need to handle them one by one. Nondeterminism: Unpredictable thread scheduling The increasing use of Arbiters which controls concurrent access to memory Snapshotting and replication Global state – snapshots – complex to generate! data replication is hard due to shared state!
4
Actor Model – Asynchronous Concurrency
General purpose concurrent programming model Facilitates geographical distribution Strong support for fault tolerance Allows mutable state, but avoids sharing it. Actor: The fundamental unit of concurrent computation in the model. Can be implemented as processes or threads, or any other entity. Benefits: Simple and high-level abstractions for distribution, concurrency and parallelism. Asynchronous, non-blocking and highly performant message-driven programming model. Very lightweight event-driven processes (several million actors per GB of heap memory).
5
An Actor Unit Consists of Three Things
Processing: “Behavior” To get something done Same as objects: Methods Storage: “State” To be able to remember/store things Same as objects: Fields Communication: “Messages” via “MailBoxes” To exchange information between actors Different than objects: Real communication instead of method calling Mailbox Mailbox Behavior State Message Message Message Communication support is added Executors/Threads do not support communication
6
Actor Model – Key Principles
No shared state between actors! Not need for synchronization Each Actor has his own mail-box(es) Used as a buffer for incoming messages Messages are handled sequentially Messages are passed asynchronously The receives does not need to immediately handle the sent message Actors can create new Actors No single ‘manager’ of the system.
7
Messages in Actor Model
Actors exchange information by sending messages. Messages are sent asynchronously Receiving Actors do not block waiting for a message. Messages are stored in an Actor ‘mail-box’ (called ‘channel’ as well) A queue with multiple producers – other actors sending messages And a single consumer – the actor handles these messages sequentially Messages are immutable! They can be handled by the actor Or, they can be propagated as is – without modification
8
Reactions Upon Message Receive
Actor can send a finite number of messages to other actors Actors may have multiple mail-boxes Actors are addressed Can have no address, one address, or multiple addresses Actor can spawn a finite number of new actors Actor change its own internal behavior This occurs when a control message is received Takes effect when the next incoming message is handled! Behavior is stacked and can be popped or pushed as needed
9
Fault Tolerance Uses “let is crash” philosophy
Instead of programming defensively, allow critical code to crash! Once crashed, a monitoring process receives a message and it needs: Message is received from a supervisor Actor To restore the state to a stable one: Stop or restart crashed actor Allows creating “self-healing” systems! Implementation Example: (in Erlang) Each Actor code is ran in a process, isolated, with their own state Monitoring process acts as a supervisor Receives message on Actor crash Restores to safe state, can be done via rollback partial changes Restart crashed Actor, mostly with initial state Can also stop actor, or delegate problem onward We can just have one exception catch clause, send a message and exit. No need to handle any special case that we didn’t anticipate or thought about.
10
Actor Model Characteristics
Messages are sent asynchronously They can take arbitrarily long to eventually arrive in the mailbox of the receiver. There is no guarantees on the ordering of messages. Queuing and de-queuing of messages in a mailbox are atomic operations There cannot be a race condition. Incoming messages are processed sequentially
11
Actor Model Characteristics
Reacting Actor changes its own internal behavior, allows to deal with mutable state The new behavior is applied after the current message has been handled Every message handling run still represents a side-effect free operation from a conceptual perspective Allows modelling inherently concurrent systems Each actor is entirely independent of any other instances. There is no shared state – no sharing of references or pointers using messages Interaction between actors is purely based on asynchronous messages
12
Message Passing Implementations
Most implementations ensure that two messages sent from one actor to another maintain their order at arrival. Messaging is always asynchronous: Fire-Forget: Send request, no need for response Ask and Reply: Send request, expect response Forward: Send request asking it to be forwarded to 3rd party. Messages: Can be any object Should be immutable Should be serializable
13
Message Handling Implementations
Most implementations provide pattern matching. This enables the developer to distinguish between different types of messages and supply different handling code associated to the type of message. While receiving messages is a blocking operation from the actor's perspective, sending new messages is always non-blocking. Some implementations also provide selective receive semantics. Depending on its behavior, an actor may then wait for a specific message in the mailbox and temporarily defer others.
14
Actor Model Programing Languages
Erlang: Programming language based on actor model Introduced in 1986 by Ericsson Elixir: Wrapper of Erlang language Dynamic, functional language designed for building scalable and maintainable applications. By Plataformatic, in 2011
15
Actor Model Libraries Akka: C++ Actor Framework: CAF_C++
Apache’s toolkit and runtime for building highly concurrent, distributed, and resilient message-driven applications on the JVM. By Lightbend in 2009 C++ Actor Framework: CAF_C++ Implemented in C++11 Uses Work-Stealing Scheduling Lockfree implementation of mailboxes using CAS operation for enqueue/dequeue Presented in 2011, open source!
16
Akka Mailboxes Akka toolkit has many types of mailboxes:
Blocking and non-blocking queues Bounded and non-bounded queues Priority queues Control aware queues Akka also allows making custom defined queues. By implementing “MailBoxType” interface You can implement your own priority queue! Control aware = an actor needs to be able to receive control messages immediately no matter how many other messages are already in its mailbox.
17
Akka: Built-In MailBox Types
UnboundedMailbox SingleConsumerOnlyUnboundedMailbox NonBlockingBoundedMailbox UnboundedControlAwar box UnboundedPriorityMailbox UnboundedStablePriorityMailbox BoundedMailbox BoundedPriorityMailbox BoundedStablePriorityMailbox BoundedControlAwar box
18
Dispatcher: dispatches threads to perform actions
Dispatcher takes an actor object and its message and assigns to it a thread from the threadpool. Once the processing is done, the thread is made available for next executions. The number of actors can be millions while the threads can be several. How do we assign what to who? Using a router!
19
Router Router is an Actor which forwards the messages following the routing algorithm!
20
Router Logic RoundRobinRoutingLogic RandomRoutingLogic
SmallestMailboxRoutingLogic BroadcastRoutingLogic ScatterGatherFirstCompletedRoutingLogic TailChoppingRoutingLogic ConsistentHashingRoutingLogic
21
Actor: Core Operations
Define: Implement a new Actor Implements the behavior of the actor: how to handle message receive Create: Instantiate a new Actor Send: Send a message to an Actor Three kinds: Fire-Forget, send a message asynchronously and return immediately Ask-Reply, sends a message asynchronously and returns a Future representing a possible reply Forward, forward a message from one actor to another Become: Change the behavior (algorithm) of an Actor dynamically! This takes effect beginning from the next message onward. Supervise: Manage another Actor failure Dynamically: during runtime!
22
Defining an Actor – 2.4 public class Greeting implements Serializable { //define the message object to be handled public final String who; public Greeting(String who) { this.who = who; } } public class GreeterActor extends UntypedActor {//define the actor + define the actor behavior public void onReceive(Object message){ if (message instanceof Greeting) { System.out.println(((Greeting)message).who); }else{ System.out.println(“error:” + message); import akka.actor.UntypedActor; import akka.event.Logging; import akka.event.LoggingAdapter; import akka.japi.Procedure; onReceive - To be implemented by concrete UntypedActor, this defines the behavior of the UntypedActor.
23
Defining an Actor – Current (2.5)
import akka.actor.AbstractActor; public class GreeterActor extends AbstractActor { @Override public Receive createReceive() { return receiveBuilder() .match(String.class, s -> { System.out.println(s.toLowerCase()); }) .matchAny(o -> System.out.println("received unknown message")) .build(); }
24
Handling Multiple Kinds Of Messages
public class WellStructuredActor extends AbstractActor { public static class Msg1 {} public static class Msg2 {} public static class Msg3 {} @Override public Receive createReceive() { return receiveBuilder() .match(Msg1.class, this::receiveMsg1) .match(Msg2.class, this::receiveMsg2) .match(Msg3.class, this::receiveMsg3) .build(); } private void receiveMsg1(Msg1 msg) { // actual work } private void receiveMsg2(Msg2 msg) { // actual work } private void receiveMsg3(Msg3 msg) { // actual work } Benefits: 1. easier to see what kind of messages the actor can handle 2. readable stack traces in case of exceptions 3. works better with performance profiling tools 4. Java HotSpot has a better opportunity for making optimizations
25
Creating a new Actor using MailBox
public class HelloActor extends Controller { public static Result index() { ActorRef greeter = Akka.system().actorOf(Props.create(GreeterActor.class, “Greeter”) .withMailBox(“akka.dispatch.UnboundedMailbox”)); return ok("ok"); } Can create 2.7 million instances per GB of RAM! package controllers; import akka.actor.ActorRef; import akka.actor.Props; import play.libs.Akka; import play.mvc.*;
26
Sending a message to an Actor
package controllers; public class HelloActor extends Controller { public static Result index() { ActorRef actor = Akka.system().actorOf(Props.create(Greeter.class, “Greeter”)); actor.tell("Hello Actor!!", null); //send a message, no reply expected! return ok("ok"); } Type of sending messages: Tell: Fire and Forget Ask: Ask and Reply Forward: Forward import akka.actor.ActorRef; import akka.actor.Props; import play.libs.Akka; import play.mvc.*; Akka.system() – Creates a new system Props.create() – Creates a new configuration
27
A Tell B Target.tell(message, sender); null ActorRef.noSender()
Object ActorRef To send a message to an actor, you need a Actor reference Asynchronous and Non-blocking (Fire-and-forget) null ActorRef.noSender() getSelf() …
28
A Tell B Target.tell(message, sender);
public void onReceive(Object message){ if (message instanceof String) { System.out.println((String) message); System.out.println("getSender()="+ getSender()); }
29
A Tell B Target.tell(message, sender);
ActorRef Object ActorRef EXAMPLE: B.tell(“Hello Actor”,ActorRef.noSender()); B.tell(new Person(“David”,”Chang”),getSelf());
30
A Ask B 1 2 3 getSender().tell(reply_message, getSelf());
Target Ask A message B reply 1 Future<Object> rt = Patterns.ask(Target, message, timeout); 2 getSender().tell(reply_message, getSelf()); 3 String result = Await.result(rt , timeout.duration);
31
Ask public class HelloActor extends Controller {
public static Result index() { ActorRef actor = Akka.system().actorOf(Props.create(AnActor.class)); final Timeout timeout = new Timeout(Duration.create(1, SECONDS)); Future<Object> rt = Patterns.ask(actor,"What's your name?", timeout); try { String result = (String) Await.result(rt, timeout.duration()); System.out.println("The name is "+result); return ok("The name is "+result); } catch (Exception e) { System.out.println(e); } return ok("");
32
Ask import akka.actor.UntypedActor; import akka.japi.Procedure;
public class AnActor extends UntypedActor { public void onReceive(Object message){ if(message.equals("What's your name?")){ getSender().tell("David",getSelf()); }else if (message instanceof String) { System.out.println((String) message); }else{ System.out.println("Unhandled message"); }
33
A Forward B C Target.forward(message, getContext());
ActorContext Target.tell(message, getSender()); ActorRef
34
Become: Altering an Actor behavior
getContext().become(Procedure<Object>); Dynamically redefines actor behavior, during runtime! Reactively triggered by receiving a message Behaviors are stacked & can be pushed and popped become() –adds a new behavior to the behavior stack unbecome() – removed last behavior from the stack Active behavior: top() of the stack. getContext().unbecome();
35
public void onReceive(Object message) { if (message.equals(“work")) {
public class HotSwapActor extends UntypedActor { Procedure<Object> angry = new Procedure<Object>() { @Override public void apply(Object message) { if (message.equals(“work")) { getSender().tell(“I am angry ",getSelf()); } else if (message.equals(“play")) { getContext().become(happy); } }; Procedure<Object> happy = new Procedure<Object>() { if (message.equals(“play")) { getSender().tell("I am happy ", getSelf()); } else if (message.equals(“work")) { getContext().become(angry); public void onReceive(Object message) { } else { System.out.println(“error:” + message); public void onReceive(Object message) { if (message.equals(“work")) { getContext().become(angry); } else if (message.equals(“play")){ getContext().become(happy); } else { System.out.println(“error:” + message); }
36
Procedure<Object> angry = new Procedure<Object>() {
public class HotSwapActor extends UntypedActor { Procedure<Object> angry = new Procedure<Object>() { @Override public void apply(Object message) { if (message.equals(“work")) { getSender().tell(“I am angry ",getSelf()); } else if (message.equals(“play")) { getContext().become(happy); } }; Procedure<Object> happy = new Procedure<Object>() { if (message.equals(“play")) { getSender().tell("I am happy ", getSelf()); } else if (message.equals(“work")) { getContext().become(angry); public void onReceive(Object message) { } else { System.out.println(“error:” + message); Procedure<Object> angry = new Procedure<Object>() { @Override public void apply(Object message) { if (message.equals(“work")) { getSender().tell("I am angry ", getSelf()); } else if (message.equals(“play")) { getContext().become(happy); } };
37
Actor Hierarchy: Child Actors
The use of child actors Delegate work to a child actor which increases resiliency and responsiveness A child actor is created to do the handling of a specific event The result is forwarded to the original sender, not the parent actor Managing Exceptions Actors can manage exceptions thrown by child actors SupervisorStrategy is created to map each exception with its handling Can be used to stop or restart child
38
Akka System Default Actor
Hierarchy Actors can form hierarchies Akka System Default Actor akka://application/user ActorRef supervisor = Akka.system().actorOf(Props.create(SupervisorActor.class), “Supervisor”); Supervisor Actor parent akka://application/user/Supervisor ActorRef child = getContext().actorOf(Props.create(ChildActor.class), “Child”); Child Actor child akka://application/user/Supervisor/Child
39
Actor Hierarchy
40
Naming System Guardian System Actor /Foo Foo Bar /Foo/A A A C /Foo/A/B
41
Top-Level Supervisors: /user - The Guardian Actor
Actors created using system.actorOf() are children of this actor. When this guardian terminates all normal actors in the system will be shutdown as well! Its supervisor strategy determines how the top-level normal actors are supervised When the guardian escalates a failure The root guardian’s response will be to terminate the user guardian Which in effect will shut down the whole actor system.
42
Top-Level Supervisors: /system - The System Guardian
Used to allow an orderly shut-down sequence Where logging remains active while all normal actors terminate It initiates its own shut-down upon reception of the Terminated message. Terminated message is received from /user guardian upon system shutdown. The top-level system actors are supervised using a strategy which will restart indefinitely upon all types of Exception ActorInitializationException and ActorKilledException, will terminate the child in question.
43
Top-Level Supervisors: / - The Root Guardian
The grand-parent of all top-level actors Supervises all the special actors mentioned in Top-Level Scopes for Actor Paths Uses the SupervisorStrategy.stoppingStrategy as a supervision strategy SupervisorStrategy.stoppingStrategy Used to terminate the child upon any type of Exception. Other types of throwables will be escalated to the system System’s isTerminated set to true once root guardian is fully terminated All children recursively stopped
44
Supervise – Fault Tolerance
SUPERVISE: manage another Actor’s failures Error handling in actors is handle by letting Actors monitor (supervise) each other for failure This means that if an Actor crashes, a notification will be sent to his supervisor, who can react upon the failure: Stop - The stream is completed with failure Resume - The element is dropped and the stream continues Restart - The element is dropped and the stream continues after restarting the stage. Restarting a stage means that any accumulated state is cleared. This is typically performed by creating a new instance of the stage. Every single actor has a default supervisor strategy. Which is usually sufficient But it can be overridden
45
Setting Up Akka Getting Started: HelloActor Tutorial:
Prerequisites/Download/IDE Integration Using Akka with Maven or SBT HelloActor Tutorial: Akka 2.4.x -> 2.5.x 2.5.x.html Complete Akka:
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.