Building Reactive Applications with Akka (in Scala)
Upcoming SlideShare
Loading in...5
×
 

Building Reactive Applications with Akka (in Scala)

on

  • 6,225 views

Abstract: ...

Abstract:
The demands and expectations for applications have changed dramatically in recent years. Applications today are deployed on a wide range of infrastructure; from mobile devices up to thousands of nodes running in the cloud—all powered by multi-core processors. They need to be rich and collaborative, have a real-time feel with millisecond response time and should never stop running. Additionally, modern applications are a mashup of external services that need to be consumed and composed to provide the features at hand. We are seeing a new type of applications emerging to address these new challenges—these are being called Reactive Applications.

In this talk we will introduce you to Akka and discuss how it can help you deliver on the four key traits of Reactive; Event-Driven, Scalable, Resilient and Responsive. We will start with the basics of Akka and work our way towards some of its more advanced modules such as Akka Cluster and Akka Persistence—all driven through code and practical examples.

Statistics

Views

Total Views
6,225
Views on SlideShare
5,941
Embed Views
284

Actions

Likes
37
Downloads
242
Comments
0

9 Embeds 284

https://twitter.com 167
http://pramodh-nanjayya.tumblr.com 53
http://jonasboner.com 42
http://bestaroundtheweb.com 7
http://www.tumblr.com 5
http://assets.txmblr.com 4
https://www.linkedin.com 3
http://tweetedtimes.com 2
http://www.slideee.com 1
More...

Accessibility

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Building Reactive Applications with Akka (in Scala) Building Reactive Applications with Akka (in Scala) Presentation Transcript

  • Building Reactive Applications with Akka Jonas Bonér Typesafe CTO & co-founder @jboner
  • This is an era of profound change.
  • Reactive  Applications Implications are massive, change is unavoidable 3 ! ! ! Users are demanding richer and more personalized experiences. ! Yet, at the same time, expecting blazing fast load time. Users ! ! ! Mobile and HTML5; Data and compute clouds; scaling on demand. ! Modern application technologies are fueling the always-on, real- time user expectation. Applications ! ! ! Businesses are being pushed to react to these changing user expectations… ! ...and embrace 
 modern application requirements. ! ! ! ! ! ! ! Businesses
  • As a matter of necessity, 
 businesses are going Reactive.
  • Reactive  Applications Reactive applications share four traits 5
  • Reactive applications react to 
 changes in the world around them.
  • Event-Driven • Loosely coupled architecture, easier to extend, maintain, evolve • Asynchronous and non-blocking • Concurrent by design, immutable state • Lower latency and higher throughput 7 “Clearly, the goal is to do these operations concurrently and 
 non-blocking, so that entire blocks of seats or sections are not locked. 
 We’re able to find and allocate seats under load in less than 20ms 
 without trying very hard to achieve it.”   Andrew Headrick, Platform Architect, Ticketfly
  • Introducing the Actor Model.
  • 9 The Actor Model
  • 9 A computational model that embodies: The Actor Model
  • 9 A computational model that embodies: ✓ Processing The Actor Model
  • 9 A computational model that embodies: ✓ Processing ✓ Storage The Actor Model
  • 9 A computational model that embodies: ✓ Processing ✓ Storage ✓ Communication The Actor Model
  • 9 A computational model that embodies: ✓ Processing ✓ Storage ✓ Communication Supports 3 axioms—when an Actor receives a message it can: The Actor Model
  • 9 A computational model that embodies: ✓ Processing ✓ Storage ✓ Communication Supports 3 axioms—when an Actor receives a message it can: 1. Create new Actors The Actor Model
  • 9 A computational model that embodies: ✓ Processing ✓ Storage ✓ Communication Supports 3 axioms—when an Actor receives a message it can: 1. Create new Actors 2. Send messages to Actors it knows The Actor Model
  • 9 A computational model that embodies: ✓ Processing ✓ Storage ✓ Communication Supports 3 axioms—when an Actor receives a message it can: 1. Create new Actors 2. Send messages to Actors it knows 3. Designate how it should handle the next message it receives The Actor Model
  • The essence of an actor 0. DEFINE 1. CREATE 2. SEND 3. BECOME 4. SUPERVISE 10
  • 0. DEFINE 11 case class Greeting(who: String) ! class GreetingActor extends Actor with ActorLogging { def receive = { case Greeting(who) => log.info(s"Hello ${who}") } }
  • 0. DEFINE 11 Define the message(s) the Actor should be able to respond to case class Greeting(who: String) ! class GreetingActor extends Actor with ActorLogging { def receive = { case Greeting(who) => log.info(s"Hello ${who}") } }
  • 0. DEFINE 11 Define the message(s) the Actor should be able to respond to case class Greeting(who: String) ! class GreetingActor extends Actor with ActorLogging { def receive = { case Greeting(who) => log.info(s"Hello ${who}") } } Define the Actor class
  • 0. DEFINE 11 Define the message(s) the Actor should be able to respond to case class Greeting(who: String) ! class GreetingActor extends Actor with ActorLogging { def receive = { case Greeting(who) => log.info(s"Hello ${who}") } } Define the Actor class Define the Actor’s behavior
  • case class Greeting(who: String) ! class GreetingActor extends Actor with ActorLogging { def receive = { case Greeting(who) => log.info("Hello " + who) } } ! val system = ActorSystem("MySystem") val greeter = system.actorOf(Props[GreetingActor], name = "greeter") 1. CREATE
  • case class Greeting(who: String) ! class GreetingActor extends Actor with ActorLogging { def receive = { case Greeting(who) => log.info("Hello " + who) } } ! val system = ActorSystem("MySystem") val greeter = system.actorOf(Props[GreetingActor], name = "greeter") 1. CREATE Create an Actor system
  • case class Greeting(who: String) ! class GreetingActor extends Actor with ActorLogging { def receive = { case Greeting(who) => log.info("Hello " + who) } } ! val system = ActorSystem("MySystem") val greeter = system.actorOf(Props[GreetingActor], name = "greeter") 1. CREATE Create an Actor system Actor configuration
  • case class Greeting(who: String) ! class GreetingActor extends Actor with ActorLogging { def receive = { case Greeting(who) => log.info("Hello " + who) } } ! val system = ActorSystem("MySystem") val greeter = system.actorOf(Props[GreetingActor], name = "greeter") Give it a name 1. CREATE Create an Actor system Actor configuration
  • case class Greeting(who: String) ! class GreetingActor extends Actor with ActorLogging { def receive = { case Greeting(who) => log.info("Hello " + who) } } ! val system = ActorSystem("MySystem") val greeter = system.actorOf(Props[GreetingActor], name = "greeter") Give it a name 1. CREATE Create the Actor Create an Actor system Actor configuration
  • case class Greeting(who: String) ! class GreetingActor extends Actor with ActorLogging { def receive = { case Greeting(who) => log.info("Hello " + who) } } ! val system = ActorSystem("MySystem") val greeter = system.actorOf(Props[GreetingActor], name = "greeter") Give it a name 1. CREATE Create the ActorYou get an ActorRef back Create an Actor system Actor configuration
  • Guardian System Actor Actors can form hierarchies
  • Guardian System Actor system.actorOf(Props[Foo], “Foo”) Actors can form hierarchies
  • Foo Guardian System Actor system.actorOf(Props[Foo], “Foo”) Actors can form hierarchies
  • Foo Guardian System Actor context.actorOf(Props[A], “A”) Actors can form hierarchies
  • A Foo Guardian System Actor context.actorOf(Props[A], “A”) Actors can form hierarchies
  • A B BarFoo C B E A D C Guardian System Actor Actors can form hierarchies
  • A B BarFoo C B E A D C Guardian System Actor Name resolution—like a file-system
  • A B BarFoo C B E A D C /Foo Guardian System Actor Name resolution—like a file-system
  • A B BarFoo C B E A D C /Foo /Foo/A Guardian System Actor Name resolution—like a file-system
  • A B BarFoo C B E A D C /Foo /Foo/A /Foo/A/B Guardian System Actor Name resolution—like a file-system
  • A B BarFoo C B E A D C /Foo /Foo/A /Foo/A/B /Foo/A/D Guardian System Actor Name resolution—like a file-system
  • 2. SEND 15 case class Greeting(who: String) ! class GreetingActor extends Actor with ActorLogging { def receive = { case Greeting(who) => log.info(s”Hello ${who}") } } ! val system = ActorSystem("MySystem") val greeter = system.actorOf(Props[GreetingActor], name = "greeter") greeter ! Greeting("Charlie Parker")
  • 2. SEND 15 case class Greeting(who: String) ! class GreetingActor extends Actor with ActorLogging { def receive = { case Greeting(who) => log.info(s”Hello ${who}") } } ! val system = ActorSystem("MySystem") val greeter = system.actorOf(Props[GreetingActor], name = "greeter") greeter ! Greeting("Charlie Parker") Send the message asynchronously
  • Bring it together 16 case class Greeting(who: String) ! class GreetingActor extends Actor with ActorLogging { def receive = { case Greeting(who) => log.info(s”Hello ${who}") } } ! val system = ActorSystem("MySystem") val greeter = system.actorOf(Props[GreetingActor], name = "greeter") greeter ! Greeting("Charlie Parker")
  • DEMO TIMEA simple game of ping pong
  • 3. BECOME 18 class GreetingActor extends Actor with ActorLogging { def receive = happy ! val happy: Receive = { case Greeting(who) => log.info(s”Hello ${who}") case Angry => context become angry } ! val angry: Receive = { case Greeting(_) => log.info("Go away!") case Happy => context become happy } }
  • 3. BECOME 18 class GreetingActor extends Actor with ActorLogging { def receive = happy ! val happy: Receive = { case Greeting(who) => log.info(s”Hello ${who}") case Angry => context become angry } ! val angry: Receive = { case Greeting(_) => log.info("Go away!") case Happy => context become happy } } Redefine the behavior
  • Reactive applications are architected 
 to handle failure at all levels.
  • Resilient • Failure is embraced as a natural state in the app lifecycle • Resilience is a first-class construct • Failure is detected, isolated, and managed • Applications self heal 20 “The Typesafe Reactive Platform helps us maintain a very 
 aggressive development and deployment cycle, all in a fail-forward manner. 
 It’s now the default choice for developing all new services.”   Peter Hausel, VP Engineering, Gawker Media
  • Think Vending Machine
  • Coffee Machine Programmer Think Vending Machine
  • Coffee Machine Programmer Inserts coins Think Vending Machine
  • Coffee Machine Programmer Inserts coins Add more coins Think Vending Machine
  • Coffee Machine Programmer Inserts coins Gets coffee Add more coins Think Vending Machine
  • Coffee Machine Programmer Think Vending Machine
  • Coffee Machine Programmer Inserts coins Think Vending Machine
  • Coffee Machine Programmer Inserts coins Think Vending Machine Out of coffee beans error
  • Coffee Machine Programmer Inserts coins Think Vending Machine Out of coffee beans error Wrong
  • Coffee Machine Programmer Inserts coins Think Vending Machine
  • Coffee Machine Programmer Inserts coins Out of coffee beans error Think Vending Machine
  • Coffee Machine Programmer Service Guy Inserts coins Out of coffee beans error Think Vending Machine
  • Coffee Machine Programmer Service Guy Inserts coins Out of coffee beans error Adds more beans Think Vending Machine
  • Coffee Machine Programmer Service Guy Inserts coins Gets coffee Out of coffee beans error Adds more beans Think Vending Machine
  • The Right Way ServiceClient
  • The Right Way ServiceClient Request
  • The Right Way ServiceClient Request Response
  • The Right Way ServiceClient Request Response Validation Error
  • The Right Way ServiceClient Request Response Validation Error Application Error
  • The Right Way ServiceClient Supervisor Request Response Validation Error Application Error
  • The Right Way ServiceClient Supervisor Request Response Validation Error Application Error Manages Failure
  • • Isolate the failure • Compartmentalize • Manage failure locally • Avoid cascading failures Use Bulkheads
  • • Isolate the failure • Compartmentalize • Manage failure locally • Avoid cascading failures Use Bulkheads
  • Enter Supervision
  • Enter Supervision
  • A B BarFoo C B E A D C Automatic and mandatory supervision Supervisor hierarchies
  • 4. SUPERVISE 28 Every single actor has a default supervisor strategy. Which is usually sufficient. But it can be overridden.
  • 4. SUPERVISE 28 Every single actor has a default supervisor strategy. Which is usually sufficient. But it can be overridden. class Supervisor extends Actor { override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) { case _: ArithmeticException => Resume case _: NullPointerException => Restart case _: Exception => Escalate } ! val worker = context.actorOf(Props[Worker], name = "worker") !
  • 4. SUPERVISE 28 class Supervisor extends Actor { override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) { case _: ArithmeticException => Resume case _: NullPointerException => Restart case _: Exception => Escalate } ! val worker = context.actorOf(Props[Worker], name = "worker") ! def receive = { case n: Int => worker forward n } } !
  • Cleanup & (Re)initialization 29 class Worker extends Actor { ... override def preRestart( reason: Throwable, message: Option[Any]) { ... // clean up before restart } override def postRestart(reason: Throwable) { ... // init after restart } }
  • Monitor through Death Watch 30 class Watcher extends Actor { val child = context.actorOf(Props.empty, "child") context.watch(child) ! def receive = { case Terminated(`child`) => … // handle child termination } }
  • Reactive applications scale up 
 and down to meet demand.
  • Scalable • Scalability and elasticity to embrace the Cloud • Leverage all cores via asynchronous programming • Clustered servers support joining and leaving of nodes • More cost-efficient utilization of hardware 32 “Our traffic can increase by as much as 100x for 15 minutes each day. 
 Until a couple of years ago, noon was a stressful time. 
 Nowadays, it’s usually a non-event.”   Eric Bowman, VP Architecture, Gilt Groupe
  • 33 Scale OUT Scale UP
  • 33 Essentially the same thing
  • 34 1. Minimize Contention 2. Maximize Locality of Reference We need to
  • 35 Share NOTHING Design
  • Fully event-driven apps are a necessity 36 Amdahl’s Law will hunt you down
  • Define a router 37 val router = context.actorOf( RoundRobinPool(5).props(Props[Worker])), “router”) Paths can be local or remote actor paths
  • …or from config 38 akka.actor.deployment { /service/router { router = round-robin-pool resizer { lower-bound = 12 upper-bound = 15 } } }
  • Turn on clustering 39 akka { actor { provider = "akka.cluster.ClusterActorRefProvider" ... }    cluster { seed-nodes = [ “akka.tcp://ClusterSystem@127.0.0.1:2551", “akka.tcp://ClusterSystem@127.0.0.1:2552" ]   auto-down = off } }
  • Use clustered routers 40 akka.actor.deployment  {      /service/master  {          router  =  consistent-­‐hashing-­‐pool          nr-­‐of-­‐instances  =  100   !        cluster  {              enabled  =  on              max-nr-of-instances-per-node = 3              allow-­‐local-­‐routees  =  on              use-­‐role  =  compute          }      }   }
  • Use clustered routers 40 akka.actor.deployment  {      /service/master  {          router  =  consistent-­‐hashing-­‐pool          nr-­‐of-­‐instances  =  100   !        cluster  {              enabled  =  on              max-nr-of-instances-per-node = 3              allow-­‐local-­‐routees  =  on              use-­‐role  =  compute          }      }   } Or perhaps use an AdaptiveLoadBalancingPool
  • Use clustered pub-sub 41
  • Use clustered pub-sub 41 class Subscriber extends Actor { val mediator = DistributedPubSubExtension(context.system).mediator mediator ! Subscribe(“content”, self) def receive = { … } }
  • Use clustered pub-sub 41 class Publisher extends Actor { val mediator = DistributedPubSubExtension(context.system).mediator def receive = { case in: String => mediator ! Publish("content", in.toUpperCase) } }
  • • Cluster Membership • Cluster Leader • Clustered Singleton • Cluster Roles • Cluster Sharding 42 Other Akka Cluster features
  • • Supports two different models: • Command Sourcing — at least once • Event Sourcing — at most once • Great for implementing • durable actors • replication • CQRS etc. • Messages persisted to Journal and replayed on restart 43 Use Akka Persistence
  • Akka  Persistence  Webinar Command Sourcing Event Sourcing write-ahead-log derive events from a command same behavior during recovery as normal operation external interaction can be problematic only state-changing behavior during recovery persisted before validation events cannot fail allows retroactive changes to the business logic fixing the business logic will not affect persisted events naming: represent intent, imperative naming: things that have completed, verbs in past tense
  • Akka  Persistence  Webinar Life beyond Distributed Transactions: an Apostate’s Opinion Position Paper by Pat Helland “In general, application developers simply do not implement large scalable applications assuming distributed transactions.”   Pat Helland http://www-­‐db.cs.wisc.edu/cidr/cidr2007/papers/cidr07p15.pdf
  • Akka  Persistence  Webinar Consistency boundary • Aggregate Root is the Transactional Boundary • Strong consistency within an Aggregate • Eventual consistency between Aggregates • No limit to scalability
  • Akka  Persistence  Webinar Domain Events • Things that have completed, facts • Immutable • Verbs in past tense • CustomerRelocated • CargoShipped • InvoiceSent “State transitions are an important part of our problem space and should be modeled within our domain.”   Greg Young, 2008
  • DEMO TIMEPersist a game of ping pong
  • Reactive applications enrich the user experience with low latency response.
  • Responsive • Real-time, engaging, rich and collaborative • Create an open and ongoing dialog with users • More efficient workflow; inspires a feeling of connectedness • Fully Reactive enabling push instead of pull 50 “The move to these technologies is already paying off. 
 Response times are down for processor intensive code–such as image 
 and PDF generation–by around 75%.”   Brian Pugh, VP of Engineering, Lucid Software
  • Responsive 51 • Keep latency consistent—under: 1. Blue sky scenarios 2. Traffic spikes 3. Failures • The system should always be responsive
  • http://reactivemanifesto.org
  • Typesafe Activator http://typesafe.com/platform/getstarted
  • 54 Typesafe Reactive Platform
  • 54 Typesafe Reactive Platform • Asynchronous and immutable programming constructs • Composable abstractions enabling simpler concurrency and parallelism
  • 54 Typesafe Reactive Platform • Actors are asynchronous and communicate via message passing • Supervision and clustering in support of fault tolerance • Asynchronous and immutable programming constructs • Composable abstractions enabling simpler concurrency and parallelism
  • 54 Typesafe Reactive Platform • Actors are asynchronous and communicate via message passing • Supervision and clustering in support of fault tolerance • Purely asynchronous and non-blocking web frameworks • No container required, no inherent bottlenecks in session management • Asynchronous and immutable programming constructs • Composable abstractions enabling simpler concurrency and parallelism
  • Reactive is being adopted across
 a wide range of industries.
  • 56 Finance Internet/Social Media Mfg/Hardware Government Retail
  • Questions?
  • ©Typesafe 2014 – All Rights Reserved