Architecture
Elixir and Phoenix for Real-Time
Elixir and Phoenix are purpose-built for real-time, concurrent applications. Master the BEAM VM, OTP framework, Phoenix Channels, and the actor model for building systems that handle millions of concurrent connections.
- Concurrency — Lightweight processes (millions of lightweight processes)
- Fault Tolerance — "Let it crash" philosophy with supervisors
- Real-Time — WebSocket channels out of the box
Elixir is what you reach for when real-time is not optional.
The BEAM VM
DfBEAM VM
BEAM (Bogdan/Björn's Erlang Abstract Machine) is the virtual machine that runs Elixir and Erlang code. It provides lightweight processes (not OS processes), preemptive scheduling, per-process garbage collection, and distribution across nodes. The BEAM is designed for soft real-time systems with high concurrency.
Process Model
DfActor Model
The actor model is a concurrency model where each actor (process) communicates exclusively through message passing. Actors have private state, can create new actors, and can send messages to other actors. This eliminates shared state and the need for locks, making concurrent programming safer and more predictable.
OTP Framework
DfOTP
OTP (Open Telecom Platform) is a set of libraries and design patterns for building fault-tolerant applications. It provides supervisors (process hierarchies), GenServer (generic server processes), GenEvent (event managers), and Application (bundling components).
| OTP Behaviour | Purpose |
|---|---|
| GenServer | Generic server with synchronous and asynchronous calls |
| Supervisor | Monitors child processes, restarts on failure |
| Application | Bundles components and manages lifecycle |
| Agent | Simple state management across processes |
| Task | Asynchronous one-shot tasks |
Supervisor Trees
DfSupervisor
A supervisor is a process that monitors and manages child processes. When a child crashes, the supervisor restarts it according to its restart strategy. This is the "let it crash" philosophy—processes don't try to recover; they crash and are restarted by their supervisor.
| Restart Strategy | Behavior |
|---|---|
| one_for_one | Restart only the failed child |
| one_for_all | Restart all children if any fails |
| rest_for_one | Restart failed child and all children started after it |
Supervisor trees enable fault tolerance through isolation. A crash in one process is contained and doesn't affect others. The system self-heals by restarting failed processes, maintaining availability.
Phoenix Channels
DfPhoenix Channels
Phoenix Channels are server-side WebSocket connections that enable real-time, bidirectional communication between client and server. Channels use topics for pub/sub, support authentication, and handle reconnection gracefully.
| Component | Purpose |
|---|---|
| Socket | WebSocket connection handler |
| Channel | Topic-based message handling |
| Topic | Namespace for messages (e.g., "room:lobby") |
| Push | Server → client message |
| Broadcast | Server → all subscribers on a topic |
Phoenix Channel for Chat
# Server-side channel
defmodule MyAppWeb.RoomChannel do
use Phoenix.Channel
def join("room:" <> _room_id, %{"token" => token}, socket) do
if authorized?(token) do
{:ok, socket}
else
{:error, %{reason: "unauthorized"}}
end
end
def handle_in("new_message", %{"body" => body}, socket) do
broadcast!(socket, "new_message", %{
body: body,
user: socket.assigns.user_name,
timestamp: DateTime.utc_now()
})
{:noreply, socket}
end
end
# Client-side JavaScript
let socket = new Socket("/socket", {params: {token: userToken}})
let channel = socket.join("room:lobby", {})
channel.on("new_message", msg => {
console.log(`${msg.user}: ${msg.body}`)
})
channel.push("new_message", {body: "Hello, world!"})
Concurrency at Scale
Elixir Process Overhead
Here,
- =Maximum concurrent processes
- =Available memory
- =Memory per process (~2KB)
Elixir processes are ~2KB each (vs ~1MB for OS threads). A single server can run millions of concurrent processes, making Elixir ideal for chat applications, real-time games, and IoT systems with millions of connections.
Practice Exercises
-
Process Design: Design a chat application using Elixir processes. How do you model rooms, users, and message routing?
-
Supervisor Strategy: Design the supervisor tree for a real-time notification system with WebSocket connections, message queues, and database connections.
-
Phoenix Channel: Build a real-time collaborative document editor using Phoenix Channels. How do you handle conflict resolution?
-
Performance Analysis: Compare the memory and CPU usage of handling 1M concurrent WebSocket connections in Elixir vs Node.js.
Key Takeaways:
- The BEAM VM provides lightweight processes with preemptive scheduling
- The actor model eliminates shared state through message passing
- OTP provides fault tolerance through supervisor trees and "let it crash"
- Phoenix Channels enable real-time WebSocket communication
- Elixir processes are ~2KB each, enabling millions of concurrent connections
- Supervisor trees enable self-healing systems that recover from failures
What to Learn Next
-> WebSockets and Real-Time WebSocket protocols, connection management, and scaling patterns.
-> gRPC and Protobuf High-performance RPC with protocol buffers.
-> Message Queues Async processing, event-driven architecture, and pub/sub patterns.
-> Event-Driven Architecture Event sourcing, CQRS, and message-driven systems.
-> Chat System Design Designing real-time chat systems at scale.
-> Realtime Analytics Design Designing real-time analytics dashboards.