100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

Erlang and Distributed Systems

Explore how Erlang nodes connect, communicate transparently, and stay resilient across a distributed cluster.

Practical ErlangAdvanced11 min readJul 10, 2026
Analogies

Connecting Erlang Nodes

An Erlang node is identified by a name of the form shortname@host (or longname@fully.qualified.host in -name mode). When a node starts in distributed mode, it registers with a small local daemon called EPMD (Erlang Port Mapper Daemon, listening on TCP port 4369 by default), which maps node names to the dynamic port each node's distribution listener is bound to. Two nodes can only connect if they share the same Erlang cookie, an atom-valued shared secret used as a lightweight authentication token; net_adm:ping('other@host') is the conventional way to establish and verify a connection.

🏏

Cricket analogy: Erlang's shared cookie authenticating nodes is like an ID card checked at the players' entrance before an IPL match — only those holding the correct credential get access to the dressing room network, regardless of which stadium (host) they arrive at.

Location-Transparent Messaging

Once nodes are connected, Erlang's messaging is location-transparent: Pid ! Msg uses exactly the same syntax whether Pid identifies a process on the local node or a process running on a remote node, and spawn/2,3,4 can start a process directly on a remote node by passing its name as the first argument. rpc:call(Node, Module, Function, Args) layers a synchronous request/response convenience on top of this same messaging, letting you invoke a function on a remote node and block for its result the way you would call a local function.

🏏

Cricket analogy: Sending Pid ! Msg with identical syntax locally or remotely is like a captain signaling a fielder the same hand gesture whether they stand at slip five meters away or on the boundary eighty meters out.

erlang
%% On node1@host1
(node1@host1)1> net_adm:ping('node2@host2').
pong

(node1@host1)2> Pid = spawn('node2@host2', fun() ->
                     receive
                         {From, Msg} -> From ! {self(), {got, Msg}}
                     end
                 end).
<8933.72.0>

(node1@host1)3> Pid ! {self(), hello}.
{<0.90.0>,hello}

(node1@host1)4> flush().
Shell got {<8933.72.0>,{got,hello}}
ok

%% RPC: run a function on a remote node and get the result back
(node1@host1)5> rpc:call('node2@host2', erlang, node, []).

Global Process Registration and Distributed Monitoring

The global module extends local process registration across the whole cluster: global:register_name(Name, Pid) makes a process reachable by one unique name that resolves consistently from any connected node, and global:whereis_name(Name) looks it up. To react to connectivity loss, a process can call monitor_node(Node, true) to receive a {nodedown, Node} message when the connection to that specific remote node drops, which is how supervisors and cluster managers detect and respond to partitions.

🏏

Cricket analogy: global:register_name giving a process one unique name recognized cluster-wide is like the ICC maintaining a single official ranking for a player that every board recognizes identically, rather than each cricket board keeping its own separate ranking.

Distributed Erlang has no built-in partition tolerance. If the network splits, both sides of a split-brain keep running independently — global:register_name/2 can end up with two processes both believing they hold the same unique name, and Mnesia can accumulate conflicting writes on each side. Production clusters typically add explicit split-brain detection (e.g. via unsplit strategies) or avoid full-mesh distributed Erlang across unreliable WAN links entirely.

Practical Limits and Alternatives

By default, distributed Erlang forms a full mesh: every connected node maintains a direct TCP connection to every other node. That works well for clusters of a handful to a few dozen nodes, but connection and heartbeat overhead grows quadratically, so it doesn't scale gracefully to hundreds of nodes without alternative topologies such as those offered by Partisan. It's also worth noting that distributed Erlang's default transport is unencrypted and authenticated only by the shared cookie, so production deployments crossing untrusted networks typically enable inet_tls_dist for certificate-based encryption instead of relying on the cookie alone.

🏏

Cricket analogy: Full-mesh clustering where every node connects to every other node is like every team in a 20-team league needing to schedule and track a direct fixture against all 19 others simultaneously — manageable for a small league but unwieldy once the competition grows to fifty teams.

  • Erlang nodes are identified as name@host and discover each other's listening port through EPMD (Erlang Port Mapper Daemon), typically on TCP port 4369.
  • A shared secret called the Erlang cookie authenticates nodes to each other; nodes with different cookies cannot connect.
  • Message sending (Pid ! Msg) and spawning are location-transparent — identical syntax whether the target process is local or on a remote node.
  • rpc:call/4 executes a function on a remote node and returns its result synchronously, layered on top of ordinary message passing.
  • global:register_name/2 provides a cluster-wide unique process name, resolved consistently across every connected node.
  • Full-mesh clustering (every node connected to every other node) doesn't scale gracefully much beyond a few dozen nodes.
  • Distributed Erlang's default TCP transport is unencrypted; inet_tls_dist enables TLS-secured inter-node traffic for untrusted networks.

Practice what you learned

Was this page helpful?

Topics covered

#Programming#ErlangStudyNotes#ErlangAndDistributedSystems#Erlang#Distributed#Systems#Connecting#StudyNotes#SkillVeris#ExamPrep