Upload
others
View
2
Download
0
Embed Size (px)
Citation preview
Akka:Simpler Concurrency, Scalability &
Fault-tolerance through Actors
Jonas Boné[email protected]
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