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

Building Reactive Systems with Akka

Building Reactive Systems with Akka

Jonas Bonér

April 03, 2014
Tweet

More Decks by Jonas Bonér

Other Decks in Programming

Transcript

  1. Building
    Reactive Systems
    with Akka
    Jonas Bonér
    Typesafe
    CTO & co-founder
    Twitter: @jboner

    View Slide

  2. The rules of the game
    have changed

    View Slide

  3. 3
    Apps in the 60s-90s
    were written for
    Apps today
    are written for

    View Slide

  4. 3
    Apps in the 60s-90s
    were written for
    Apps today
    are written for
    Single machines

    View Slide

  5. 3
    Apps in the 60s-90s
    were written for
    Apps today
    are written for
    Single machines Clusters of machines

    View Slide

  6. 3
    Apps in the 60s-90s
    were written for
    Apps today
    are written for
    Single machines Clusters of machines
    Single core processors

    View Slide

  7. 3
    Apps in the 60s-90s
    were written for
    Apps today
    are written for
    Single machines Clusters of machines
    Single core processors Multicore processors

    View Slide

  8. 3
    Apps in the 60s-90s
    were written for
    Apps today
    are written for
    Single machines Clusters of machines
    Single core processors Multicore processors
    Expensive RAM

    View Slide

  9. 3
    Apps in the 60s-90s
    were written for
    Apps today
    are written for
    Single machines Clusters of machines
    Single core processors Multicore processors
    Expensive RAM Cheap RAM

    View Slide

  10. 3
    Apps in the 60s-90s
    were written for
    Apps today
    are written for
    Single machines Clusters of machines
    Single core processors Multicore processors
    Expensive RAM Cheap RAM
    Expensive disk

    View Slide

  11. 3
    Apps in the 60s-90s
    were written for
    Apps today
    are written for
    Single machines Clusters of machines
    Single core processors Multicore processors
    Expensive RAM Cheap RAM
    Expensive disk Cheap disk

    View Slide

  12. 3
    Apps in the 60s-90s
    were written for
    Apps today
    are written for
    Single machines Clusters of machines
    Single core processors Multicore processors
    Expensive RAM Cheap RAM
    Expensive disk Cheap disk
    Slow networks

    View Slide

  13. 3
    Apps in the 60s-90s
    were written for
    Apps today
    are written for
    Single machines Clusters of machines
    Single core processors Multicore processors
    Expensive RAM Cheap RAM
    Expensive disk Cheap disk
    Slow networks Fast networks

    View Slide

  14. 3
    Apps in the 60s-90s
    were written for
    Apps today
    are written for
    Single machines Clusters of machines
    Single core processors Multicore processors
    Expensive RAM Cheap RAM
    Expensive disk Cheap disk
    Slow networks Fast networks
    Few concurrent users

    View Slide

  15. 3
    Apps in the 60s-90s
    were written for
    Apps today
    are written for
    Single machines Clusters of machines
    Single core processors Multicore processors
    Expensive RAM Cheap RAM
    Expensive disk Cheap disk
    Slow networks Fast networks
    Few concurrent users Lots of concurrent users

    View Slide

  16. 3
    Apps in the 60s-90s
    were written for
    Apps today
    are written for
    Single machines Clusters of machines
    Single core processors Multicore processors
    Expensive RAM Cheap RAM
    Expensive disk Cheap disk
    Slow networks Fast networks
    Few concurrent users Lots of concurrent users
    Small data sets

    View Slide

  17. 3
    Apps in the 60s-90s
    were written for
    Apps today
    are written for
    Single machines Clusters of machines
    Single core processors Multicore processors
    Expensive RAM Cheap RAM
    Expensive disk Cheap disk
    Slow networks Fast networks
    Few concurrent users Lots of concurrent users
    Small data sets Large data sets

    View Slide

  18. 3
    Apps in the 60s-90s
    were written for
    Apps today
    are written for
    Single machines Clusters of machines
    Single core processors Multicore processors
    Expensive RAM Cheap RAM
    Expensive disk Cheap disk
    Slow networks Fast networks
    Few concurrent users Lots of concurrent users
    Small data sets Large data sets
    Latency in seconds

    View Slide

  19. 3
    Apps in the 60s-90s
    were written for
    Apps today
    are written for
    Single machines Clusters of machines
    Single core processors Multicore processors
    Expensive RAM Cheap RAM
    Expensive disk Cheap disk
    Slow networks Fast networks
    Few concurrent users Lots of concurrent users
    Small data sets Large data sets
    Latency in seconds Latency in milliseconds

    View Slide

  20. View Slide

  21. Cost Gravity is at Work
    X

    View Slide

  22. Cost Gravity is at Work
    X

    View Slide

  23. Reactive  Applications
    Reactive applications share four traits
    5

    View Slide

  24. Reactive applications enrich the user
    experience with low latency response.

    View Slide

  25. 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
    7
    “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

    View Slide

  26. Reactive applications react to 

    changes in the world around them.

    View Slide

  27. Message-Driven
    • Loosely coupled architecture, easier to extend, maintain, evolve
    • Asynchronous and non-blocking
    • Concurrent by design, immutable state
    • Lower latency and higher throughput
    9
    “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

    View Slide

  28. Introducing the Actor Model

    View Slide

  29. 11
    The Actor Model

    View Slide

  30. 11
    A computational model that embodies:
    The Actor Model

    View Slide

  31. 11
    A computational model that embodies:
    ✓ Processing
    The Actor Model

    View Slide

  32. 11
    A computational model that embodies:
    ✓ Processing
    ✓ Storage
    The Actor Model

    View Slide

  33. 11
    A computational model that embodies:
    ✓ Processing
    ✓ Storage
    ✓ Communication
    The Actor Model

    View Slide

  34. 11
    A computational model that embodies:
    ✓ Processing
    ✓ Storage
    ✓ Communication
    Supports 3 axioms—when an Actor receives a message it can:
    The Actor Model

    View Slide

  35. 11
    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

    View Slide

  36. 11
    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

    View Slide

  37. 11
    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

    View Slide

  38. The essence of an actor
    from Akka’s perspective
    0. DEFINE
    1. CREATE
    2. SEND
    3. BECOME
    4. SUPERVISE
    12

    View Slide

  39. public class Greeting implements Serializable {
    public final String who;
    public Greeting(String who) { this.who = who; }
    }
    !
    public class Greeter extends AbstractActor {{
    receive(ReceiveBuilder.
    match(Greeting.class, m -> {
    println(“Hello " + m.who);
    }).
    matchAny(unknown -> {
    println(“Unknown message " + unknown);
    }).build());
    }}
    0. DEFINE
    X

    View Slide

  40. public class Greeting implements Serializable {
    public final String who;
    public Greeting(String who) { this.who = who; }
    }
    !
    public class Greeter extends AbstractActor {{
    receive(ReceiveBuilder.
    match(Greeting.class, m -> {
    println(“Hello " + m.who);
    }).
    matchAny(unknown -> {
    println(“Unknown message " + unknown);
    }).build());
    }}
    0. DEFINE
    X
    Define the message(s) the Actor
    should be able to respond to

    View Slide

  41. public class Greeting implements Serializable {
    public final String who;
    public Greeting(String who) { this.who = who; }
    }
    !
    public class Greeter extends AbstractActor {{
    receive(ReceiveBuilder.
    match(Greeting.class, m -> {
    println(“Hello " + m.who);
    }).
    matchAny(unknown -> {
    println(“Unknown message " + unknown);
    }).build());
    }}
    0. DEFINE
    X
    Define the message(s) the Actor
    should be able to respond to
    Define the Actor class

    View Slide

  42. public class Greeting implements Serializable {
    public final String who;
    public Greeting(String who) { this.who = who; }
    }
    !
    public class Greeter extends AbstractActor {{
    receive(ReceiveBuilder.
    match(Greeting.class, m -> {
    println(“Hello " + m.who);
    }).
    matchAny(unknown -> {
    println(“Unknown message " + unknown);
    }).build());
    }}
    0. DEFINE
    X
    Define the message(s) the Actor
    should be able to respond to
    Define the Actor class
    Define the Actor’s behavior

    View Slide

  43. ActorSystem system = ActorSystem.create("MySystem");
    !
    ActorRef greeter =
    system.actorOf(Props.create(Greeter.class), “greeter");
    1. CREATE

    View Slide

  44. ActorSystem system = ActorSystem.create("MySystem");
    !
    ActorRef greeter =
    system.actorOf(Props.create(Greeter.class), “greeter");
    1. CREATE
    Create an Actor system

    View Slide

  45. ActorSystem system = ActorSystem.create("MySystem");
    !
    ActorRef greeter =
    system.actorOf(Props.create(Greeter.class), “greeter");
    1. CREATE
    Create an Actor system
    Actor configuration

    View Slide

  46. ActorSystem system = ActorSystem.create("MySystem");
    !
    ActorRef greeter =
    system.actorOf(Props.create(Greeter.class), “greeter");
    Give it a name
    1. CREATE
    Create an Actor system
    Actor configuration

    View Slide

  47. ActorSystem system = ActorSystem.create("MySystem");
    !
    ActorRef greeter =
    system.actorOf(Props.create(Greeter.class), “greeter");
    Give it a name
    1. CREATE
    Create the Actor
    Create an Actor system
    Actor configuration

    View Slide

  48. ActorSystem system = ActorSystem.create("MySystem");
    !
    ActorRef greeter =
    system.actorOf(Props.create(Greeter.class), “greeter");
    Give it a name
    1. CREATE
    Create the Actor
    You get an ActorRef back
    Create an Actor system
    Actor configuration

    View Slide

  49. 0. DEFINE
    13
    case class Greeting(who: String)
    !
    class GreetingActor extends Actor with ActorLogging {
    def receive = {
    case Greeting(who) => log.info(s"Hello ${who}")
    }
    }

    View Slide

  50. 0. DEFINE
    13
    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}")
    }
    }

    View Slide

  51. 0. DEFINE
    13
    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

    View Slide

  52. 0. DEFINE
    13
    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

    View Slide

  53. 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

    View Slide

  54. 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

    View Slide

  55. 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

    View Slide

  56. 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

    View Slide

  57. 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

    View Slide

  58. 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
    You get an ActorRef back
    Create an Actor system
    Actor configuration

    View Slide

  59. Guardian System Actor
    Actors can form hierarchies

    View Slide

  60. Guardian System Actor
    system.actorOf(Props.create(Foo.class), “Foo”);
    Actors can form hierarchies

    View Slide

  61. Foo
    Guardian System Actor
    system.actorOf(Props.create(Foo.class), “Foo”);
    Actors can form hierarchies

    View Slide

  62. Foo
    Guardian System Actor
    context().actorOf(Props.create(A.class), “A”);
    Actors can form hierarchies

    View Slide

  63. A
    Foo
    Guardian System Actor
    context().actorOf(Props.create(A.class), “A”);
    Actors can form hierarchies

    View Slide

  64. A
    B
    Bar
    Foo
    C
    B
    E
    A
    D
    C
    Guardian System Actor
    Actors can form hierarchies

    View Slide

  65. Guardian System Actor
    Actors can form hierarchies

    View Slide

  66. Guardian System Actor
    system.actorOf(Props[Foo], “Foo”)
    Actors can form hierarchies

    View Slide

  67. Foo
    Guardian System Actor
    system.actorOf(Props[Foo], “Foo”)
    Actors can form hierarchies

    View Slide

  68. Foo
    Guardian System Actor
    context.actorOf(Props[A], “A”)
    Actors can form hierarchies

    View Slide

  69. A
    Foo
    Guardian System Actor
    context.actorOf(Props[A], “A”)
    Actors can form hierarchies

    View Slide

  70. A
    B
    Bar
    Foo
    C
    B
    E
    A
    D
    C
    Guardian System Actor
    Actors can form hierarchies

    View Slide

  71. A
    B
    Bar
    Foo
    C
    B
    E
    A
    D
    C
    Guardian System Actor
    Name resolution—like a file-system

    View Slide

  72. A
    B
    Bar
    Foo
    C
    B
    E
    A
    D
    C
    /Foo
    Guardian System Actor
    Name resolution—like a file-system

    View Slide

  73. A
    B
    Bar
    Foo
    C
    B
    E
    A
    D
    C
    /Foo
    /Foo/A
    Guardian System Actor
    Name resolution—like a file-system

    View Slide

  74. A
    B
    Bar
    Foo
    C
    B
    E
    A
    D
    C
    /Foo
    /Foo/A
    /Foo/A/B
    Guardian System Actor
    Name resolution—like a file-system

    View Slide

  75. A
    B
    Bar
    Foo
    C
    B
    E
    A
    D
    C
    /Foo
    /Foo/A
    /Foo/A/B
    /Foo/A/D
    Guardian System Actor
    Name resolution—like a file-system

    View Slide

  76. 2. SEND
    X
    greeter.tell(new Greeting("Charlie Parker”), sender);

    View Slide

  77. 2. SEND
    X
    Send the message asynchronously
    greeter.tell(new Greeting("Charlie Parker”), sender);

    View Slide

  78. 2. SEND
    X
    Send the message asynchronously
    greeter.tell(new Greeting("Charlie Parker”), sender);
    Pass in the sender ActorRef

    View Slide

  79. Bring it together
    X
    public class Greeting implements Serializable {
    public final String who;
    public Greeting(String who) { this.who = who; }
    }
    public class Greeter extends AbstractActor {{
    receive(ReceiveBuilder.
    match(Greeting.class, m -> {
    println(“Hello " + m.who);
    }).
    matchAny(unknown -> {
    println(“Unknown message " + unknown);
    }).build());
    }
    }}
    !
    ActorSystem system = ActorSystem.create("MySystem");
    ActorRef greeter = system.actorOf(Props.create(Greeter.class), “greeter");
    greeter.tell(new Greeting(“Charlie Parker”));

    View Slide

  80. 2. SEND
    17
    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")

    View Slide

  81. 2. SEND
    17
    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

    View Slide

  82. Bring it together
    18
    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")

    View Slide

  83. DEMO TIME
    A simple game of ping pong

    View Slide

  84. 3. BECOME
    X
    public class Greeter extends AbstractActor {
    public Greeter {
    receive(ReceiveBuilder.
    match(Greeting.class, m -> {
    println(“Hello " + m.who);
    }).
    matchEquals(“stop" -> {
    !
    !
    !
    !
    }).build();
    }
    }

    View Slide

  85. 3. BECOME
    X
    public class Greeter extends AbstractActor {
    public Greeter {
    receive(ReceiveBuilder.
    match(Greeting.class, m -> {
    println(“Hello " + m.who);
    }).
    matchEquals(“stop" -> {
    !
    !
    !
    !
    }).build();
    }
    }
    context().become(ReceiveBuilder.

    View Slide

  86. 3. BECOME
    X
    public class Greeter extends AbstractActor {
    public Greeter {
    receive(ReceiveBuilder.
    match(Greeting.class, m -> {
    println(“Hello " + m.who);
    }).
    matchEquals(“stop" -> {
    !
    !
    !
    !
    }).build();
    }
    }
    Change the behavior
    context().become(ReceiveBuilder.

    View Slide

  87. 3. BECOME
    X
    public class Greeter extends AbstractActor {
    public Greeter {
    receive(ReceiveBuilder.
    match(Greeting.class, m -> {
    println(“Hello " + m.who);
    }).
    matchEquals(“stop" -> {
    !
    !
    !
    !
    }).build();
    }
    }
    Change the behavior
    context().become(ReceiveBuilder.
    match(Greeting.class, m -> {

    View Slide

  88. 3. BECOME
    X
    public class Greeter extends AbstractActor {
    public Greeter {
    receive(ReceiveBuilder.
    match(Greeting.class, m -> {
    println(“Hello " + m.who);
    }).
    matchEquals(“stop" -> {
    !
    !
    !
    !
    }).build();
    }
    }
    Change the behavior
    context().become(ReceiveBuilder.
    match(Greeting.class, m -> {
    println(“Go Away!”);

    View Slide

  89. 3. BECOME
    X
    public class Greeter extends AbstractActor {
    public Greeter {
    receive(ReceiveBuilder.
    match(Greeting.class, m -> {
    println(“Hello " + m.who);
    }).
    matchEquals(“stop" -> {
    !
    !
    !
    !
    }).build();
    }
    }
    Change the behavior
    context().become(ReceiveBuilder.
    match(Greeting.class, m -> {
    println(“Go Away!”);
    }).build());

    View Slide

  90. 3. BECOME
    X
    public class Greeter extends AbstractActor {
    public Greeter {
    receive(ReceiveBuilder.
    match(Greeting.class, m -> {
    println(“Hello " + m.who);
    }).
    matchEquals(“stop" -> {
    !
    !
    !
    !
    }).build();
    }
    }
    Change the behavior
    context().become(ReceiveBuilder.
    match(Greeting.class, m -> {
    println(“Go Away!”);
    }).build());

    View Slide

  91. 3. BECOME
    19
    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
    }
    }

    View Slide

  92. 3. BECOME
    19
    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

    View Slide

  93. Reactive applications are architected 

    to handle failure at all levels.

    View Slide

  94. 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
    21
    “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

    View Slide

  95. Think Vending Machine

    View Slide

  96. Coffee
    Machine
    Programmer
    Think Vending Machine

    View Slide

  97. Coffee
    Machine
    Programmer
    Inserts coins
    Think Vending Machine

    View Slide

  98. Coffee
    Machine
    Programmer
    Inserts coins
    Add more coins
    Think Vending Machine

    View Slide

  99. Coffee
    Machine
    Programmer
    Inserts coins
    Gets coffee
    Add more coins
    Think Vending Machine

    View Slide

  100. Coffee
    Machine
    Programmer
    Think Vending Machine

    View Slide

  101. Coffee
    Machine
    Programmer
    Inserts coins
    Think Vending Machine

    View Slide

  102. Coffee
    Machine
    Programmer
    Inserts coins
    Think Vending Machine
    Out of coffee beans error

    View Slide

  103. Coffee
    Machine
    Programmer
    Inserts coins
    Think Vending Machine
    Out of coffee beans error
    Wrong

    View Slide

  104. Coffee
    Machine
    Programmer
    Inserts coins
    Think Vending Machine

    View Slide

  105. Coffee
    Machine
    Programmer
    Inserts coins
    Out of
    coffee beans
    error
    Think Vending Machine

    View Slide

  106. Coffee
    Machine
    Programmer
    Service
    Guy
    Inserts coins
    Out of
    coffee beans
    error
    Think Vending Machine

    View Slide

  107. Coffee
    Machine
    Programmer
    Service
    Guy
    Inserts coins
    Out of
    coffee beans
    error
    Adds
    more
    beans
    Think Vending Machine

    View Slide

  108. Coffee
    Machine
    Programmer
    Service
    Guy
    Inserts coins
    Gets coffee
    Out of
    coffee beans
    error
    Adds
    more
    beans
    Think Vending Machine

    View Slide

  109. The Right Way
    Service
    Client

    View Slide

  110. The Right Way
    Service
    Client
    Request

    View Slide

  111. The Right Way
    Service
    Client
    Request
    Response

    View Slide

  112. The Right Way
    Service
    Client
    Request
    Response
    Validation Error

    View Slide

  113. The Right Way
    Service
    Client
    Request
    Response
    Validation Error
    Application
    Error

    View Slide

  114. The Right Way
    Service
    Client
    Supervisor
    Request
    Response
    Validation Error
    Application
    Error

    View Slide

  115. The Right Way
    Service
    Client
    Supervisor
    Request
    Response
    Validation Error
    Application
    Error
    Manages
    Failure

    View Slide

  116. View Slide

  117. • Isolate the failure
    • Compartmentalize
    • Manage failure locally
    • Avoid cascading failures
    Use Bulkheads

    View Slide

  118. • Isolate the failure
    • Compartmentalize
    • Manage failure locally
    • Avoid cascading failures
    Use Bulkheads

    View Slide

  119. Enter Supervision

    View Slide

  120. Enter Supervision

    View Slide

  121. A
    B
    Bar
    Foo
    C
    B
    E
    A
    D
    C
    Automatic and mandatory supervision
    Supervisor hierarchies

    View Slide

  122. 4. SUPERVISE
    X
    class Supervisor extends UntypedActor {
    private SupervisorStrategy strategy = new OneForOneStrategy(
    10, Duration.create(1, TimeUnit.MINUTES),
    DeciderBuilder.
    match(ArithmeticException.class, e -> resume()).
    match(NullPointerException.class, e -> restart()).
    matchAny( e -> escalate()).
    build());
    !
    @Override public SupervisorStrategy supervisorStrategy() {
    return strategy;
    }
    Every single actor has a default supervisor strategy.
    Which is usually sufficient.
    But it can be overridden.

    View Slide

  123. 4. SUPERVISE
    X
    class Supervisor extends UntypedActor {
    private SupervisorStrategy strategy = new OneForOneStrategy(
    10, Duration.create(1, TimeUnit.MINUTES),
    DeciderBuilder.
    match(ArithmeticException.class, e -> resume()).
    match(NullPointerException.class, e -> restart()).
    matchAny( e -> escalate()).
    build());
    !
    @Override public SupervisorStrategy supervisorStrategy() {
    return strategy;
    }
    ActorRef worker = context.actorOf(
    Props.create(Worker.class), "worker");
    public void onReceive(Object i) throws Exception {

    }
    }

    View Slide

  124. Monitor through Death Watch
    X
    public class WatchActor extends AbstractActor {
    final ActorRef child = context().actorOf(Props.empty(), "child");
    !
    public WatchActor() {
    context().watch(child);
    receive(ReceiveBuilder.
    match(Terminated.class,
    t -> t.actor().equals(child),
    t -> {
    … // handle termination
    }).build()
    );
    }
    }

    View Slide

  125. Monitor through Death Watch
    X
    public class WatchActor extends AbstractActor {
    final ActorRef child = context().actorOf(Props.empty(), "child");
    !
    public WatchActor() {
    context().watch(child);
    receive(ReceiveBuilder.
    match(Terminated.class,
    t -> t.actor().equals(child),
    t -> {
    … // handle termination
    }).build()
    );
    }
    }
    Create a child actor

    View Slide

  126. Monitor through Death Watch
    X
    public class WatchActor extends AbstractActor {
    final ActorRef child = context().actorOf(Props.empty(), "child");
    !
    public WatchActor() {
    context().watch(child);
    receive(ReceiveBuilder.
    match(Terminated.class,
    t -> t.actor().equals(child),
    t -> {
    … // handle termination
    }).build()
    );
    }
    }
    Create a child actor
    Watch it

    View Slide

  127. Monitor through Death Watch
    X
    public class WatchActor extends AbstractActor {
    final ActorRef child = context().actorOf(Props.empty(), "child");
    !
    public WatchActor() {
    context().watch(child);
    receive(ReceiveBuilder.
    match(Terminated.class,
    t -> t.actor().equals(child),
    t -> {
    … // handle termination
    }).build()
    );
    }
    }
    Create a child actor
    Watch it
    Handle termination message

    View Slide

  128. 4. SUPERVISE
    29
    Every single actor has a default
    supervisor strategy.
    Which is usually sufficient.
    But it can be overridden.

    View Slide

  129. 4. SUPERVISE
    29
    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")
    !

    View Slide

  130. 4. SUPERVISE
    29
    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
    }
    }
    !

    View Slide

  131. Cleanup & (Re)initialization
    30
    class Worker extends Actor {
    ...
    override def preRestart(
    reason: Throwable, message: Option[Any]) {
    ... // clean up before restart
    }
    override def postRestart(reason: Throwable) {
    ... // init after restart
    }
    }

    View Slide

  132. Monitor through Death Watch
    31
    class Watcher extends Actor {
    val child = context.actorOf(Props.empty, "child")
    context.watch(child)
    !
    def receive = {
    case Terminated(`child`) => … // handle child termination
    }
    }

    View Slide

  133. Monitor through Death Watch
    31
    class Watcher extends Actor {
    val child = context.actorOf(Props.empty, "child")
    context.watch(child)
    !
    def receive = {
    case Terminated(`child`) => … // handle child termination
    }
    }
    Create a child actor

    View Slide

  134. Monitor through Death Watch
    31
    class Watcher extends Actor {
    val child = context.actorOf(Props.empty, "child")
    context.watch(child)
    !
    def receive = {
    case Terminated(`child`) => … // handle child termination
    }
    }
    Create a child actor
    Watch it

    View Slide

  135. Monitor through Death Watch
    31
    class Watcher extends Actor {
    val child = context.actorOf(Props.empty, "child")
    context.watch(child)
    !
    def receive = {
    case Terminated(`child`) => … // handle child termination
    }
    }
    Create a child actor
    Watch it
    Handle termination message

    View Slide

  136. Reactive applications scale up 

    and down to meet demand.

    View Slide

  137. Elastic
    • Elasticity and Scalability to embrace the Cloud
    • Adaptive Scale on Demand
    • Clustered servers support joining and leaving of nodes
    • More cost-efficient utilization of hardware
    33
    “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

    View Slide

  138. 34
    Scale OUT
    Scale UP

    View Slide

  139. 34
    Essentially the same thing

    View Slide

  140. 35
    1. Minimize Contention
    2. Maximize Locality of Reference
    We need to

    View Slide

  141. 36
    Share
    NOTHING
    Design

    View Slide

  142. Fully event-driven apps are a necessity
    X
    Amdahl’s Law will hunt you down

    View Slide

  143. Define a router
    X
    ActorRef router = context().actorOf(
    new RoundRobinPool(5).props(Props.create(Worker.class)),
    “router”)

    View Slide

  144. Define a router
    37
    val router = context.actorOf(
    RoundRobinPool(5).props(Props[Worker])), “router”)

    View Slide

  145. …or from config
    38
    akka.actor.deployment {
    /service/router {
    router = round-robin-pool
    resizer {
    lower-bound = 12
    upper-bound = 15
    }
    }
    }

    View Slide

  146. Turn on clustering
    39
    akka {
    actor {
    provider = "akka.cluster.ClusterActorRefProvider"
    ...
    }
    cluster {
    seed-nodes = [
    “akka.tcp://[email protected]:2551",
    “akka.tcp://[email protected]:2552"
    ]
    auto-down = off
    }
    }

    View Slide

  147. 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  
           }  
       }  
    }

    View Slide

  148. 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

    View Slide

  149. Use clustered pub-sub
    41

    View Slide

  150. Use clustered pub-sub
    41
    class Subscriber extends Actor {
    val mediator =
    DistributedPubSubExtension(context.system).mediator
    mediator ! Subscribe(“content”, self)
    def receive = { … }
    }

    View Slide

  151. 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)
    }
    }

    View Slide

  152. • Cluster Membership
    • Cluster Pub/Sub
    • Cluster Leader
    • Clustered Singleton
    • Cluster Roles
    • Cluster Sharding
    42
    Other Akka Cluster features

    View Slide

  153. • Supports two different models:
    • Command Sourcing
    • Event Sourcing
    • Great for implementing
    • durable actors
    • replication
    • CQRS etc.
    • Messages persisted to Journal and replayed on restart
    43
    Use Akka Persistence

    View Slide

  154. X
    Command Sourcing Event Sourcing

    View Slide

  155. X
    Command Sourcing Event Sourcing
    write-ahead-log

    View Slide

  156. X
    Command Sourcing Event Sourcing
    write-ahead-log derive events from a command

    View Slide

  157. X
    Command Sourcing Event Sourcing
    write-ahead-log derive events from a command
    same behavior during recovery
    as normal operation

    View Slide

  158. X
    Command Sourcing Event Sourcing
    write-ahead-log derive events from a command
    same behavior during recovery
    as normal operation
    only state-changing behavior
    during recovery

    View Slide

  159. X
    Command Sourcing Event Sourcing
    write-ahead-log derive events from a command
    same behavior during recovery
    as normal operation
    only state-changing behavior
    during recovery
    persisted before validation

    View Slide

  160. X
    Command Sourcing Event Sourcing
    write-ahead-log derive events from a command
    same behavior during recovery
    as normal operation
    only state-changing behavior
    during recovery
    persisted before validation events cannot fail

    View Slide

  161. X
    Command Sourcing Event Sourcing
    write-ahead-log derive events from a command
    same behavior during recovery
    as normal operation
    only state-changing behavior
    during recovery
    persisted before validation events cannot fail
    allows retroactive changes to
    the business logic

    View Slide

  162. X
    Command Sourcing Event Sourcing
    write-ahead-log derive events from a command
    same behavior during recovery
    as normal operation
    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

    View Slide

  163. X
    Command Sourcing Event Sourcing
    write-ahead-log derive events from a command
    same behavior during recovery
    as normal operation
    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

    View Slide

  164. X
    Command Sourcing Event Sourcing
    write-ahead-log derive events from a command
    same behavior during recovery
    as normal operation
    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

    View Slide

  165. 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

    View Slide

  166. 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

    View Slide

  167. Akka  Persistence  Webinar
    Consistency boundary
    • An Actor is can define an Aggregate Root
    • Each containing one or more Entities
    • Aggregate Root is the Transactional Boundary
    • Strong consistency within an Aggregate
    • Eventual consistency between Aggregates
    • No limit to scalability

    View Slide

  168. DEMO TIME
    Persist a game of ping pong

    View Slide

  169. View Slide

  170. http://reactivemanifesto.org

    View Slide

  171. Typesafe Activator
    http://typesafe.com/platform/getstarted

    View Slide

  172. 48
    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

    View Slide

  173. Reactive is being adopted across

    a wide range of industries.

    View Slide

  174. 50
    Finance Internet/Social Media Mfg/Hardware Government Retail

    View Slide

  175. Questions?

    View Slide

  176. ©Typesafe 2014 – All Rights Reserved

    View Slide