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 …

Mapreduce

… or not.

Thanks for reading!