Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Why Being Reactive is Good

Why Being Reactive is Good

One of the more difficult aspects of systems architecture is finding concrete terms to describe desirable characteristics that everyone understands. Reactive was one of those terms until two years ago, when the Reactive Manifesto was released. Today, over 12,000 people have signed the online document and participated in its evolution. But what does it mean, and how do the principles described by it help developers engineer systems that are elastic, resilient and responsive to users in the face of bursty load and random/unknown failures? We will discuss these topics, as well as clearly discuss the concepts of asynchronous tasks, non-blocking threads, concurrency issues and parallelism.

The goal of this talk is to frame the term reactive in a positive light, because when it comes to building real-time systems, being reactive is good.

Kevin Webber

October 22, 2015
Tweet

More Decks by Kevin Webber

Other Decks in Programming

Transcript

  1. Being Reactive is Good
    Kevin Webber, Developer Advocate, Typesafe

    View full-size slide

  2. Problem?
    » we used the right tools to build the wrong thing

    View full-size slide

  3. Problem?
    » we used the right tools to build the wrong thing
    » proactive isn't always good

    View full-size slide

  4. Problem?
    » we used the right tools to build the wrong thing
    » proactive isn't always good
    » reactive isn't always bad

    View full-size slide

  5. » let principles guide our
    » design
    » tool selection
    » implementation choices

    View full-size slide

  6. » let principles guide our
    » design
    » tool selection
    » implementation choices
    » principles should be accessible and universal

    View full-size slide

  7. » let principles guide our
    » design
    » tool selection
    » implementation choices
    » principles should be accessible and universal
    » principles should help engineers
    » meet expectations
    » take advantage of the latest advancements in
    technology

    View full-size slide

  8. What is Reactive?

    View full-size slide

  9. asynchronous, non-blocking, real-time, highly-
    available, loosely coupled, scalable, fault-tolerant,
    concurrent, reactive, event-driven, push instead of
    pull, distributed, low latency, high throughput...

    View full-size slide

  10. asynchronous, non-blocking, real-time, highly-
    available, loosely coupled, scalable, fault-tolerant,
    concurrent, reactive, event-driven, push instead of
    pull, distributed, low latency, high throughput...
    Too complicated. We need a simple vocabulary.

    View full-size slide

  11. Typesafe
    Reactive
    Platform
    » Play: RESTful API framework
    » Akka: Distributed computing
    framework
    » Spark: General purpose in-
    memory compute engine

    View full-size slide

  12. Message-driven
    » distribution
    » location transparency
    » isolation

    View full-size slide

  13. object GameEngineActor {
    def props = Props(new GameEngineActor)
    }
    }

    View full-size slide

  14. object GameEngineActor {
    def props = Props(new GameEngineActor)
    }
    class GameEngineActor extends Actor {
    val log = Logging(context.system, this)
    var openGameQ = new Queue[ActorRef]
    }

    View full-size slide

  15. object GameEngineActor {
    def props = Props(new GameEngineActor)
    }
    class GameEngineActor extends Actor {
    val log = Logging(context.system, this)
    var openGameQ = new Queue[ActorRef]
    def receive = {
    // find open game and register player for the game
    case r: RegisterPlayerRequest => findGame(r) ! r
    case _ => log.error(_)
    }
    }

    View full-size slide

  16. object GameEngineActor {
    def props = Props(new GameEngineActor)
    }
    class GameEngineActor extends Actor {
    val log = Logging(context.system, this)
    var openGameQ = new Queue[ActorRef]
    def receive = {
    // find open game and register player for the game
    case r: RegisterPlayerRequest => findGame(r) ! r
    case _ => log.error(_)
    }
    private def findGame(r: RegisterPlayerRequest): ActorRef = {
    if (openGameQ.isEmpty) {
    // create a new game and add it to the queue
    val newGame = {
    val gameUuid = java.util.UUID.randomUUID.toString
    context.actorOf(Props[GameActor], name = "gameActor" + gameUuid)
    }
    openGameQ += newGame
    newGame
    } else {
    // pull a game off the queue that is waiting for players
    openGameQ.dequeue
    }
    }
    }

    View full-size slide

  17. Resilient
    » supervision

    View full-size slide

  18. Resilient
    » emitting errors

    View full-size slide

  19. Resilient
    » handling errors

    View full-size slide

  20. Resilient
    » dedicated separate error
    channel

    View full-size slide

  21. Elastic
    » scale up
    » async
    » non-blocking

    View full-size slide

  22. Elastic
    » scale up
    » async
    » non-blocking
    » scale out
    » immutable data
    » share nothing

    View full-size slide

  23. Responsive
    » responsive to events
    » responsive to load
    » responsive to failure
    » responsive to users

    View full-size slide

  24. » responsive
    a request for service is always answered, even
    when failures occur.
    » elastic
    services scale up and down on demand.
    » resilient
    services recover from failures.
    » message driven
    services respond to the world, not attempt to
    control what it does.

    View full-size slide

  25. How can we envision Proactive Security Solutions as
    Reactive Security Solutions?
    Using:
    » Reactive principles
    » The Typesafe Reactive Platform

    View full-size slide

  26. How do we get there?
    Applying the Reactive principles to build a fully
    reactive microservices system, using:
    » The Typesafe Reactive Platform
    » Third-party tools
    » Existing infrastructure (hybrid-cloud, etc)

    View full-size slide

  27. Async in Action with the
    Play framework

    View full-size slide

  28. Play Anatomy
    » Stateless: session is stored in the browser cookie
    » Actions: user-defined functions that run in a
    different context than the request loop

    View full-size slide

  29. Play at its core
    » RESTful API framework

    View full-size slide

  30. Play at its core
    » RESTful API framework
    » Familiar MVC paradigm

    View full-size slide

  31. Play at its core
    » RESTful API framework
    » Familiar MVC paradigm
    » Embraces flows of data
    » WebSockets, SSE
    » File uploads

    View full-size slide

  32. Play at its core
    » RESTful API framework
    » Familiar MVC paradigm
    » Embraces flows of data
    » WebSockets, SSE
    » File uploads
    » Integration with Akka
    » Distribute work via messaging

    View full-size slide

  33. Single thread per request

    View full-size slide

  34. Single thread per request
    » A thread keeps data in memory until it has access
    to the CPU

    View full-size slide

  35. Single thread per request
    » A thread keeps data in memory until it has access
    to the CPU
    » More threads = more memory required

    View full-size slide

  36. Single thread per request
    » A thread keeps data in memory until it has access
    to the CPU
    » More threads = more memory required
    » If a thread is idle while blocked (e.g, IO)
    » Memory is being consumed inefficiently
    » Must limit total number of threads
    » This can leave the CPU idle (bounded on memory)

    View full-size slide

  37. Work stealing

    View full-size slide

  38. » Play uses a fork join execution context with work
    stealing
    » Does not bind a thread to a request

    View full-size slide

  39. » Play uses a fork join execution context with work
    stealing
    » Does not bind a thread to a request
    » Uses Futures and Thread Pools to let CPU go at
    full throttle

    View full-size slide

  40. » Play uses a fork join execution context with work
    stealing
    » Does not bind a thread to a request
    » Uses Futures and Thread Pools to let CPU go at
    full throttle
    » Uses NIO.2 through Netty to avoid blocking on
    network IO

    View full-size slide

  41. » Play uses a fork join execution context with work
    stealing
    » Does not bind a thread to a request
    » Uses Futures and Thread Pools to let CPU go at
    full throttle
    » Uses NIO.2 through Netty to avoid blocking on
    network IO
    » Stateless (no HTTP session)

    View full-size slide

  42. » Play uses a fork join execution context with work
    stealing
    » Does not bind a thread to a request
    » Uses Futures and Thread Pools to let CPU go at
    full throttle
    » Uses NIO.2 through Netty to avoid blocking on
    network IO
    » Stateless (no HTTP session)
    » No ThreadLocal anywhere

    View full-size slide

  43. Future[Result]
    def index = Action.async {
    implicit request =>
    Ok(...)
    }

    View full-size slide

  44. Future[Result]
    » The async block indicates that the controller will
    return a Future[Result]

    View full-size slide

  45. Future[Result]
    » The async block indicates that the controller will
    return a Future[Result]
    » The Future provides a way to do asynchronous
    handling but doesn't necessarily have to be non-
    blocking

    View full-size slide

  46. Future[Result]
    » The async block indicates that the controller will
    return a Future[Result]
    » The Future provides a way to do asynchronous
    handling but doesn't necessarily have to be non-
    blocking
    » If a thread can't be deallocated while waiting for
    those other systems to respond, then it is
    blocking

    View full-size slide

  47. Future[Result]
    » The async block indicates that the controller will
    return a Future[Result]
    » The Future provides a way to do asynchronous
    handling but doesn't necessarily have to be non-
    blocking
    » If a thread can't be deallocated while waiting for
    those other systems to respond, then it is
    blocking
    » Order of execution doesn't matter

    View full-size slide

  48. Implications
    » ACID doesn't work across location/trust boundaries
    » No 2-Phase commits (2PC)
    » No holding locks for the duration of the work

    View full-size slide

  49. Implications
    » Must embrace eventual consistency
    » Multiple workflows across multiple systems
    » Each provides a path of compensating actions

    View full-size slide

  50. Saga pattern
    » a Saga splits work into individual transactions
    » effects can be reversed after work has been
    performed and commited

    View full-size slide

  51. ConductR and
    Monitoring

    View full-size slide

  52. How do I get started?
    https://www.typesafe.com/activator/download

    View full-size slide

  53. Thank you!
    Kevin Webber
    Medium: medium.com/@kvnwbbr
    Twitter: @kvnwbbr
    Point of contact
    [email protected]

    View full-size slide