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

Consistent, Distributed Elixir

Consistent, Distributed Elixir

An explanation of consistency guarantees in erlang and what we might be able to do with a consistency protocol like Raft.

Chris Keathley

February 23, 2018
Tweet

More Decks by Chris Keathley

Other Decks in Programming

Transcript

  1. defmodule Demo.Lock do use GenServer def init(:ok) do state =

    {:unlocked, nil} {:ok, state} end def handle_call({:lock, client}, _from, {:unlocked, nil}) do {:reply, :ok, {:locked, client}} end end
  2. defmodule Demo.Lock do use GenServer def init(:ok) do state =

    {:unlocked, nil} {:ok, state} end def handle_call({:lock, client}, _from, {:unlocked, nil}) do {:reply, :ok, {:locked, client}} end def handle_call({:lock, client}, _from, {:locked, other_client}) do {:reply, :error, {:locked, other_client}} end end
  3. defmodule Demo.Lock do use GenServer def init(:ok) do state =

    {:unlocked, nil} {:ok, state} end def handle_call({:lock, client}, _from, {:unlocked, nil}) do {:reply, :ok, {:locked, client}} end def handle_call({:lock, client}, _from, {:locked, other_client}) do {:reply, :error, {:locked, other_client}} end def handle_call({:unlock, client}, _from, {:locked, client}) do {:reply, :ok, {:unlocked, nil}} end def handle_call({:unlock, client}, _from, {:locked, other_client}) do {:reply, :error, {:locked, other_client}} end end
  4. Some problems need consistency Distributed Locking Databases Distributed scheduling and

    coordination Configuration and metadata storage Transactions
  5. defmodule Demo.Lock do use GenServer def init(:ok) do {:ok, {:unlocked,

    nil}} end def handle_call({:lock, client}, _from, {:unlocked, nil}) do {:reply, :ok, {:locked, client}} end def handle_call({:lock, client}, _from, {:locked, other_client}) do {:reply, :error, {:locked, other_client}} end def handle_call({:unlock, client}, _from, {:locked, client}) do {:reply, :ok, {:unlocked, nil}} end def handle_call({:unlock, client}, _from, {:locked, other_client}) do {:reply, :error, {:locked, other_client}} end end
  6. defmodule Demo.Lock do use Raft.StateMachine def init(:ok) do {:ok, {:unlocked,

    nil}} end def handle_call({:lock, client}, _from, {:unlocked, nil}) do {:reply, :ok, {:locked, client}} end def handle_call({:lock, client}, _from, {:locked, other_client}) do {:reply, :error, {:locked, other_client}} end def handle_call({:unlock, client}, _from, {:locked, client}) do {:reply, :ok, {:unlocked, nil}} end def handle_call({:unlock, client}, _from, {:locked, other_client}) do {:reply, :error, {:locked, other_client}} end end
  7. defmodule Demo.Lock do use Raft.StateMachine def init(:ok) do {:unlocked, nil}

    end def handle_call({:lock, client}, _from, {:unlocked, nil}) do {:reply, :ok, {:locked, client}} end def handle_call({:lock, client}, _from, {:locked, other_client}) do {:reply, :error, {:locked, other_client}} end def handle_call({:unlock, client}, _from, {:locked, client}) do {:reply, :ok, {:unlocked, nil}} end def handle_call({:unlock, client}, _from, {:locked, other_client}) do {:reply, :error, {:locked, other_client}} end end
  8. defmodule Demo.Lock do use Raft.StateMachine def init(:ok) do {:unlocked, nil}

    end def handle_write({:lock, client}, _from, {:unlocked, nil}) do {:reply, :ok, {:locked, client}} end def handle_call({:lock, client}, _from, {:locked, other_client}) do {:reply, :error, {:locked, other_client}} end def handle_call({:unlock, client}, _from, {:locked, client}) do {:reply, :ok, {:unlocked, nil}} end def handle_call({:unlock, client}, _from, {:locked, other_client}) do {:reply, :error, {:locked, other_client}} end end
  9. defmodule Demo.Lock do use Raft.StateMachine def init(:ok) do {:unlocked, nil}

    end def handle_write({:lock, client}, {:unlocked, nil}) do {:reply, :ok, {:locked, client}} end def handle_call({:lock, client}, _from, {:locked, other_client}) do {:reply, :error, {:locked, other_client}} end def handle_call({:unlock, client}, _from, {:locked, client}) do {:reply, :ok, {:unlocked, nil}} end def handle_call({:unlock, client}, _from, {:locked, other_client}) do {:reply, :error, {:locked, other_client}} end end
  10. defmodule Demo.Lock do use Raft.StateMachine def init(:ok) do {:unlocked, nil}

    end def handle_write({:lock, client}, {:unlocked, nil}) do {:ok, {:locked, client}} end def handle_call({:lock, client}, _from, {:locked, other_client}) do {:reply, :error, {:locked, other_client}} end def handle_call({:unlock, client}, _from, {:locked, client}) do {:reply, :ok, {:unlocked, nil}} end def handle_call({:unlock, client}, _from, {:locked, other_client}) do {:reply, :error, {:locked, other_client}} end end
  11. defmodule Demo.Lock do use Raft.StateMachine def init(:ok) do {:unlocked, nil}

    end def handle_write({:lock, client}, {:unlocked, nil}) do {:ok, {:locked, client}} end def handle_write({:lock, client}, {:locked, other_client}) do {:error, {:locked, other_client}} end def handle_call({:unlock, client}, _from, {:locked, client}) do {:reply, :ok, {:unlocked, nil}} end def handle_call({:unlock, client}, _from, {:locked, other_client}) do {:reply, :error, {:locked, other_client}} end end
  12. defmodule Demo.Lock do use Raft.StateMachine def init(:ok) do {:unlocked, nil}

    end def handle_write({:lock, client}, {:unlocked, nil}) do {:ok, {:locked, client}} end def handle_write({:lock, client}, {:locked, other_client}) do {:error, {:locked, other_client}} end def handle_write({:unlock, client}, {:locked, client}) do {:ok, {:unlocked, nil}} end def handle_write({:unlock, client}, {:locked, other_client}) do {:error, {:locked, other_client}} end end
  13. Raft.start_peer(Demo.Lock, name: :s1) Raft.start_peer(Demo.Lock, name: :s2) Raft.start_peer(Demo.Lock, name: :s3) Raft.set_configuration(:s1,

    [:s1, :s2, :s3]) :ok = Raft.write(:s1, {:lock, :s1}) :error = Raft.write(:s2, {:lock, :s2}) :error = Raft.write(:s2, {:unlock, :s2})
  14. Raft.start_peer(Demo.Lock, name: :s1) Raft.start_peer(Demo.Lock, name: :s2) Raft.start_peer(Demo.Lock, name: :s3) Raft.set_configuration(:s1,

    [:s1, :s2, :s3]) :ok = Raft.write(:s1, {:lock, :s1}) :error = Raft.write(:s2, {:lock, :s2}) :error = Raft.write(:s2, {:unlock, :s2}) :ok = Raft.write(:s1, {:unlock, :s1})
  15. Raft.start_peer(Demo.Lock, name: :s1) Raft.start_peer(Demo.Lock, name: :s2) Raft.start_peer(Demo.Lock, name: :s3) Raft.set_configuration(:s1,

    [:s1, :s2, :s3]) :ok = Raft.write(:s1, {:lock, :s1}) :error = Raft.write(:s2, {:lock, :s2}) :error = Raft.write(:s2, {:unlock, :s2}) :ok = Raft.write(:s1, {:unlock, :s1}) :ok = Raft.write(:s2, {:lock, :s2})