We’ve all heard that Erlang (and therefore Elixir) is brilliant for building distributed applications. I even did a post that had a small distributed Elixir section (see: A Sneak Peek into Distributed Elixir).
A Quick Refresher on Connecting Nodes
In that post, I showed how easy it was to connect nodes together in Elixir. Here’s a quick refresher. Open 2 terminal windows.
In the first window:
% iex --sname one
Erlang/OTP 17 [erts-6.0] [source-07b8f44] [64-bit] [smp:2:2] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
Interactive Elixir (0.13.1-dev) - press Ctrl+C to exit (type h() ENTER for help)
iex(one@benjamintan)1>
In the second window:
% iex --sname two
Erlang/OTP 17 [erts-6.0] [source-07b8f44] [64-bit] [smp:2:2] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
Interactive Elixir (0.13.1-dev) - press Ctrl+C to exit (type h() ENTER for help)
iex(two@benjamintan)1>
Here, we use the short name (--sname
) flag to start the 2 nodes. At this point, the nodes cannot see each other yet. Let’s change that.
In this example, I will pick the second terminal session (iex(two@benjamintan)
):
iex(two@benjamintan)1> Node.connect :'one@benjamintan'
true
Success! You can see the connected node(s) using Node.list/0
. If you run this function on one@benjamintan
, you get:
iex(one@benjamintan)1> Node.list
[:two@benjamintan]
Note that it only shows the nodes connected except itself. If you wanted an entire list of connected nodes, you could do this:
iex(one@benjamintan)2> [node|Node.list]
[:one@benjamintan, :two@benjamintan]
What about Connecting Nodes via LAN?
This was the exact question I was asking myself today. Unfortunately, my Google-fu was not strong, so I had to resort to good old trial-and-error.
I had written a simple distributed application, and wondered if I could test it on 2 separate machines instead of simply opening 2 iex
sessions. Obviously, I knew this could be done, but I had to prove to myself that it worked.
Turns out, it wasn’t that complicated (nothing really is once you got things figured out). If you have 2 machines with Elixir (or Erlang) installed, and you haven’t done this before, I encourage you to try this out.
Step 1: Find out the IP Addresses of both machines
First, we need to find out the IP addresses of both machines. On Linux/Unix systems, that’s usually ifconfig
. Also, do make sure that they both are connected to the same LAN.
So here’s an example output on one of my machines:
% ifconfig
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
options=3<RXCSUM,TXCSUM>
inet6 ::1 prefixlen 128
inet 127.0.0.1 netmask 0xff000000
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1
nd6 options=1<PERFORMNUD>
gif0: flags=8010<POINTOPOINT,MULTICAST> mtu 1280
stf0: flags=0<> mtu 1280
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
ether 10:93:e9:05:19:da
inet6 fe80::1293:e9ff:fe05:19da%en0 prefixlen 64 scopeid 0x4
inet 192.168.0.103 netmask 0xffffff00 broadcast 192.168.0.255
nd6 options=1<PERFORMNUD>
media: autoselect
status: active
In this case, the IP address I’m interested in is 192.168.0.103
. On the other machine, the IP address is 192.168.0.100
.
Step 2: Connecting both Nodes together
Alright, let’s give this a go. On the first machine, start iex
but this time with the long name (--name
) flag. Also, append @<ip-address>
after the name.
% iex --name one@192.168.0.100
Erlang/OTP 17 [erts-6.0] [source-07b8f44] [64-bit] [smp:2:2] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
Interactive Elixir (0.13.1-dev) - press Ctrl+C to exit (type h() ENTER for help)
iex(one@192.168.0.100)1>
Do the same on the second machine:
% iex --name two@192.168.0.103
Erlang/OTP 17 [erts-6.0] [source-07b8f44] [64-bit] [smp:2:2] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
Interactive Elixir (0.13.1-dev) - press Ctrl+C to exit (type h() ENTER for help)
iex(two@192.168.0.103)1>
With that, let’s connect one@192.168.0.100
to two@192.168.0.103
:
iex(one@192.168.0.100)1> Node.connect :'two@192.168.0.103'
false
Wait what? On two@192.168.0.103
, you would be able to see a similar error report:
=ERROR REPORT==== 25-May-2014::22:32:25 ===
** Connection attempt from disallowed node 'one@192.168.0.100' **
Remember the Cookie!
When you connect nodes on the same machine AND you do not set any cookie with the --cookie
flag, the Erlang VM simply uses the generated one that sits in your home directory:
% cat ~/.erlang.cookie
XBYWEVWSNBAROAXWPTZX%
This means that if you connect nodes without the cookie flag on the same local machine, you usually will not hit into any problems.
On different machines however, this is a problem, since the cookies are likely to be different (unless you copied them over by hand). So, let’s restart the entire process, except this time, we a cookie value:
On the first machine:
% iex --name one@192.168.0.100 --cookie monster
Erlang/OTP 17 [erts-6.0] [source-07b8f44] [64-bit] [smp:2:2] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
Interactive Elixir (0.13.1-dev) - press Ctrl+C to exit (type h() ENTER for help)
iex(one@192.168.0.100)1>
On the second machine, we make sure we use the same cookie value:
% iex --name two@192.168.0.103 --cookie monster
Erlang/OTP 17 [erts-6.0] [source-07b8f44] [64-bit] [smp:2:2] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
Interactive Elixir (0.13.1-dev) - press Ctrl+C to exit (type h() ENTER for help)
iex(two@192.168.0.103)1>
Let’s connect one@192.168.0.100
to two@192.168.0.103
again:
iex(one@192.168.0.100)1> Node.connect :'two@192.168.0.103'
true
iex(one@192.168.0.100)2> Node.list
[:"two@192.168.0.103"]
Hurray! You have successfully set up an Elixir cluster in your LAN. Instead of typing the full IP address, you could always add an entry to /etc/hosts
, but I’m too lazy for that.
Step 3: Write a Distributed Map-Reduce in Elixir …
… or not.
Thanks for reading!