Jonas Bonérjaoo.dk/dl/2010/GeekNight_Slides/akka_2_h_talk.pdf · Akka is the platform for the next...

Post on 22-May-2020

2 views 0 download

transcript

Akka:Simpler Concurrency, Scalability &

Fault-tolerance through Actors

Jonas Bonérjonas@jonasboner.com

twtr: @jboner

Wednesday, August 11, 2010

•Writing correct concurrent applications is too hard

•Scaling out applications is too hard

•Writing highly fault-tolerant applications is too hard

We believe that...

Wednesday, August 11, 2010

It doesn’t have to be like this

We need to raise the abstraction level

Wednesday, August 11, 2010

Locks & Threadsare...

Wednesday, August 11, 2010

...sometimes

plain evil

Wednesday, August 11, 2010

...but always the

wrong default

Wednesday, August 11, 2010

“Threads are to Concurrency as Witchcraft is to Physics”

“Hanging by a thread is the punishment for Shared State Concurrency”

- Gilad Bracha

Wednesday, August 11, 2010

Introducing

STM

Persistent

Distributed

RESTful Secure

Agents

Dataflow Open Source

Actors

Wednesday, August 11, 2010

Akka is the platform for the next generation event-driven, scalable and fault-tolerant architectures on the JVM

Simpler ConcurrencyWrite simpler concurrent (yet correct) applications using Actors, STM & Transactors.

Event-driven ArchitectureThe perfect platform for asynchronous event-driven architectures. Never block.

True ScalabilityScale out on multi-core or multiple nodes using asynchronous message passing.

Fault-toleranceEmbrace failure. Write applications that self-heal using Erlang-style Actor supervisor hierarchies.

Transparent RemotingRemote Actors gives you a high-performance transparent distributed programming model.

Java & Scala API

OVERVIEW

Wednesday, August 11, 2010

ARCHITECTURE

CORE SERVICES

Wednesday, August 11, 2010

ARCHITECTURE

ADD-ON MODULES

Wednesday, August 11, 2010

ARCHITECTURE

ENTERPRISEMODULES

Wednesday, August 11, 2010

Actorsone tool in the toolbox

Wednesday, August 11, 2010

• 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

Wednesday, August 11, 2010

Actor Model of Concurrency

• Easier to reason about• Raised abstraction level• Easier to avoid–Race conditions–Deadlocks–Starvation–Live locks

Wednesday, August 11, 2010

Akka Actors

Wednesday, August 11, 2010

Two different models

• Thread-based• Event-based– Very lightweight (600 bytes per actor)– Can easily create millions on a single workstation (6.5 million on 4 G RAM)– Does not consume a thread

Wednesday, August 11, 2010

Actor

Wednesday, August 11, 2010

caseobjectTick

classCounterextendsActor{privatevarcounter=0

defreceive={caseTick=>counter+=1println(counter)}}

Actors

Wednesday, August 11, 2010

importActor._

valcounter=actorOf[Counter]

Create Actors

counter is an ActorRef

Wednesday, August 11, 2010

valactor=actorOf(newMyActor(..))

Create Actors

create actor with constructor arguments

Wednesday, August 11, 2010

valcounter=actorOf[Counter]counter.start

Start actors

Wednesday, August 11, 2010

valcounter=actorOf[Counter].start

Start actors

Wednesday, August 11, 2010

valcounter=actorOf[Counter].startcounter.stop

Stop actors

Wednesday, August 11, 2010

classMyActorextendsActor{

overridedefinit={...//calledafter‘start’}

overridedefshutdown={...//calledbefore‘stop’}}

init & shutdown callbacks

Wednesday, August 11, 2010

classRecursiveActorextendsActor{privatevarcounter=0self.id=“service:recursive”

defreceive={caseTick=>counter+=1self!Tick}}

the self reference

Wednesday, August 11, 2010

valworker=actor{caseWork(fn)=>fn()}

Actorsanonymous

Wednesday, August 11, 2010

counter!Tick

Send: !

fire-forget

Wednesday, August 11, 2010

valresult=(actor!!Message).as[String]

Send: !!

uses Future under the hood (with time-out)

Wednesday, August 11, 2010

valresultOption=actor!!Message

valresult=resultOption.getOrElse(defaultResult)

valresult=resultOption.getOrElse(thrownewException(“Timedout”)))

Send: !!

returns an Option[ResultType] directly

Wednesday, August 11, 2010

//returnsafuturevalfuture=actor!!!Messagefuture.awaitvalresult=future.get

...Futures.awaitOne(List(fut1,fut2,...))Futures.awaitAll(List(fut1,fut2,...))

Send: !!!

returns the Future directly

Wednesday, August 11, 2010

classSomeActorextendsActor{defreceive={caseUser(name)=>//usereplyself.reply(“Hi”+name)}}

Reply

Wednesday, August 11, 2010

classSomeActorextendsActor{defreceive={caseUser(name)=>//storeawaythesender//touselateror//somewhereelse...=self.sender}}

Reply

Wednesday, August 11, 2010

classSomeActorextendsActor{defreceive={caseUser(name)=>//storeawaythesenderfuture//toresolvelateror//somewhereelse...=self.senderFuture}}

Reply

Wednesday, August 11, 2010

UntypedActor

Wednesday, August 11, 2010

publicclassMyUntypedActorextendsUntypedActor{

publicvoidonReceive(Objectmessage)throwsException{if(messageinstanceofString){Stringmsg=(String)message;System.out.println("Receivedmessage:"+msg);}}}

Untyped Actors

Wednesday, August 11, 2010

UntypedActorRefactor=UntypedActor.actorOf(MyUntypedActor.class);

actor.start();

Create UntypedActor

Wednesday, August 11, 2010

classRecursiveActorextendsUntypedActor{getContext().setId(“service:recursive”);

publicvoidonReceive(Objectmessage)throwsException{if(messageinstanceofTick)getContext().sendOneWay(Tick);}}

the context reference

Wednesday, August 11, 2010

actor.sendOneWay(msg);

sendOneWay

fire-forget

Wednesday, August 11, 2010

Objectres=actor.sendRequestReply(msg);

sendRequestReply

uses Future under the hood (with time-out)

Wednesday, August 11, 2010

//returnsafutureFuturefuture=actor.sendRequestReplyFuture(msg);

future.await();Objectresult=future.get();

sendRequestReplyFuture

returns the Future directly

Wednesday, August 11, 2010

publicclassHelloUntypedActorextendsUntypedActor{

publicvoidonReceive(Objectmessage)throwsException{if(messageinstanceofString){Stringname=(String)message;//usereplygetContext().reply(“Hi”+name);}}}

reply

Wednesday, August 11, 2010

TypedActor

Wednesday, August 11, 2010

publicclassCounterImplextendsTypedActorimplementsCounter{

privateintcounter=0;

publicvoidcount(){counter++;System.out.println(counter);}}

Typed Actors

Wednesday, August 11, 2010

Countercounter=(Counter)TypedActor.newInstance(Counter.class,CounterImpl.class,1000);

Create Typed Actor

Wednesday, August 11, 2010

counter.count();

Send message

fire-forget

Wednesday, August 11, 2010

inthits=counter.getNrOfHits();

Request Reply

uses Future under the hood (with time-out)

Wednesday, August 11, 2010

classPingImplextendsTypedActorimplementsPing{publicvoidhit(intcount){Pongpong=(Pong)getContext().getSender();pong.hit(count++);}}

the context reference

Wednesday, August 11, 2010

//definethecaseclasscaseclassRegister(user:User)

//createandsendanewcaseclassmessageactor!Register(user)

//tuplesactor!(username,password)

//listsactor!List(“bill”,“bob”,“alice”)

Immutable messages

Wednesday, August 11, 2010

akka{version="0.9.1"time‐unit="seconds"actor{timeout=5throughput=5}}

Actors: config

Wednesday, August 11, 2010

Scalability BenchmarkSimple Trading system

• Synchronous Scala version• Scala Library Actors 2.8.0 • Akka request-reply• Akka fire-forget (default dispatcher)• Akka fire-forget (Hawt dispatcher)

Run it yourself: http://github.com/patriknw/akka-sample-trading

Wednesday, August 11, 2010

Performance Microbenchmark

•Chameneos benchmark• http://shootout.alioth.debian.org/

• +4 times faster• Run it yourself (3 different benchmarks):

• http://github.com/jboner/akka-bench

Akka 0.8.1 3815

Scala Actors 2.8.0 (react) 16086

Wednesday, August 11, 2010

Agentsyet another tool in the toolbox

Wednesday, August 11, 2010

valagent=Agent(5)

//sendfunctionasynchronouslyagentsend(_+1)

valresult=agent()//deref...//useresult

agent.close

Agents

Cooperates with STMWednesday, August 11, 2010

Akka Dispatchers

Wednesday, August 11, 2010

Dispatchers• Executor-based Dispatcher• Executor-based Work-stealing Dispatcher• Hawt Dispatcher• Reactor-based Dispatcher• Reactor-based Single-thread Dispatcher• Thread-based Dispatcher

Wednesday, August 11, 2010

objectDispatchers{objectglobalHawtDispatcherextendsHawtDispatcher...defnewExecutorBasedEventDrivenDispatcher(name:String)

defnewExecutorBasedEventDrivenWorkStealingDispatcher(name:String)

defnewHawtDispatcher(aggregate:Boolean)

...}

Dispatchers

Wednesday, August 11, 2010

classMyActorextendsActor{self.dispatcher=Dispatchers.newThreadBasedDispatcher(self)...}

actor.dispatcher=dispatcher//beforestarted

Set dispatcher

Wednesday, August 11, 2010

valdispatcher=Dispatchers.newExecutorBasedEventDrivenDispatcherdispatcher.withNewThreadPoolWithBoundedBlockingQueue(100).setCorePoolSize(16).setMaxPoolSize(128).setKeepAliveTimeInMillis(60000).setRejectionPolicy(newCallerRunsPolicy).buildThreadPool

EventBasedDispatcherFluent DSL

Wednesday, August 11, 2010

MessageQueues

• Unbounded LinkedBlockingQueue• Bounded LinkedBlockingQueue• Bounded ArrayBlockingQueue

Bounded SynchronousQueue

Plus different options per queue

Wednesday, August 11, 2010

Let it crash fault-tolerance

Wednesday, August 11, 2010

Stolen from

ErlangWednesday, August 11, 2010

9 nines

Wednesday, August 11, 2010

OneForOne fault handling strategy

Wednesday, August 11, 2010

OneForOne fault handling strategy

Wednesday, August 11, 2010

OneForOne fault handling strategy

Wednesday, August 11, 2010

OneForOne fault handling strategy

Wednesday, August 11, 2010

OneForOne fault handling strategy

Wednesday, August 11, 2010

OneForOne fault handling strategy

Wednesday, August 11, 2010

OneForOne fault handling strategy

Wednesday, August 11, 2010

AllForOnefault handling strategy

Wednesday, August 11, 2010

AllForOnefault handling strategy

Wednesday, August 11, 2010

AllForOnefault handling strategy

Wednesday, August 11, 2010

AllForOnefault handling strategy

Wednesday, August 11, 2010

Supervisor hierarchies

Wednesday, August 11, 2010

Supervisor hierarchies

Wednesday, August 11, 2010

Supervisor hierarchies

Wednesday, August 11, 2010

Supervisor hierarchies

Wednesday, August 11, 2010

AllForOneStrategy(maxNrOfRetries,withinTimeRange)

OneForOneStrategy(maxNrOfRetries,withinTimeRange)

Fault handlers

Wednesday, August 11, 2010

link(actor)unlink(actor)

startLink(actor)spawnLink[MyActor]

Linking

Wednesday, August 11, 2010

trapExit=List(classOf[ServiceException],classOf[PersistenceException])

trapExit

Wednesday, August 11, 2010

classSupervisorextendsActor{trapExit=List(classOf[Throwable])faultHandler=Some(OneForOneStrategy(5,5000))

defreceive={caseRegister(actor)=>link(actor)}}

Supervision

Wednesday, August 11, 2010

classFaultTolerantServiceextendsActor{...overridedefpreRestart(reason:Throwable)={...//cleanupbeforerestart}overridedefpostRestart(reason:Throwable)={...//initafterrestart}}

Manage failure

Wednesday, August 11, 2010

valsupervisor=Supervisor(SupervisorConfig(RestartStrategy(AllForOne,3,10000),Supervise(actor1,LifeCycle(Permanent))::Supervise(actor2,LifeCycle(Temporary))::Nil))

Declarative config

Wednesday, August 11, 2010

valactors=ActorRegistry.actorsvalactors=ActorRegistry.actorsFor[TYPE]valactors=ActorRegistry.actorsFor(id)valactor=ActorRegistry.actorFor(uuid)ActorRegistry.foreach(fn)ActorRegistry.shutdownAll

ActorRegistry

Wednesday, August 11, 2010

Remote Actors

Wednesday, August 11, 2010

//usehost&portinconfigRemoteNode.start

RemoteNode.start("localhost",9999)

Remote Server

Scalable implementation based on NIO (Netty) & Protobuf

Wednesday, August 11, 2010

•Client-initated and managed•Server-initiated and managed

Two types of

remote actors

Wednesday, August 11, 2010

//methodsinActorclass

spawnRemote[MyActor](host,port)

spawnLinkRemote[MyActor](host,port)

startLinkRemote(actor,host,port)

Client-managedsupervision works across nodes

Wednesday, August 11, 2010

valactorProxy=spawnLinkRemote[MyActor](“darkstar”,9999)

actorProxy!message

Client-managedmoves actor to server

client manages through proxy

Wednesday, August 11, 2010

RemoteNode.register(“service:id”,actorOf[MyService])

Server-managedregister and manage actor on server

client gets “dumb” proxy handle

server part

Wednesday, August 11, 2010

valhandle=RemoteClient.actorFor(“service:id”,“darkstar”,9999)

handle!message

Server-managed

client part

Wednesday, August 11, 2010

Cluster.relayMessage(classOf[TypeOfActor],message)

for(endpoint<‐Cluster)spawnRemote[TypeOfActor](endpoint.host,endpoint.port)

Cluster Membership

Wednesday, August 11, 2010

akka{remote{service=onhostname="homer.lan"port=9999connection‐timeout=1000}}

Remote config

Wednesday, August 11, 2010

STMyet another tool in the toolbox

Wednesday, August 11, 2010

84

What is STM?

Wednesday, August 11, 2010

85

Software Transactional Memory (STM)

Wednesday, August 11, 2010

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

Wednesday, August 11, 2010

> Transactions can nest> Transactions compose (yipee!!)atomic{..atomic{..}}

STM: overview

Wednesday, August 11, 2010

>All operations in scope of a transaction:Need to be idempotentCan’t have side-effects

STM: restrictions

Wednesday, August 11, 2010

• Typical OO: direct access to mutable objects

Managed ReferencesTypical OO - Direct

references to Mutable Objects

• Unifies identity and value

• Anything can change at any time

• Consistency is a user problem

• Encapsulation doesn’t solve concurrency problems

?

?

42

?

6:e

:d

:c

:b

:a

foo

•Managed Reference: separates Identity & ValueClojure - Indirect references

to Immutable Objects

6

17

"ethel"

"fred"

42

:e

:d

:c

:b

:afoo

@foo

• Separates identity and value

• Obtaining value requires explicit dereference

• Values can never change

• Never an inconsistent value

• Encapsulation is orthogonal

Copyright Rich Hickey 2009

Wednesday, August 11, 2010

• 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

Wednesday, August 11, 2010

valref=Ref(Map[String,User]())

valusers=ref.get

valnewUsers=users+(“bill”‐>User(“bill”))

ref.swap(newUsers)

Managed References

Wednesday, August 11, 2010

valusers=TransactionalMap[String,User]()

valusers=TransactionalVector[User]()

Transactionaldatastructures

Wednesday, August 11, 2010

importTransaction.Local._

atomic{...atomic{//nestedtransactionscompose...//dosomethingwithinatransaction}}

atomic

Wednesday, August 11, 2010

Actors + STM = Transactors

Wednesday, August 11, 2010

classUserRegistryextendsTransactor{privatelazyvalstorage=TransactionalMap[String,User]()

defreceive={caseNewUser(user)=>storage+(user.name‐>user)...}}

Transactors

Wednesday, August 11, 2010

Transactors

Wednesday, August 11, 2010

TransactorsStart transaction

Wednesday, August 11, 2010

TransactorsStart transaction

Send message

Wednesday, August 11, 2010

TransactorsStart transaction

Send message

Wednesday, August 11, 2010

TransactorsStart transaction

Send message

Update statewithin transaction

Wednesday, August 11, 2010

TransactorsStart transaction

Send message

Update statewithin transaction

Wednesday, August 11, 2010

TransactorsStart transaction

Send message

Update statewithin transaction

Wednesday, August 11, 2010

TransactorsStart transaction

Send message

Update statewithin transaction

Wednesday, August 11, 2010

TransactorsStart transaction

Send message

Update statewithin transaction

Wednesday, August 11, 2010

TransactorsStart transaction

Send message

Update statewithin transaction

Wednesday, August 11, 2010

TransactorsStart transaction

Send message

Update statewithin transaction

Transaction fails

Wednesday, August 11, 2010

TransactorsStart transaction

Send message

Update statewithin transaction

Transaction fails

Wednesday, August 11, 2010

Transactors

Wednesday, August 11, 2010

Transactors

Wednesday, August 11, 2010

Transactors

Wednesday, August 11, 2010

Transactors

Wednesday, August 11, 2010

Transactors

Wednesday, August 11, 2010

Transactors

Wednesday, August 11, 2010

TransactorsTransactionautomatically

retried

Wednesday, August 11, 2010

akka{stm{fair=onjta‐aware=offtimeout=5}}

STM: config

Wednesday, August 11, 2010

TransactionManagement.disableTransactions

STM: disable

Wednesday, August 11, 2010

Akka Serialization

Wednesday, August 11, 2010

SerializersScala JSONJava JSONProtobufSBinary

JavaWednesday, August 11, 2010

valfoo=newFoovaljson=Serializer.ScalaJSON.out(foo)valfooCopy=Serializer.ScalaJSON.in(json).asInstanceOf[Foo]

SerializersScala 2 JSON & JSON 2 Scala

Wednesday, August 11, 2010

importsbinary.DefaultProtocol._valusers=("user1","passwd1")::("user2","passwd2")::("user3","passwd3")::Nilvalbytes=Serializer.SBinary.out(users)

valusersCopy:List[Tuple2[String,String]]]=Serializer.SBinary.in(bytes)

SerializersScala 2 Binary & Binary 2 Scala

Wednesday, August 11, 2010

valpojo=ProtobufPOJO.getDefaultInstance.toBuilder.setId(1).setName("protobuf").setStatus(true).buildvalbytes=pojo.toByteArray

valpojoCopy=Serializer.Protobuf.in(bytes,classOf[ProtobufPOJO])

SerializersProtobuf

Wednesday, August 11, 2010

caseclassMyMessage(id:String,value:Tuple2[String,Int])extendsSerializable.ScalaJSON

valmessage=MyMessage("id",("hello",34))valjson=message.toJSON

Serializable

Wednesday, August 11, 2010

Modules

Wednesday, August 11, 2010

Akka Spring

Wednesday, August 11, 2010

<beans><akka:typed‐actorid="myActiveObject"interface="com.biz.MyPOJO"implementation="com.biz.MyPOJO"transactional="true"timeout="1000"/>...</beans>

Spring integration

Wednesday, August 11, 2010

<akka:supervisionid="my‐supervisor">

<akka:restart‐strategyfailover="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‐actorinterface="com.biz.MyPOJO"implementation="com.biz.MyPOJOImpl"lifecycle="permanent"timeout="1000"></akka:typed‐actor></akka:typed‐actors></akka:supervision>

Spring integration

Wednesday, August 11, 2010

Akka Camel

Wednesday, August 11, 2010

classMyConsumerextendsActorwithConsumer{defendpointUri="file:data/input"defreceive={casemsg:Message=>log.info("received%s"formatmsg.bodyAs(classOf[String]))}}

Camel: consumer

Wednesday, August 11, 2010

classMyConsumerextendsActorwithConsumer{defendpointUri="jetty:http://0.0.0.0:8877/camel/test"defreceive={casemsg:Message=>reply("Hello%s"formatmsg.bodyAs(classOf[String]))}}

Camel: consumer

Wednesday, August 11, 2010

classCometProducerextendsActorwithProducer{defendpointUri="cometd://localhost:8111/test"defreceive=produce//usedefaultimpl}

Camel: producer

Wednesday, August 11, 2010

valproducer=actorOf[CometProducer].start

valtime="Currenttime:"+newDateproducer!time

Camel: producer

Wednesday, August 11, 2010

Akka Persistence

Wednesday, August 11, 2010

STM gives usAtomicConsistentIsolated

Wednesday, August 11, 2010

AtomicConsistentIsolatedDurable

Persistence module turns STM into

Wednesday, August 11, 2010

Akka Persistence API

//transactionalCassandra‐backedMapvalmap=CassandraStorage.newMap

//transactionalRedis‐backedVectorvalvector=RedisStorage.newVector

//transactionalMongo‐backedRefvalref=MongoStorage.newRef

Wednesday, August 11, 2010

Get data by id

//transactionalCassandra‐backedMapvalmap=CassandraStorage.getMap(uuid)

//transactionalRedis‐backedVectorvalvector=RedisStorage.getVector(uuid)

//transactionalMongo‐backedRefvalref=MongoStorage.getRef(uuid)

Wednesday, August 11, 2010

For Redis only (so far)

valqueue:PersistentQueue[ElementType]=RedisStorage.newQueue

valset:PersistentSortedSet[ElementType]=RedisStorage.newSortedSet

Wednesday, August 11, 2010

Akka HotSwap

Wednesday, August 11, 2010

HotSwapactor!HotSwap(Some({//newbodycasePing=>...casePong=>...}))

Wednesday, August 11, 2010

Akka AMQP

Wednesday, August 11, 2010

valproducer=AMQP.newProducer(config,hostname,port,exchangeName,serializer,None,None,//listeners100)

producer!Message(“Hithere”,routingId)

AMQP: producer

Wednesday, August 11, 2010

valconsumer=AMQP.newConsumer(config,hostname,port,exchangeName,ExchangeType.Direct,serializer,None,100,passive,durable,Map[String,AnyRef())

consumer!MessageConsumerListener(queueName,routingId,actor{caseMessage(payload,_,_,_,_)=>...//processmessage})

AMQP: consumer

Wednesday, August 11, 2010

Deploy as dependency JAR in WEB-INF/lib etc. Run as stand-alone microkernel Soon OSGi-enabled, then drop

in any OSGi container (Spring DM server, Karaf etc.)

How to run it?

Wednesday, August 11, 2010

Akka Kernel

Wednesday, August 11, 2010

java‐jarakka‐0.9.1.jar\‐Dakka.config=<path>/akka.conf

Start Kernel

exportAKKA_HOME=<pathtoakkadist>java‐jar$AKKA_HOME/dist/akka‐0.9.1.jar

Or

Wednesday, August 11, 2010

classBoot{valsupervisor=Supervisor(SupervisorConfig(RestartStrategy(OneForOne,3,100),Supervise(actorOf[Counter],LifeCycle(Permanent))::Supervise(actorOf[Chat],LifeCycle(Permanent))::Nil)))}

Boot classes

Wednesday, August 11, 2010

akka{boot=["sample.rest.Boot","sample.comet.Boot"]...}

Boot config

Wednesday, August 11, 2010

Learn morehttp://akkasource.org

Wednesday, August 11, 2010

EOFWednesday, August 11, 2010