February 6, 2016

Connecting machines in a local network using Elixir nodes

Distribution out-of-box is one of the great features any Elixir application can have due to how Erlang VM operates, and it is one of the reasons the language is gaining popularity.

It is the ability to easily create clusters (scaling horizontally) instead of depending in one single machine resources (scaling vertically) to perform any computation. The most important, you can get this advantage of a distributed system anytime, without modifying any core functionality of your project.

Assuming that:

  • both machines are in the same network;
  • they can communicate with each other;
  • both have Elixir installed.

For this basic example, the machines will simply run iex, one machine will create a simple function to display its node name. The another machine will execute the remote function and receive the output.

Setup

Machine 1 has IP 172.16.0.1 and machine 2 has IP 172.16.0.2.

On machine 172.16.0.1

iex --name machine1@172.16.0.1 --cookie somecookie

On machine 172.16.0.2

iex --name machine2@172.16.0.2 --cookie somecookie

Both machines need to define a common word/phrase using the argument --cookie. If the machines have different cookies they cannot connect with each other.

Connection

To establish a connection, let's use the function Node.connect/1. In the machine 1:

iex(machine1@172.16.0.1)1> Node.list
[]

iex(machine1@172.16.0.1)2> Node.connect :"machine2@172.16.0.2"
true

iex(machine1@172.16.0.1)3> Node.list
[:"machine2@172.16.0.2"]

As long the machine 1 is connected with machine 2 the message exchange can happen in both ways, it doesn't matter what machine started the connection.

Executing code in a remote node

Let's create a very simple function that will return a greetings message from the node that executes the code.

iex(machine1@172.16.0.1)4> greetings = fn -> IO.puts "Hello from #{Node.self}" end
#Function<20.54118792/0 in :erl_eval.expr/5>

iex(machine1@172.16.0.1)5> Node.spawn(:"machine2@172.16.0.2", greetings)
#PID<9071.68.0>
Hello from machine2@172.16.0.2

The function Node.self/0 returns the node name, showing that the code was executed in the machine 2.

Node.spawn/2 spawns a process in a node (in our case, a remote one) passing a function to be executed. The return is a PID (the process id in the remote node) following by the output of the function passed.