I’ve been building an open-source multiplayer game server framework in Elixir, and I wanted to share the results.
The Challenge: Can the BEAM handle MMO-scale real-time simulation? The conventional wisdom says “use C++ for game servers.” I wanted to prove otherwise.
The Results:
| Metric | Target | Achieved |
|---|---|---|
| Tick time (10K entities) | < 29ms | 8ms avg, 13ms max |
| P99 tick time | < 29ms | 11.1ms |
| Bytes per entity | < 20 | 18 (template bitpacking) |
| Per-player bandwidth | < 1 MB/s | 264 KB/s |
| Full broadcast bandwidth | < 100 MB/s | 5.2 MB/s |
| Crash recovery | < 100ms | 4.6ms |
Key Techniques:
-
Bucket-parallel tick loop — Chunk entities across schedulers, not Task-per-entity
-
Fused encoding — Tick + serialize in one pass while data is hot in L1 cache
-
:maps.from_list— 9x faster thanMap.putin a reduce (TIL!) -
IO lists everywhere — Never concatenate binaries, let
writevgather fragments -
Time-travel debugging — Circular buffer with structural sharing for replay
-
Cross-zone shadows — PubSub-based visibility across zone boundaries
-
Async persistence — Snapshot + journal with atomic writes
The “aha moment”: Killing the 68ms sequential serialization bottleneck. Fused parallel encoding brought it down to 2ms for a typical player’s visible area (500 entities).
Architecture highlights:
-
Hybrid entity model (players as processes, NPCs as data in zone state)
-
ETS spatial grid for O(1) neighbor queries
-
Binary protocol with
reliable_seqgap detection -
Dead reckoning for shadow entity interpolation
-
Hysteresis on zone boundaries to prevent oscillation
Test suite: 340 tests, 0 failures
Still early days, but the engine handles the “10K goblin stress test” without breaking a sweat. Next up: TypeScript client SDK and a simple LiveView visualizer.
Curious if others have pushed the BEAM for real-time simulation workloads. What’s your experience?






















