Akka: Simpler Concurrency, Scalability & Fault-tolerance through Actors. Jonas Bonér Scalable Solutions

Similar documents
Akka: Simpler Concurrency, Scalability & Fault-tolerance through Actors. Jonas Bonér Viktor Klang

Above the Clouds: Introducing Akka. Jonas Bonér Scalable Solutions

[ «*< > t] open source t. Akka Essentials. Akka's actor-based, distributed, concurrent, and scalable Java applications

Akka. Developing SEDA Based Applications

Favoring Isolated Mutability The Actor Model of Concurrency. CSCI 5828: Foundations of Software Engineering Lecture 24 04/11/2012

Identity, State and Values

Executive Summary. It is important for a Java Programmer to understand the power and limitations of concurrent programming in Java using threads.

CMPT 435/835 Tutorial 1 Actors Model & Akka. Ahmed Abdel Moamen PhD Candidate Agents Lab

Scala Actors. Scalable Multithreading on the JVM. Philipp Haller. Ph.D. candidate Programming Methods Lab EPFL, Lausanne, Switzerland

Concurrency. Unleash your processor(s) Václav Pech

Persistent Data Structures and Managed References

Building Reactive Applications with Akka

Inside Broker How Broker Leverages the C++ Actor Framework (CAF)

CS Programming Languages: Scala

Building loosely coupled and scalable systems using Event-Driven Architecture. Jonas Bonér Patrik Nordwall Andreas Källberg

Akka Java Documentation

The Actor Model. Towards Better Concurrency. By: Dror Bereznitsky

Tackling Concurrency With STM. Mark Volkmann 10/22/09

Tackling Concurrency With STM

Covers Scala 2.10 IN ACTION. Nilanjan Raychaudhuri. FOREWORD BY Chad Fowler MANNING

Combining Concurrency Abstractions

Clojure Lisp for the Real #clojure

Reactive App using Actor model & Apache Spark. Rahul Kumar Software

Clojure Lisp for the Real clojure.com

Introduction Basics Concurrency Conclusion. Clojure. Marcel Klinzing. December 13, M. Klinzing Clojure 1/18

Time and Space. Indirect communication. Time and space uncoupling. indirect communication

The Actor Model, Part Two. CSCI 5828: Foundations of Software Engineering Lecture 18 10/23/2014

Reference types in Clojure. April 2, 2014

Erlang 101. Google Doc

Stuart

Scaling out with Akka Actors. J. Suereth

FRANCESCO CESARINI. presents ERLANG/OTP. Francesco Cesarini Erlang

Seminar on Languages for Scientific Computing Aachen, 6 Feb Navid Abbaszadeh.

Threads Questions Important Questions

Message Passing. Advanced Operating Systems Tutorial 7

Actors in the Small. Making Actors more Useful. Bill La

Fault Tolerance. Goals: transparent: mask (i.e., completely recover from) all failures, or predictable: exhibit a well defined failure behavior

Advances in Programming Languages

Scala Java Sparkle Monday, April 16, 2012

Akka Scala Documentation

Scaling Up & Out. Haidar Osman

Using the SDACK Architecture to Build a Big Data Product. Yu-hsin Yeh (Evans Ye) Apache Big Data NA 2016 Vancouver

What the optimizer does to your code

Effective v2.0. Jamie Allen Sr. Director of Global Services

Distributed Data Analytics Akka Actor Programming

Evolution of an Apache Spark Architecture for Processing Game Data

9.1 Know when to use Actors

Fault Tolerance Causes of failure: process failure machine failure network failure Goals: transparent: mask (i.e., completely recover from) all

Philipp Wille. Beyond Scala s Standard Library

Indirect Communication

Overview. CMSC 330: Organization of Programming Languages. Concurrency. Multiprocessors. Processes vs. Threads. Computation Abstractions

Clojure Concurrency Constructs. CSCI 5828: Foundations of Software Engineering Lecture 12 10/02/2014

CONCURRENCY AND THE ACTOR MODEL

Reminder from last time

02 - Distributed Systems

Exceptional Actors. Implementing Exception Handling for Encore. Sahand Shamal Taher

02 - Distributed Systems

Clojure. A Dynamic Programming Language for the JVM. Rich Hickey

Clojure. A (not-so-pure) functional approach to concurrency. Paolo Baldan Linguaggi per il Global Computing AA 2016/2017

Programming Paradigms for Concurrency Lecture 10 The Actor Paradigm

Concurrent & Distributed Systems Supervision Exercises

Simon Peyton Jones (Microsoft Research) Tokyo Haskell Users Group April 2010

Page 1. CS 194: Distributed Systems Distributed Coordination-based Systems. Coordination Systems. Taxonomy of Coordination Models

Akka Java Documentation

SDC 2015 Santa Clara

Scheduling Transactions in Replicated Distributed Transactional Memory

Threads and Continuations COS 320, David Walker

Shared state model. April 3, / 29

Chapter 2 Distributed Information Systems Architecture

AUTOBEST: A United AUTOSAR-OS And ARINC 653 Kernel. Alexander Züpke, Marc Bommert, Daniel Lohmann

Consistency in Distributed Systems

Cliff Moon. Bottleneck Whack-A-Mole. Thursday, March 21, 13

Multi-core Parallelization in Clojure - a Case Study

Akka. Reactive Applications made easy

CS 162 Operating Systems and Systems Programming Professor: Anthony D. Joseph Spring Lecture 22: Remote Procedure Call (RPC)

Making most of Scala. Akka, Scala, Spray, Specs2; all in 50 minutes!

2. The system of... generally ran one job at a time. These were called single stream batch processing.

IV. Process Synchronisation

CS 6112 (Fall 2011) Foundations of Concurrency

Achieving Scalability and High Availability for clustered Web Services using Apache Synapse. Ruwan Linton WSO2 Inc.

Manchester University Transactions for Scala

Problems with Concurrency. February 19, 2014

An actor system for Scala.js Semester project, Fall 2013

ΠΙΝΑΚΑΣ ΠΛΑΝΟΥ ΕΚΠΑΙΔΕΥΣΗΣ

TWO-PHASE COMMIT ATTRIBUTION 5/11/2018. George Porter May 9 and 11, 2018


Concurrency: Past and Present

A Survey of Concurrency Constructs. Ted Leung Sun

CSE 230. Concurrency: STM. Slides due to: Kathleen Fisher, Simon Peyton Jones, Satnam Singh, Don Stewart

Solved MCQs on Operating System Principles. Set-1

! How is a thread different from a process? ! Why are threads useful? ! How can POSIX threads be useful?

!! How is a thread different from a process? !! Why are threads useful? !! How can POSIX threads be useful?

An overview of (a)sync & (non-) blocking

JAVA CONCURRENCY FRAMEWORK. Kaushik Kanetkar

Exam Questions 1Z0-895

Concurrency User Guide

Producer Consumer in Ada

Parallel Programming Languages COMP360

Erlang. Joe Armstrong

Principles of Software Construction: Objects, Design, and Concurrency. Concurrency: More Design Tradeoffs School of Computer Science

Transcription:

Akka: Simpler Concurrency, Scalability & Fault-tolerance through Actors Jonas Bonér Scalable Solutions jonas@jonasboner.com twitter: @jboner

The problem It is way too hard to build: 1. correct highly concurrent systems 2. truly scalable systems 3. fault-tolerant systems that self-heals...using state-of-the-art tools

Vision Simpler Concurrency Scalability Fault-tolerance Through one single unified Programming model Runtime service

Manage system overload

Scale up & Scale out

Replicate and distribute for fault-tolerance

Automatic & adaptive load balancing

Introducing Concurrency Scalability Fault-tolerance Actors STM Agents Dataflow Distributed Secure Persistent Open Source Clustered

Architecture Core Modules

Architecture Add-on Modules Add-on Modules

Architecture Enterprise Modules

Actors one tool in the toolbox

Akka Actors

Actor Model of Concurrency Implements Message-Passing Concurrency Share NOTHING Isolated lightweight processes Communicates through messages Asynchronous and non-blocking Each actor has a mailbox (message queue)

Actor Model of Concurrency Easier to reason about Raised abstraction level Easier to avoid Race conditions Deadlocks Starvation Live locks

Two different models Thread-based Event-based Very lightweight (600 bytes per actor) Can easily create millions on a single workstation (13 million on 8 G RAM) Does not consume a thread

Actors case object Tick class Counter extends Actor { private var counter = 0 } def receive = { case Tick => counter += 1 println(counter) }

Create Actors import Actor._ val counter = actorof[counter] counter is an ActorRef

Create Actors val actor = actorof(new MyActor(..)) create actor with constructor arguments

Start actors val counter = actorof[counter] counter.start

Start actors val counter = actorof[counter].start

Stop actors val counter = actorof[counter].start counter.stop

init & shutdown callbacks class MyActor extends Actor { override def prestart = { }... // called after start } override def poststop = { }... // called before stop

the self reference class RecursiveActor extends Actor { private var counter = 0 self.id = service:recursive } def receive = { case Tick => counter += 1 self! Tick }

Actors anonymous val worker = actor { } case Work(fn) => fn()

Send:! counter! Tick fire-forget

Send:! counter.sendoneway(tick) fire-forget

Send:!! val result = (actor!! Message).as[String] uses Future under the hood (with time-out)

Send:!! val result = counter.sendrequestreply(tick) uses Future under the hood (with time-out)

Send:!!! // returns a future val future = actor!!! Message future.await val result = future.get... Futures.awaitOne(List(fut1, fut2,...)) Futures.awaitAll(List(fut1, fut2,...)) returns the Future directly

Send:!!! val result = counter.sendrequestreplyfuture(tick) returns the Future directly

Reply class SomeActor extends Actor { def receive = { case User(name) => // use reply self.reply( Hi + name) } }

Reply class SomeActor extends Actor { def receive = { case User(name) => // store away the sender // to use later or // somewhere else... = self.sender } }

Reply class SomeActor extends Actor { def receive = { case User(name) => // store away the sender future // to resolve later or // somewhere else... = self.senderfuture } }

Immutable messages // define the case class case class Register(user: User) // create and send a new case class message actor! Register(user) // tuples actor! (username, password) // lists actor! List( bill, bob, alice )

ActorRegistry val actors = ActorRegistry.actors val actors = ActorRegistry.actorsFor[TYPE] val actors = ActorRegistry.actorsFor(id) val actor = ActorRegistry.actorFor(uuid) ActorRegistry.foreach(fn) ActorRegistry.shutdownAll

TypedActor

Typed Actors class CounterImpl extends TypedActor with Counter { private var counter = 0; } def count = { counter += 1 println(counter) }

Create Typed Actor val counter = TypedActor.newInstance( classof[counter], classof[counterimpl])

Send message counter.count fire-forget

Request Reply val hits = counter.getnrofhits uses Future under the hood (with time-out)

the context reference class PingImpl extends TypedActor with Ping { def hit(count: Int) = { val pong = getcontext.getsender.asinstanceof[pong] pong.hit(count += 1) } }

Actors: config akka { version = "0.10" time- unit = "seconds" actor { timeout = 5 throughput = 5 } }

Scalability Benchmark Simple Trading system Synchronous Scala version Scala Library Actors 2.8.0 Fire-forget Request-reply (Futures) Akka Fire-forget (Hawt dispatcher) Fire-forget (default dispatcher) Request-reply Run it yourself: http://github.com/patriknw/akka-sample-trading

Agents yet another tool in the toolbox

Agents val agent = Agent(5) // send function asynchronously agent send (_ + 1) val result = agent() // deref... // use result agent.close Cooperates with STM

Akka Dispatchers

Dispatchers Executor-based Dispatcher Executor-based Work-stealing Dispatcher Hawt Dispatcher Thread-based Dispatcher

Dispatchers object Dispatchers { object globalhawtdispatcher extends HawtDispatcher... def newexecutorbasedeventdrivendispatcher(name: String) def newexecutorbasedeventdrivenworkstealingdispatcher(name: String) def newhawtdispatcher(aggregate: Boolean) }...

Set dispatcher class MyActor extends Actor { self.dispatcher = Dispatchers.newThreadBasedDispatcher(self) }... actor.dispatcher = dispatcher // before started

Let it crash fault-tolerance

Influenced by Erlang

9 nines

OneForOne fault handling strategy

OneForOne fault handling strategy

OneForOne fault handling strategy

OneForOne fault handling strategy

OneForOne fault handling strategy

OneForOne fault handling strategy

OneForOne fault handling strategy

OneForOne fault handling strategy

AllForOne fault handling strategy

AllForOne fault handling strategy

AllForOne fault handling strategy

AllForOne fault handling strategy

AllForOne fault handling strategy

Supervisor hierarchies

Supervisor hierarchies

Supervisor hierarchies

Supervisor hierarchies

Supervisor hierarchies

Supervisor hierarchies

Fault handlers AllForOneStrategy( maxnrofretries, withintimerange) OneForOneStrategy( maxnrofretries, withintimerange)

Linking link(actor) unlink(actor) startlink(actor) spawnlink[myactor]

trapexit trapexit = List( classof[serviceexception], classof[persistenceexception])

Supervision class Supervisor extends Actor { trapexit = List(classOf[Throwable]) faulthandler = Some(OneForOneStrategy(5, 5000)) } def receive = { case Register(actor) => link(actor) }

Manage failure class FaultTolerantService extends Actor {... override def prerestart(reason: Throwable) = {... // clean up before restart } override def postrestart(reason: Throwable) = {... // init after restart } }

Remote Actors

Remote Server // use host & port in config RemoteNode.start RemoteNode.start("localhost", 9999) Scalable implementation based on NIO (Netty) & Protobuf

Two types of remote actors Client managed Server managed

Client-managed supervision works across nodes // methods in Actor class spawnremote[myactor](host, port) spawnlinkremote[myactor](host, port) startlinkremote(actor, host, port)

Client-managed moves actor to server client manages through proxy val actorproxy = spawnlinkremote[myactor]( darkstar, 9999) actorproxy! message

Server-managed register and manage actor on server client gets dumb proxy handle RemoteNode.register( service:id, actorof[myservice]) server part

Server-managed val handle = RemoteClient.actorFor( service:id, darkstar, 9999) handle! message client part

Cluster Membership Cluster.relayMessage( classof[typeofactor], message) for (endpoint <- Cluster) spawnremote[typeofactor]( endpoint.host, endpoint.port)

STM yet another tool in the toolbox

What is STM? 71

STM: overview See the memory (heap and stack) as a transactional dataset Similar to a database begin commit abort/rollback Transactions are retried automatically upon collision Rolls back the memory on abort

Managed References Separates Identity from Value - Values are immutable - Identity (Ref) holds Values Change is a function Compare-and-swap (CAS) Abstraction of time Must be used within a transaction

atomic import se.scalablesolutions.akka.stm.local._ atomic {... } atomic { }... // transactions compose!!!

Managed References Typical OO: direct access to mutable objects foo :a :b :c :d :e?? 42? 6 Managed Reference: separates Identity & Value foo @foo :a :b :c :d :e "fred" "ethel" 42 17 6 Copyright Rich Hickey 2009

Managed References Separates Identity from Value - Values are immutable - Identity (Ref) holds Values Change is a function Compare-and-swap (CAS) Abstraction of time Must be used within a transaction

Managed References import se.scalablesolutions.akka.stm.local._ // giving an initial value val ref = Ref(0) // specifying a type but no initial value val ref = Ref[Int]

Managed References val ref = Ref(0) atomic { ref.set(5) } // - > 0 atomic { ref.get } // - > 5

Managed References val ref = Ref(0) atomic { ref alter (_ + 5) } // - > 5 val inc = (i: Int) => i + 1 atomic { ref alter inc } // - > 6

Managed References val ref = Ref(1) val anotherref = Ref(3) atomic { for { value1 <- ref value2 <- anotherref } yield (value1 + value2) } // - > Ref(4) val emptyref = Ref[Int] atomic { for { value1 <- ref value2 <- emptyref } yield (value1 + value2) } // - > Ref[Int]

Transactional datastructures // using initial values val map = TransactionalMap("bill" - > User("bill")) val vector = TransactionalVector(Address("somewhere")) // specifying types val map = TransactionalMap[String, User] val vector = TransactionalVector[Address]

life-cycle listeners atomic { deferred { // executes when transaction commits } compensating { // executes when transaction aborts } }

Actors + STM = Transactors

Transactors class UserRegistry extends Transactor { private lazy val storage = TransactionalMap[String, User]() } def receive = { case NewUser(user) => storage + (user.name - > user)... }

Transactors

Start transaction Transactors

Transactors Start transaction Send message

Transactors Start transaction Send message

Transactors Start transaction Send message Update state within transaction

Transactors Start transaction Send message Update state within transaction

Transactors Start transaction Send message Update state within transaction

Transactors Start transaction Send message Update state within transaction

Transactors Start transaction Send message Update state within transaction

Transactors Start transaction Send message Update state within transaction

Transactors Start transaction Send message Update state within transaction Transaction fails

Transactors Start transaction Send message Update state within transaction Transaction fails

Transactors

Transactors

Transactors

Transactors

Transactors

Transactors

Transactors Transaction automatically retried

blocking transactions class Transferer extends Actor { implicit val txfactory = TransactionFactory( blockingallowed = true, trackreads = true, timeout = 60 seconds) } def receive = { case Transfer(from, to, amount) => atomic { if (from.get < amount) { log.info("not enough money - retrying") retry } log.info("transferring") from alter (_ - amount) to alter (_ + amount) } }

either-orelse atomic { either { if (left.get < amount) { log.info("not enough on left - retrying") retry } log.info("going left") } orelse { if (right.get < amount) { log.info("not enough on right - retrying") retry } log.info("going right") } }

STM: config akka { stm { max- retries = 1000 timeout = 10 write- skew = true blocking- allowed = false interruptible = false speculative = true quick- release = true propagation = requires trace- level = none hooks = true jta- aware = off } }

Modules

Akka Persistence

STM gives us Atomic Consistent Isolated

Persistence module turns STM into Atomic Consistent Isolated Durable

Akka Persistence API // transactional Cassandra- backed Map val map = CassandraStorage.newMap // transactional Redis- backed Vector val vector = RedisStorage.newVector // transactional Mongo- backed Ref val ref = MongoStorage.newRef

For Redis only (so far) val queue: PersistentQueue[ElementType] = RedisStorage.newQueue val set: PersistentSortedSet[ElementType] = RedisStorage.newSortedSet

Akka Spring

Spring integration <beans> <akka:typed- actor id="myactiveobject" interface="com.biz.mypojo" implementation="com.biz.mypojo" transactional="true" timeout="1000" />... </beans>

Spring integration <akka:supervision id="my- supervisor"> <akka:restart- strategy failover="allforone" retries="3" timerange="1000"> <akka:trap- exits> <akka:trap- exit>java.io.ioexception</akka:trap- exit> </akka:trap- exits> </akka:restart- strategy> <akka:typed- actors> <akka:typed- actor interface="com.biz.mypojo" implementation="com.biz.mypojoimpl" lifecycle="permanent" timeout="1000"> </akka:typed- actor> </akka:typed- actors> </akka:supervision>

Akka Camel

Camel: consumer class MyConsumer extends Actor with Consumer { def endpointuri = "file:data/input" } def receive = { case msg: Message => log.info("received %s" format msg.bodyas(classof[string])) }

Camel: consumer class MyConsumer extends Actor with Consumer { def endpointuri = "jetty:http://0.0.0.0:8877/camel/test" } def receive = { case msg: Message => reply("hello %s" format msg.bodyas(classof[string])) }

Camel: producer class CometProducer extends Actor with Producer { def endpointuri = "cometd://localhost:8111/test" } def receive = produce // use default impl

Camel: producer val producer = actorof[cometproducer].start val time = "Current time: " + new Date producer! time

Akka HotSwap

HotSwap actor! HotSwap({ // new body case Ping =>... case Pong =>... })

HotSwap self.become({ // new body case Ping =>... case Pong =>... })

How to run it? Deploy as dependency JAR in WEB-INF/lib etc. Run as stand-alone microkernel OSGi-enabled; drop in any OSGi container (Spring DM server, Karaf etc.)

Akka Kernel

Start Kernel java - jar akka- 1.0- SNAPSHOT.jar \ - Dakka.config=<path>/akka.conf

...and much much more REST PubSub FSM Security Comet OSGi Web Guice

Learn more http://akkasource.org

EOF