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

Distributed Elixir

Distributed Elixir

Presentation about some of the tools for distributed programming in Elixir

Maciej Kaszubowski

July 07, 2018
Tweet

More Decks by Maciej Kaszubowski

Other Decks in Programming

Transcript

  1. It’s scary out there

    View full-size slide

  2. Organisational Matters

    View full-size slide

  3. We’re 1 year old!

    View full-size slide

  4. Summer break (probably)

    View full-size slide

  5. We’re looking for speakers!

    View full-size slide

  6. It’s scary out there
    Distributed Systems in Elixir
    Poznań Elixir Meetup #8

    View full-size slide

  7. Pid 1 Pid 2
    Node A Node B

    View full-size slide

  8. iex --name [email protected] --cookie cookie -S mix

    View full-size slide

  9. #PID<0.94.0>

    View full-size slide

  10. #PID<0.94.0>
    node identifier
    (relative to current node)

    View full-size slide

  11. #PID<0.94.0>
    node identifier
    (relative to current node)
    0 =a local process

    View full-size slide

  12. #PID<0.94.0>
    Process id
    node identifier
    (relative to current node)

    View full-size slide

  13. How does it work?

    View full-size slide

  14. Pid 1
    Node A
    Pid 2
    Node B

    View full-size slide

  15. Pid 1
    Node A
    Pid 2
    Node B
    TCP Connection

    View full-size slide

  16. send(pid2, msg)
    Pid 1
    Node A
    Pid 2
    Node B
    TCP Connection

    View full-size slide

  17. send(pid2, msg)
    Pid 1
    Node A
    Pid 2
    Node B
    destination_node = node(pid)
    TCP Connection

    View full-size slide

  18. send(pid2, msg)
    Pid 1
    Node A
    Pid 2
    Node B
    destination_node = node(pid)
    :erlang.term_to_binary(msg)
    TCP Connection

    View full-size slide

  19. send(pid2, msg)
    Pid 1
    Node A
    Pid 2
    Node B
    destination_node = node(pid)
    :erlang.term_to_binary(msg)
    TCP Connection

    View full-size slide

  20. send(pid2, msg)
    Pid 1
    Node A
    Pid 2
    Node B
    destination_node = node(pid)
    :erlang.term_to_binary(msg)
    TCP Connection
    :erlang.binary_to_term(encode)

    View full-size slide

  21. send(pid2, msg)
    Pid 1
    Node A
    receive msg
    Pid 2
    Node B
    destination_node = node(pid)
    :erlang.term_to_binary(msg)
    TCP Connection
    :erlang.binary_to_term(encode)

    View full-size slide

  22. Distributed Systems?

    View full-size slide

  23. Distributed Systems?
    Solved!

    View full-size slide

  24. Well, not exactly…

    View full-size slide

  25. Difficulties

    View full-size slide

  26. Node A
    Node B

    View full-size slide

  27. Node A
    Node B
    Node C

    View full-size slide

  28. Node A
    Node B
    Node C
    Node D

    View full-size slide

  29. A lot of messages

    View full-size slide

  30. us-east-1
    us-west-2

    View full-size slide

  31. 8 fallacies of
    distributed computing

    View full-size slide

  32. fallacies of distributed computing
    1. The network is reliable
    2. Latency is zero
    3. Bandwidth is infinite
    4. The network is secure
    5. Topology doesn’t change
    6. The is one administrator
    7. Transport cost is zero
    8. The network is homogenous

    View full-size slide

  33. CAP THEOREM
    us-west-2
    us-east-1

    View full-size slide

  34. CAP THEOREM
    us-west-2
    us-east-1
    Set X=5

    View full-size slide

  35. CAP THEOREM
    us-west-2
    us-east-1
    Set X=5
    Read X

    View full-size slide

  36. CAP THEOREM
    us-west-2
    us-east-1
    Set X=5
    Set X = 7

    View full-size slide

  37. Consistency or Availability
    (under network partition)

    View full-size slide

  38. Consistency or Speed
    In practice

    View full-size slide

  39. Pid 1
    Pid 2
    Pid3
    Guarantees
    m1, m2, m3
    m4, m5, m6
    send(pid2, m1)
    send(pid2, m2)
    send(pid2, m3)
    send(pid2, m4)
    send(pid2, m5)
    send(pid2, m6)

    View full-size slide

  40. Pid 1
    Pid 2
    Pid3
    Guarantees
    m1, m2, m3
    m4, m5, m6
    send(pid2, m1)
    send(pid2, m2)
    send(pid2, m3)
    send(pid2, m4)
    send(pid2, m5)
    send(pid2, m6)
    Ordering between two processes
    is preserved

    View full-size slide

  41. Pid 1
    Pid 2
    Pid3
    Guarantees
    m4, m5, m6
    send(pid2, m1)
    send(pid2, m2)
    send(pid2, m3)
    send(pid2, m4)
    send(pid2, m5)
    send(pid2, m6)
    m1, m2, m3
    Delivery is not guaranteed

    View full-size slide

  42. Pid 1
    Pid 2
    Pid3
    Guarantees
    m1, m2, m3
    m4, m5, m6
    send(pid2, m1)
    send(pid2, m2)
    send(pid2, m3)
    send(pid2, m4)
    send(pid2, m5)
    send(pid2, m6)
    Ordering between different processes
    is not guaranteed

    View full-size slide

  43. [m1, m2, m3, m4, m5, m6]

    View full-size slide

  44. [m1, m2, m3, m4, m5, m6]
    [m4, m5, m6, m1, m2, m3]

    View full-size slide

  45. [m1, m2, m3, m4, m5, m6]
    [m4, m5, m6, m1, m2, m3]
    [m1, m4, m2, m5, m3, m6]

    View full-size slide

  46. [m1, m2, m3, m4, m5, m6]
    [m4, m5, m6, m1, m2, m3]
    [m1, m4, m2, m5, m3, m6]
    [m1, m2, m3]

    View full-size slide

  47. [m1, m2, m3, m4, m5, m6]
    [m4, m5, m6, m1, m2, m3]
    [m1, m4, m2, m5, m3, m6]
    [m1, m2, m3]
    [m1, m3, m5, m6]

    View full-size slide

  48. [m1, m2, m3, m4, m5, m6]
    [m4, m5, m6, m1, m2, m3]
    [m1, m4, m2, m5, m3, m6]
    [m1, m2, m3]
    [m1, m3, m5, m6]
    []

    View full-size slide

  49. [m1, m2, m3, m4, m5, m6]
    [m4, m5, m6, m1, m2, m3]
    [m1, m4, m2, m5, m3, m6]
    [m1, m2, m3]
    [m1, m3, m5, m6]
    []
    [m1, m3, m2, m4, m5, m6]

    View full-size slide

  50. [m1, m2, m3, m4, m5, m6]
    [m4, m5, m6, m1, m2, m3]
    [m1, m4, m2, m5, m3, m6]
    [m1, m2, m3]
    [m1, m3, m5, m6]
    []
    [m1, m3, m2, m4, m5, m6]
    [M3, M3]

    View full-size slide

  51. Phoenix
    Request A User Logged In

    View full-size slide

  52. Phoenix
    Request A
    Phoenix
    Request B
    User Logged In
    User Logged OUT

    View full-size slide

  53. Phoenix
    Request A
    Phoenix
    Request B
    User Logged In
    User Logged OUT
    This Can arrive first

    View full-size slide

  54. Unfortunately, things tend to work fine
    locally

    View full-size slide

  55. Pid 1
    Node A Node B
    Pid 2

    View full-size slide

  56. Pid 1
    Node A Node B
    Pid 2
    :global.register_name(“global”, self())

    View full-size slide

  57. Pid 1
    Node A Node B
    Pid 2
    :global.register_name(“global”, self())
    Register PId1 as “global”

    View full-size slide

  58. Pid 1
    Node A Node B
    Pid 2
    :global.register_name(“global”, self())
    Register PId1 as “global”
    Sure

    View full-size slide

  59. Pid 1
    Node A Node B
    Pid 2
    :global.register_name(“global”, self())
    Register PId1 as “global”
    Sure
    :global.whereis_name(“global”) = pid1

    View full-size slide

  60. Pid 1
    Node A Node B
    Pid 2
    :global.register_name(“global”, self()) :global.register_name(“global”, self())
    ?

    View full-size slide

  61. :global
    • single process registration (if everything works OK)
    • Favours availability over consistency
    • Information stored locally (reading is fast)
    • Registration is blocking (may be slow)

    View full-size slide

  62. Pid1
    Pid3
    Pid2
    []
    []
    []

    View full-size slide

  63. Pid1
    Pid3
    Pid2
    :pg2.create(“my_group”)
    []
    []
    []

    View full-size slide

  64. Pid1
    Pid3
    Pid2
    []
    []
    []
    join
    join
    :pg2.join(“my_group”, self()

    View full-size slide

  65. Pid1
    Pid3
    Pid2
    []
    [pid1]
    []
    Monitor
    Monitor
    :pg2.join(“my_group”, self()

    View full-size slide

  66. Pid1
    Pid3
    Pid2
    [pid1]
    [pid1]
    [pid1]
    Monitor
    Monitor
    :pg2.join(“my_group”, self()

    View full-size slide

  67. Pid1
    Pid3
    Pid2
    [pid1]
    [pid1]
    [pid1]

    View full-size slide

  68. Pid1
    Pid3
    Pid2
    :pg2.join(“my_group”, self()
    [pid1]
    [pid1, pid2]
    [pid1]

    View full-size slide

  69. Pid1
    Pid3
    Pid2
    join
    :pg2.join(“my_group”, self()
    join
    [pid1, pid2]
    [pid1, pid2]
    [pid1, pid2]

    View full-size slide

  70. Pid1
    Pid3
    Pid2
    [pid1]
    [pid2]
    [pid1]

    View full-size slide

  71. Pid1
    Pid3
    Pid2
    [pid1]
    [pid2]
    [pid1]

    View full-size slide

  72. Pid1
    Pid3
    Pid2
    [pid1]
    [pid2]
    [pid1]

    View full-size slide

  73. Pid1
    Pid3
    Pid2
    [pid1, pid2]
    [pid1, pid2]
    [pid1, pid2]

    View full-size slide

  74. It will heal, but the state in inconsistent for
    some time

    View full-size slide

  75. What does it matter?

    View full-size slide

  76. Node A
    Pg2
    Pg2
    Pg2
    Node B Node C

    View full-size slide

  77. Node A
    Pg2
    Pg2
    Pg2
    Node B Node C
    Phoenix Channels

    View full-size slide

  78. Node A
    Pg2
    Pg2
    Pg2
    Node B Node C
    Phoenix Presence

    View full-size slide

  79. Node A
    Pg2
    Pg2
    Pg2
    Node B Node C
    Phoenix Channels

    View full-size slide

  80. :pg2
    • Process groups
    • Favours availability over consistency
    • Information stored locally (reading is fast)
    • Registration is blocking (may be slow)

    View full-size slide

  81. Strongly consistent Solutions

    View full-size slide

  82. Strongly consistent Solutions
    • Consensus - Raft, Paxos, ZAB
    • Two-phase commit/THree-phase commit (2PC/3PC)
    • Read/Write quorums
    • Single database as a source of truth

    View full-size slide

  83. Distributed Systems

    View full-size slide

  84. Well, not exactly…

    View full-size slide

  85. Asynchronous messages
    Distributed systems are all about

    View full-size slide

  86. Really, there’s no magic

    View full-size slide

  87. Just asynchronous messages between nodes

    View full-size slide

  88. Just asynchronous messages between nodes
    & node failures

    View full-size slide

  89. Just asynchronous messages between nodes
    & node failures
    & Communication failures

    View full-size slide

  90. Just asynchronous messages between nodes
    & node failures
    & Communication failures
    & Network partitions

    View full-size slide

  91. Tradeoffs
    Distributed systems are all about

    View full-size slide

  92. Where to go next

    View full-size slide

  93. Worth looking at
    • Riak_core
    • RAFT
    • Two-Phase Commit (2PC) / Three-Phase Commit (3PC)
    • CRDTs
    • LASP and Partisan

    View full-size slide

  94. Free online (click!)
    Elixir / Erlang

    View full-size slide

  95. Free PDF (Click!)
    Distributed Systems

    View full-size slide

  96. Theory (The hard stuff)

    View full-size slide

  97. • https://raft.github.io/ (Raft Consensus)
    • http://learnyousomeerlang.com/distribunomicon
    • https://www.rgoarchitects.com/Files/fallacies.pdf (Fallacies of distributed computing)
    • https://dzone.com/articles/better-explaining-cap-theorem (CAP Theorem)
    • https://medium.com/learn-elixir/message-order-and-delivery-guarantees-in-elixir-
    erlang-9350a3ea7541 (Elixir message delivery guarantees)
    • https://lasp-lang.readme.io/ (LASP)
    • https://arxiv.org/pdf/1802.02652.pdf (Partisan Paper)
    • https://bravenewgeek.com/tag/three-phase-commit/ (3PC)

    View full-size slide

  98. We’re looking for speakers!

    View full-size slide

  99. Thank You!
    Poznań Elixir Meetup #8

    View full-size slide