Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Scalable dist-sys from grounds up
Search
udit
April 28, 2019
Technology
210
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Scalable dist-sys from grounds up
udit
April 28, 2019
More Decks by udit
See All by udit
Road to masterless multi-node distributed system in Elixir
yudistrange
0
58
Other Decks in Technology
See All in Technology
こんなアーキテクチャ図は嫌だ BEYOND THE TIME: 半年後の自分へ贈る15のメッセージ / 15 of Anti-pattern in AWS Architecture Diagrams
naospon
3
260
いま、生成AIにKaggleをどこまで 任せられるか — ROGIIコンペでの進め方とTips
k951286
3
1.4k
PdMをやめて、 "プロダクトビルダー"という 働き方に変えました / PdM to Product Builder
shikichee
2
730
PfEingのアプローチで働こう
rindrics
0
180
深夜のクラウド懺悔室 1:29:300 or 1:0:0
kazzpapa3
0
190
GoにおけるFFIのこれまでとこれから
goccy
1
130
Webとヘルスデータ
yukukotani
0
190
リージョンの壁を越える、 ちょっと変わったAWSサービスの話
falken
PRO
0
270
Backstageでつくるセルフサービスな社内開発基盤
kikunosuke75
1
340
AI時代におけるプロダクト横断勉強会の設計
zozotech
PRO
0
160
ペアプロの価値はコードを書くことだけじゃない
codmoninc
PRO
0
130
設計の世代交代を乗り越える、14年続くAndroidアプリの開発戦略
sansantech
PRO
1
150
Featured
See All Featured
The Impact of AI in SEO - AI Overviews June 2024 Edition
aleyda
6
1.2k
Color Theory Basics | Prateek | Gurzu
gurzu
0
460
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
1
290
The Organizational Zoo: Understanding Human Behavior Agility Through Metaphoric Constructive Conversations (based on the works of Arthur Shelley, Ph.D)
kimpetersen
PRO
0
440
Digital Ethics as a Driver of Design Innovation
axbom
PRO
1
410
What the history of the web can teach us about the future of AI
inesmontani
PRO
1
680
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
Embracing the Ebb and Flow
colly
88
5.2k
Designing for humans not robots
tammielis
254
26k
30 Presentation Tips
portentint
PRO
1
390
SEO in 2025: How to Prepare for the Future of Search
ipullrank
3
3.8k
Lightning Talk: Beautiful Slides for Beginners
inesmontani
PRO
2
670
Transcript
scalable dist-sys from the grounds up in Elixir
whoami udit @ nilenso
agenda why elixir/erlang under the hood build you a live
game for great good build you a better live game for greater good
why elixir / erlang
why dist-sys are hard? state computation reliability order . .
.
why elixir/erlang asynchronous message passing no sharing fault tolerance
why elixir/erlang distributed out of the box primitives for concurrency
under the hood
beam Bjorn’s erlang abstract machine bytecode ~ erlang / Elixir
/ Gleam / LFE etc
process light weight - green thread communicate via message passing
single threaded
process process control board heap stack
process garbage collection when: heap meets stack runs on process
schedule compaction vs full copy
process schedulers process queues soft pre-emptive
process defmodule RcDemo.Echo do def start() do receive do :exit
-> IO.puts("Shutting down") x -> IO.inspect(x, label: "Received Message on #{inspect(self())}: ") start() end end end
process registration noname :local :global pg2 swarm Registry (elixir)
supervisor reliability monitor other process
gen_server generic server better abstraction over state still a process
defmodule RcDemo.EchoGenServer do use GenServer def start(), do: GenServer.start(__MODULE__, nil) def init(nil), do: {:ok, %{}} def handle_cast(message, state) do IO.inspect(message, label: "Cast:") {:noreply, state} end def handle_call(message, from, state) do IO.inspect(message, label: "Call:") :timer.sleep(2000) {:reply, :called, state} end end
gen_server call GenServer.call(pid, :hi, 1000) cast GenServer.cast(pid, :hello) info send(pid,
:info)
distributed nodes fully connected mesh network heartbeat
None
a live game for great good
listener def receive_message(socket, receive_callback) do case :gen_tcp.recv(socket, 0) do {:ok,
message} -> :gen_tcp.send(socket, "Message received\n") {m, f, a} = receive_callback apply(m, f, a ++ [message]) receive_message(socket, receive_callback) _otherwise -> IO.inspect("Shutting down the socket") end end def listen(port, accept_callback) do {:ok, socket} = :gen_tcp.listen(port, [:binary, reuseaddr: true]) accept_connection(socket, accept_callback) end def accept_connection(listen_socket, accept_callback) do {:ok, accept_socket} = :gen_tcp.accept(listen_socket) spawn(fn -> {m, f, a} = accept_callback receive_callback = apply(m, f, a ++ [accept_socket]) receive_message(accept_socket, receive_callback) end) accept_connection(listen_socket, accept_callback) end
one for all defmodule RcDemo.Game.OneToAll.SingleActor do def start (port), do:
GenServer.start_link( __MODULE__, port, name: {:global, Single}) def init(port) do spawn(fn -> TcpListner.listen(port, {__MODULE__, :noop, []}) end) {:ok, %{}} end def noop(_), do: {__MODULE__, :incoming, []} def incoming(message), do: GenServer.cast(Single, {:incoming, message}) def handle_cast({:incoming, message}, state) do IO.inspect(message, label: "Received in GenServer with pid #{inspect self()}") {:noreply, state} end
one for all
one for all 1 : n single thread of execution
for all incoming message message queue build up no fault tolerance
one for one defmodule RcDemo.Game.OneToOne.Master do def start(port), do: GenServer.start_link(__MODULE__,
port, name: Master) def init(port) do spawn(fn -> TcpListner.listen(port, {__MODULE__, :new_connection, []}) end) {:ok, %{}} end def new_connection(socket) do {:ok, pid} = Worker.start(socket) {Worker, :incoming, [pid]} end end defmodule RcDemo.Game.OneToOne.Worker do def start(_socket), do: GenServer.start_link(__MODULE__, []) def init(_), do: {:ok, %{}} def incoming(pid, message), do: GenServer.cast(pid, {:incoming, message}) def handle_cast({:incoming, message}, state) do IO.inspect(message, label: "Received in Worker with pid: #{inspect self()}") {:noreply, state} end end
one for one 1 : 1 can process responses from
players faster large process queue on schedulers
n to m defmodule RcDemo.Game.Balanced.Master do def init(port) do worker_pids
= Enum.reduce(1..2, [], fn _x, acc -> {:ok, pid} = Worker.start() [pid] ++ acc end) spawn(fn -> TcpListner.listen(port,{__MODULE__, :new_connection, [[worker_pids]]}) end) {:ok, %{}} end def new_connection([worker_pids], socket) do worker_index = hash_socket(socket) worker_pid = Enum.at(worker_pids, worker_index) {Worker, :incoming, [worker_pid]} end defp hash_socket(_socket), do: :rand.uniform(2) – 1 end defmodule RcDemo.Game.Balanced.Worker do def init(_params), do: {:ok, %{}} def incoming(pid, message), do: GenServer.cast(pid, {:incoming, message}) def handle_cast({:incoming, message}, state) do IO.inspect(message, label: "Received in Worker with pid: #{inspect self()}") {:noreply, state} end end
n to m n : m shard player
None
a live game for greater good
addendum supervision
addendum differentiate processes
addendum distributed processes
addendum islands
fin
references Erlang Garbage Collection Details and Why It Matters The
beam book Discord Blog Whatsapp’s island architecture Elixir School Elixir Official Documentation Demo code repo Slides
thank you @yudistrange