Day 5 of 5
⏱ ~60 minutes
Elixir in 5 Days — Day 5

Distributed Elixir & Production

Elixir runs natively distributed across multiple nodes. Today you connect nodes, use distributed GenServers, deploy with releases, and look at Elixir in production at scale.

Connecting BEAM Nodes

Start a named node: 'iex --sname node1 --cookie secret'. Connect: 'Node.connect(:node2@hostname)'. After connecting, you can spawn processes on remote nodes, send messages to registered processes on other nodes, and call functions on remote nodes. Distributed Erlang/Elixir uses the actor model across a cluster — the same code works locally or distributed.

Mix Releases

Mix releases bundle your Elixir app and its dependencies into a self-contained directory that runs without Elixir or Mix installed. Create a release: 'mix release'. The _build/prod/rel/myapp/bin/myapp start command starts it. Releases embed the BEAM VM, so deployment is just copying a directory. Gigalixir, Fly.io, and Render support Elixir releases natively.

Elixir in Production: Real Numbers

Discord handles 11 million concurrent WebSocket connections on Elixir/Phoenix. WhatsApp ran 2 million connections per server before moving to Erlang clusters. Bleacher Report scaled from 150 servers (Ruby) to 5 servers (Elixir) with better performance. The BEAM's preemptive scheduler ensures low latency under load — it gives each process a fair time slice and never lets one process starve others, unlike Node.js's single-threaded event loop.

bash
# Create and run a Mix project
mix new my_app
cd my_app
mix run --no-halt

# Build a production release
MIX_ENV=prod mix release
./_build/prod/rel/my_app/bin/my_app start

# Start two named nodes (in separate terminals)
iex --sname alice --cookie secret
iex --sname bob --cookie secret

# In alice's iex:
Node.connect(:bob@localhost)
Node.list()  # [:bob@localhost]

# Spawn process on remote node
Node.spawn(:bob@localhost, fn ->
  IO.puts "Running on #{node()}"
end)

# Observer: graphical process inspector
# In iex: :observer.start()

# Check BEAM memory and process count
:erlang.memory()
:erlang.system_info(:process_count)
💡
Use :observer.start() in iex to open a graphical dashboard showing all running processes, memory usage, message queues, and supervision trees. It is the best tool for understanding what your Elixir app is actually doing.
📝 Day 5 Exercise
Deploy an Elixir Release
  1. Add runtime configuration to config/runtime.exs using System.get_env/2
  2. Build a release: MIX_ENV=prod mix release
  3. Start the release and verify it is running
  4. Connect a remote iex shell to the running release: ./bin/my_app remote
  5. Use :observer.start() to inspect the supervision tree and process list

Day 5 Summary

  • BEAM nodes connect over TCP and share the actor model across the cluster
  • Mix releases bundle the VM + app for deployment without Elixir installed
  • Preemptive scheduling ensures low latency even under heavy load
  • Discord (11M connections) and WhatsApp prove BEAM's production scale
  • :observer.start() provides a live graphical view of the BEAM runtime
Challenge

Build a distributed key-value store across two connected BEAM nodes using GenServer. The primary node handles writes; the secondary replicates state via message passing. Simulate primary failure and verify the secondary can take over.

Finished this lesson?