Post on 08-May-2015
Scaling Web Apps with Akka
Maciej Matyjas London Scala User Group Skills Matter2010 July 14
“ Simple Scalability, Fault-Tolerance, Concurrency & Remoting through Actors”akkasource.org
Scaling Web Apps with Akka
High AvailabilityQuick Page LoadsFast Reads/Writes
Characteristics TechniquesHardware Load BalancingCachingPartitioning Queues/MessagingReplication CDN
Scaling Web Apps with Akka
Scaling Web Apps with Akka
Range of mountains in Sweden
Open Source Project
Written in Scala with Scala/Java APIs
Scaling Web Apps with Akka
Actors Model
Multi-Core and Cloud Infrastructure
Graceful Failure a la Erlang OTP
Transactions a la Clojure
NoSQL and Distributed Data Stores
Flexible Dispatch Strategies
Actors Model of Computing
Defined in 1963 by Carl Hewitt
Used by Erlang to support reliability (99.9999999% uptime)
Actors Model of Computing
"encapsulates state and behavior into a lightweight process/thread" - Jonas BonérAsynchronous message passing between ActorsMessages are immutableSynchronized mailboxMailbox is read with pattern matchingNo shared stateNo locksSafe concurrency
No shared state +
No locks =
Safe concurrency
ErlangScala Thread basedScala Event basedLift ActorsAkka
Actors Model Implementations
Erlang Actors Example-module(mypackage). myErlangActor() ->receive{msgType, Msg} -> io:format(" p n", [Msg]), myErlangActor()Other -> io:format("wholy canoli, this is unmatched! n"), myErlangActor()end.
c(mypackage).Pid = spawn(fun mypackage:myErlangActor/0).Pid ! {msgType, "Erlang is for the discerning programmer"}.
Scala Thread Based Actorsimport scala.actor.Actorimport scala.actor.Actor._
case class Message(msg: String)
class AnActor extends Actor { def act() = receive { case Message(m) => println(m) case _ => println("unknown message") }}
class Director { val myActor = new AnActor myActor.start myActor ! Message("threedz can haz block?")}
Scala Event Based Actorsimport scala.actor.Actorimport scala.actor.Actor._
case class Message(msg: String)
class AnActor extends Actor { def act() = loop { react { case Message(m) => println(m) case _ => println("unknown message")} } }
class Director { val myActor = new AnActor myActor.start myActor ! Message("eventz iz lightweight?")}
Lift Actors
case class Message(msg: String)
class AnActor extends LiftActor { def messageHandler = { case Message(m) => println(m) case _ => println("unknown message")} }
class Director { val myActor = new AnActor myActor ! Message("Lift Actors is lightest & rulz!")}
Akka Actorsimport se.scalablesolutions.akka.actor.Actorcase class Message(msg: String)
class AnActor extends Actor { def receive = { case Message(m) => println(m) case _ => println("unknown message") }}
class Director { val myActor = Actor.actorOf[AnActor] myActor.start myActor ! Message("akkastic!")}
Leverage Multi-Core and Distributed Cloud Infrastructure
Millions of lightweight actors on commodity hardware
Safe Concurrency
Remote Actors
Leverage Multi-Core and Distributed Cloud Infrastructure: Remote Actorsimport se.scalablesolutions.akka.remote.RemoteNode spawnRemote[MyActor](host, port) spawnLinkRemote[MyActor](host, port)startLinkRemote(myActor, host, port)
Handle Failure Gracefully
"Let it Crash"Actor exceptions w/out supervision do not behave well Remote Actors w/out supervision are unmanaged Linking ActorsSupervisor
Manages linked ActorsNotified when linked Actor crashesOneForOneAllForOne
Works with Remote Actors
Handle Failure Gracefully: Supervisor val supervisor = Supervisor( SupervisorConfig( RestartStrategy(OneForOne, 3, 1000, List(classOf[Exception])), Supervise( actorOf[MyActor], LifeCycle(Permanent)) :: Nil))
supervisor.link(actorOf[MyActor])
class MyActor extends Actor { self.lifeCycle = Some(LifeCycle(Permanent)) override def preRestart(reason: Throwable) { // clean things up }}
Manage Transactions
Software Transactional Memory (STM)Thanks Clojure!Addresses fundamental weakness of Actors ModelHello Shared State!Transactional but still no locksIn memoryMap, Vector, & Ref throw exceptions if modified outside of transactionACI but no D
Transactors Transactional ActorsActors + STMIf Actor's writes clash, rollback memory and retried
Manage Transactions: Transactorsimport se.scalablesolutions.akka.actor.Transactorimport se.scalablesolutions.akka.stm._ class MyActor extends Transactor { def receive = { case Increment(counter) => counter.swap(counter.get + 1) } }
class Director { lazy val counter = Ref(0) //counter.swap(7) // blows up, cannot mutate outside transaction myActor ! Increment(counter)}
NoSQL & Distributed Data Stores
Pluggable Storage Back EndsCassandraRedisMongoDBOthers...
Brings the D in ACIDWorks with STM and Transactors
NoSQL & Distributed Data Stores: Casssandraimport se.scalablesolutions.akka._import stm.Transaction.Local._import persistence.cassandra._ val map = CassandraStorage.newMap(myId)// map += "myKey" -> Value(someSuch) // exceptionatomic { map += "myKey" -> Value(someSuch)}
Flexible Dispatch Strategies
Default is Single-threaded, Event-based dispatcher Work-stealing, Event-based Reactor-base, Event-drivenThread-basedEvent-based
Flexible Dispatch Strategies
class MyActor extends Actor { self.dispatcher = Dispatchers.newExecutorBasedEventDrivenDispatche(name) dispatcher .withNewThreadPoolWithBoundedBlockingQueue(100) .setCorePoolSize(16) .setMaxPoolSize(128) .setKeepAliveTimeInMillis(60000) .setRejectionPolicy(new CallerRunsPolicy) .buildThreadPool}
Here Comes the Code Demo Time!
Versions
Scala 2.8.0.RC6Lift 2.0-scala2.8.0-SNAPSHOTAkka 2.8.0.RC3 0.9.1sbt 0.7.4ensime master on github.com
AlternativesBefore Drinking the Kool-Aid or Flogging Your Fav Tool
scalaz FunctionalJavaGParallelizerKilimActorFoundryActors GuildJetlangActoromFan Actors
Other Actor Impls More Options JVM
Fork/JoinESBNettyHawtDispatch
ErlangRabbitMQHadoopOpenMPMPI
Questions About Akka?
http://akkasource.orghttp://groups.google.com/group/akka-userCourse at Skills Matter Oct 13-14 LSUG talk on Oct 13Ask me:
@matyjas matyjas@gmail.com