More Related Content Similar to Magic Clusters and Where to Find Them 2.0 - Eugene Pirogov (20) More from Elixir Club (20) Magic Clusters and Where to Find Them 2.0 - Eugene Pirogov 7. set of loosely or tightly
connected computers that work
together so that, in many
respects, they can be viewed as
a single system
24. ~> iex
Erlang/OTP 19 [erts-8.1] [source] [64-bit] [smp:8:8] [async-
threads:10] [hipe] [kernel-poll:false] [dtrace]
Interactive Elixir (1.3.4) - press Ctrl+C to exit (type h()
ENTER for help)
iex(1)> node()
:nonode@nohost
iex(2)>
26. ~> iex --name eugene
Erlang/OTP 19 [erts-8.1] [source] [64-bit] [smp:8:8] [async-
threads:10] [hipe] [kernel-poll:false] [dtrace]
Interactive Elixir (1.3.4) - press Ctrl+C to exit (type h()
ENTER for help)
iex(eugene@Eugenes-MacBook-Pro-2.local)1>
28. ~> iex --sname eugene
Erlang/OTP 19 [erts-8.1] [source] [64-bit] [smp:8:8] [async-
threads:10] [hipe] [kernel-poll:false] [dtrace]
Interactive Elixir (1.3.4) - press Ctrl+C to exit (type h()
ENTER for help)
iex(eugene@Eugenes-MacBook-Pro-2)1>
30. ~> iex --name eugene@host
Erlang/OTP 19 [erts-8.1] [source] [64-bit] [smp:8:8] [async-
threads:10] [hipe] [kernel-poll:false] [dtrace]
Interactive Elixir (1.3.4) - press Ctrl+C to exit (type h()
ENTER for help)
iex(eugene@host)1>
33. ~> iex --name node1@127.0.0.1
iex(node1@127.0.0.1)1>
~> iex --name node2@127.0.0.1
iex(node2@127.0.0.1)1>
# On node1
iex(1)> :net_adm.ping(:’node2@127.0.0.1’)
:pong
36. # On node2
iex(1)> Process.register(Terminal, self())
# On node1
iex(1)> send({Terminal, :’node2@127.0.0.1’}, “Hello!”)
# On node2
iex(2)> flush()
“Hello!”
38. # On node1
iex(node1@127.0.0.1)1> :rpc.call(:'node2@127.0.0.1', Enum, :reverse, [100..1])
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, …]
iex(node1@127.0.0.1)2>
45. # On node1
iex(1)> :erlang.get_cookie()
:abc
# On node2
iex(1)> :erlang.get_cookie()
:xyz
# On node1
iex(2)> :net_kernel.connect(:'node2@127.0.01')
false
# On node1
iex(3)> :erlang.set_cookie(:’node1@127.0.01’, :xyz)
true
# On node1
iex(4)> :net_kernel.connect(:'node2@127.0.01')
true
50. ~> ps ax | grep epmd
25502 ?? S 0:11.53 /usr/local/Cellar/erlang/19.1/lib/
erlang/erts-8.1/bin/epmd -daemon
56. ~> iex
Erlang/OTP 19 [erts-8.1] [source] [64-bit] [smp:8:8] [async-
threads:10] [hipe] [kernel-poll:false] [dtrace]
Interactive Elixir (1.3.4) - press Ctrl+C to exit (type h()
ENTER for help)
iex(1)>
57. ~> iex
Erlang/OTP 19 [erts-8.1] [source] [64-bit] [smp:8:8] [async-
threads:10] [hipe] [kernel-poll:false] [dtrace]
Interactive Elixir (1.3.4) - press Ctrl+C to exit (type h()
ENTER for help)
iex(1)> node()
:nonode@nohost
iex(2)>
58. ~> iex
Erlang/OTP 19 [erts-8.1] [source] [64-bit] [smp:8:8] [async-
threads:10] [hipe] [kernel-poll:false] [dtrace]
Interactive Elixir (1.3.4) - press Ctrl+C to exit (type h()
ENTER for help)
iex(1)> node()
:nonode@nohost
iex(2)> Process.registered() |> Enum.find(&(&1
== :net_kernel))
nil
59. ~> iex
Erlang/OTP 19 [erts-8.1] [source] [64-bit] [smp:8:8] [async-
threads:10] [hipe] [kernel-poll:false] [dtrace]
Interactive Elixir (1.3.4) - press Ctrl+C to exit (type h()
ENTER for help)
iex(1)> node()
:nonode@nohost
iex(2)> Process.registered() |> Enum.find(&(&1
== :net_kernel))
nil
iex(3)> :net_kernel.start([:’mynode@127.0.0.1’])
{:ok, #PID<0.84.0>}
iex(mynode@127.0.0.1)4>
60. ~> iex
Erlang/OTP 19 [erts-8.1] [source] [64-bit] [smp:8:8] [async-
threads:10] [hipe] [kernel-poll:false] [dtrace]
Interactive Elixir (1.3.4) - press Ctrl+C to exit (type h()
ENTER for help)
iex(1)> node()
:nonode@nohost
iex(2)> Process.registered() |> Enum.find(&(&1
== :net_kernel))
nil
iex(3)> :net_kernel.start([:’mynode@127.0.0.1’])
{:ok, #PID<0.84.0>}
iex(mynode@127.0.0.1)4> Process.registered() |>
Enum.find(&(&1 == :net_kernel))
:net_kernel
84. iex --name node1@host1.com
iex --name node2@host1.com
iex --name node3@host2.com
iex --name node4@host2.com
iex --name node5@host3.com
iex --name node6@host3.com
89. $ iex --remsh foo@127.0.0.1 --cookie abc --
name bar@localhost
Erlang/OTP 19 [erts-8.1] [source] [64-bit]
[smp:8:8] [async-threads:10] [hipe] [kernel-
poll:false] [dtrace]
Interactive Elixir (1.3.4) - press Ctrl+C to
exit (type h() ENTER for help)
iex(foo@127.0.0.1)1>
90. $ kubectl get pods -l app=matcher -o template --
template="{{range.items}}{{.metadata.name}}{{end}}" | xargs -o
-I my_pod kubectl exec my_pod -i -t -- iex --name
debugging@127.0.0.1 --remsh marketplace@127.0.0.1 --cookie
marketplace
91. $ kubectl get pods -l app=matcher -o template --
template="{{range.items}}{{.metadata.name}}{{end}}" | xargs -o
-I my_pod kubectl exec my_pod -i -t -- iex --name
debugging@127.0.0.1 --remsh marketplace@127.0.0.1 --cookie
marketplace
92. $ kubectl get pods -l app=matcher -o template --
template="{{range.items}}{{.metadata.name}}{{end}}" | xargs -o
-I my_pod kubectl exec my_pod -i -t -- iex --name
debugging@127.0.0.1 --remsh marketplace@127.0.0.1 --cookie
marketplace
109. …a simple case where workers are
dynamically created in response to
some events under a supervisor, and
we want them to be distributed across
the cluster and be discoverable by
name from anywhere in the cluster
114. …I didn’t want to resort to
something like Docker,
because I wanted to see how
far I could push Elixir and its
tooling.
121. iex(node1@127.0.0.1)1> :mnesia.create_schema([:'node1@127.0.0.1'])
:ok
iex(node1@127.0.0.1)2> :mnesia.start()
:ok
iex(node1@127.0.0.1)3> :mnesia.info()
---> Processes holding locks <---
---> Processes waiting for locks <---
---> Participant transactions <---
---> Coordinator transactions <---
---> Uncertain transactions <---
---> Active tables <---
schema : with 1 records occupying 413 words of mem
===> System info in version "4.14.1", debug level = none <===
opt_disc. Directory "/Users/gmile/Mnesia.node1@127.0.0.1" is used.
use fallback at restart = false
running db nodes = ['node1@127.0.0.1']
stopped db nodes = []
master node tables = []
remote = []
ram_copies = []
disc_copies = [schema]
disc_only_copies = []
[{'node1@127.0.0.1',disc_copies}] = [schema]
2 transactions committed, 0 aborted, 0 restarted, 0 logged to disc
0 held locks, 0 in queue; 0 local transactions, 0 remote
0 transactions waits for other nodes: []
:ok
iex(node1@127.0.0.1)4>
122. iex(node1@127.0.0.1)1> :mnesia.create_schema([:'node1@127.0.0.1'])
:ok
iex(node1@127.0.0.1)2> :mnesia.start()
:ok
iex(node1@127.0.0.1)3> :mnesia.info()
---> Processes holding locks <---
---> Processes waiting for locks <---
---> Participant transactions <---
---> Coordinator transactions <---
---> Uncertain transactions <---
---> Active tables <---
schema : with 1 records occupying 413 words of mem
===> System info in version "4.14.1", debug level = none <===
opt_disc. Directory "/Users/gmile/Mnesia.node1@127.0.0.1" is used.
use fallback at restart = false
running db nodes = ['node1@127.0.0.1']
stopped db nodes = []
master node tables = []
remote = []
ram_copies = []
disc_copies = [schema]
disc_only_copies = []
[{'node1@127.0.0.1',disc_copies}] = [schema]
2 transactions committed, 0 aborted, 0 restarted, 0 logged to disc
0 held locks, 0 in queue; 0 local transactions, 0 remote
0 transactions waits for other nodes: []
:ok
iex(node1@127.0.0.1)4>
“schema” table exists
as a disk_copy (RAM + disk)
on node1@127.0.0.1
128. iex(node2@127.0.0.1)2> :mnesia.start()
:ok
iex(node3@127.0.0.1)2> :mnesia.start()
:ok
iex(node1@127.0.0.1)2> :mnesia.change_config(:extra_db_nodes, [:’node2@127.0.0.1’])
{:ok, [:"node2@127.0.0.1"]}
iex(node1@127.0.0.1)3> :mnesia.change_config(:extra_db_nodes, [:’node3@127.0.0.1’])
{:ok, [:"node3@127.0.0.1"]}
iex(node1@127.0.0.1)1> :mnesia.create_table(:books, [disc_copies: [:'node1@127.0.0.1'],
attributes: [:id, :title, :year]])
:ok
iex(node1@127.0.0.1)4> :mnesia.add_table_copy(:books, :'node2@127.0.0.1', :ram_copies)
:ok
129. iex(node2@127.0.0.1)2> :mnesia.start()
:ok
iex(node3@127.0.0.1)2> :mnesia.start()
:ok
iex(node1@127.0.0.1)2> :mnesia.change_config(:extra_db_nodes, [:’node2@127.0.0.1’])
{:ok, [:"node2@127.0.0.1"]}
iex(node1@127.0.0.1)3> :mnesia.change_config(:extra_db_nodes, [:’node3@127.0.0.1’])
{:ok, [:"node3@127.0.0.1"]}
iex(node1@127.0.0.1)1> :mnesia.create_table(:books, [disc_copies: [:'node1@127.0.0.1'],
attributes: [:id, :title, :year]])
:ok
iex(node1@127.0.0.1)4> :mnesia.add_table_copy(:books, :'node2@127.0.0.1', :ram_copies)
:ok
iex(node1@127.0.0.1)5> :mnesia.add_table_copy(:books, :'node3@127.0.0.1', :ram_copies)
:ok
130. iex(node1@127.0.0.1)6> :mnesia.info()
---> Processes holding locks <---
---> Processes waiting for locks <---
---> Participant transactions <---
---> Coordinator transactions <---
---> Uncertain transactions <---
---> Active tables <---
books : with 0 records occupying 304 words of mem
schema : with 2 records occupying 566 words of mem
===> System info in version "4.14.1", debug level = none <===
opt_disc. Directory "/Users/gmile/Mnesia.node1@127.0.0.1" is used.
use fallback at restart = false
running db nodes = ['node3@127.0.0.1','node2@127.0.0.1','node1@127.0.0.1']
stopped db nodes = []
master node tables = []
remote = []
ram_copies = []
disc_copies = [books,schema]
disc_only_copies = []
[{'node1@127.0.0.1',disc_copies},
{'node2@127.0.0.1',ram_copies},
{'node3@127.0.0.1',ram_copies}] = [schema,books]
12 transactions committed, 0 aborted, 0 restarted, 10 logged to disc
0 held locks, 0 in queue; 0 local transactions, 0 remote
0 transactions waits for other nodes: []
:ok
iex(node1@127.0.0.1)32>
131. iex(node1@127.0.0.1)6> :mnesia.info()
---> Processes holding locks <---
---> Processes waiting for locks <---
---> Participant transactions <---
---> Coordinator transactions <---
---> Uncertain transactions <---
---> Active tables <---
books : with 0 records occupying 304 words of mem
schema : with 2 records occupying 566 words of mem
===> System info in version "4.14.1", debug level = none <===
opt_disc. Directory "/Users/gmile/Mnesia.node1@127.0.0.1" is used.
use fallback at restart = false
running db nodes = ['node3@127.0.0.1','node2@127.0.0.1','node1@127.0.0.1']
stopped db nodes = []
master node tables = []
remote = []
ram_copies = []
disc_copies = [books,schema]
disc_only_copies = []
[{'node1@127.0.0.1',disc_copies},
{'node2@127.0.0.1',ram_copies},
{'node3@127.0.0.1',ram_copies}] = [schema,books]
12 transactions committed, 0 aborted, 0 restarted, 10 logged to disc
0 held locks, 0 in queue; 0 local transactions, 0 remote
0 transactions waits for other nodes: []
:ok
iex(node1@127.0.0.1)32>
“schema” + “books” tables exist
on 3 different nodes
3 nodes are running
current node (node1)
keeps 2 tables as RAM + disk
144. If in your cluster the network
connection between two nodes
goes bad, then each one
will think that the other node is down,
and continue to write data.
Recovery from this is complicated.
150. “…In such a highly specialized
environment, the reliability of the control
backplane essentially removes some of
the worries which the CAP theorem
introduces.”