Software architecture · part 6 of 6
MMORPG: architecture for 1 million concurrent players
How to design a 1-million-player MMORPG on AWS: 30 Hz ticks, UDP, spatial partitioning, anti-dupe, anti-cheat telemetry and node failover.
advancedRevised on · 37 min read
This lesson is a deep dive into software engineering and infrastructure for massively multiplayer online games. By the end, you should be able to design from scratch the full architecture of an MMORPG that supports 1 million concurrent players (1M CCU) on AWS. You will understand the physical limits of the network, spatial partitioning algorithms, physics concurrency models, economic integrity and disaster tolerance.
The concepts are illustrated with well-known industry architectures such as World of Warcraft, EVE Online and New World. Every figure was generated and rendered with ArchFlow (see MCP), with the vector diagram sources in the assets folder. The AWS service limits and prices cited here were checked on November 2, 2026. The sources are at the end of the note. The transfer price bands come from third-party tables and must be recalculated in the official AWS calculator before any budget decision.
Map of the lesson
| Part | Sections | Question it answers |
|---|---|---|
| 1. Fundamentals and the brutal scale | 1 to 3 | What makes an MMORPG the hardest problem in distributed computing? |
| 2. Physics, tick rate and transport | 4 to 6 | How do you sync the movement of 1 million people without turning into a slideshow? |
| 3. World division and space | 7 to 9 | How do you slice a continuous world across servers without loading screens? |
| 4. Economy, data and integrity | 10 to 12 | How do you stop item duping and inventory collapse in databases? |
| 5. Social services and metagame | 13 to 15 | How do you run global chat, web auctions and moderation without polluting the simulation? |
| 6. Telemetry, security and costs | 16 to 18 | How do you stop cheaters in real time and survive the AWS network bill? |
| 7. High availability and practice | 19 to 22 | What do you do when a node blows up? Practice exercises and technical glossary |
Part 1: Fundamentals and the brutal scale
1. What an MMORPG is for computing
Ask a player what an MMORPG is and they will talk about shiny swords, dragons and guilds. Ask a distributed systems engineer and the answer is a nightmare. It is a real-time distributed system with state kept in memory, where tens of thousands of clients on unstable connections try to change the same shared variables at the same time, 30 to 60 times per second.
In conventional enterprise web systems, when traffic reaches 1 million requests per second, the traditional recipe is to stack stateless nodes behind load balancers, put a cache in front of the database and go get a coffee. In action MMORPGs, that model simply does not work. The position of your avatar depends on the position of a monster, which depends on a stun spell cast by another player 50 milliseconds ago. You cannot keep the combat position of 1 million entities in a relational database and run a SELECT with a pessimistic lock 30 times per second.
The world state has to live in the volatile memory of the CPU. The collision physics has to run without external locks. And every decision has to reach every interested spectator before the human brain notices a delay longer than 100 milliseconds.
The figure above sums up the backbone of a modern MMORPG running on AWS for 1 million concurrent players. Pay attention to the basic split between two large halves:
- The real-time layer (stateful, with state held in server memory): PC and console players connect with direct UDP packets (datagrams with no delivery confirmation, explained in section 5) through AWS Global Accelerator, which removes hops over the public internet. The packets reach the edge clusters (Edge Gateways), which terminate the encryption and hand clean data to the world simulation nodes (World Nodes) running on compute-heavy C7g instances.
- The metagame layer (stateless, with no context kept in server memory): login, chat, mail, auctions and persistent data run in managed containers (ECS and EKS). They talk to microservices over internal gRPC (binary remote calls, detailed in section 13), and they persist critical data in Amazon DynamoDB, Aurora and Amazon SQS queues.
2. The math of 1 million concurrent players (1M CCU)
To design the supporting infrastructure, we need to translate 1 million connected users into network and operating system quantities. Suppose your game runs at a moderate tick rate of 30 Hz (30 simulation cycles per second):
- Inbound packet rate: if 1,000,000 clients send control data (keyboard, mouse, analog sticks) on every tick of 33.3 milliseconds, your network gateways will receive exactly 30,000,000 packets per second (PPS). For comparison, a gigabit port has a theoretical ceiling of about 1.49 million packets per second with minimum-size 64-byte frames (the frame takes 672 bits on the wire, counting the preamble and the inter-frame gap). Above that, the bottleneck becomes interrupt processing (softIRQs), not bandwidth.
- Outbound packet rate: if the server has to update each client with the state of the objects around it, at a lean average of 40 KB/s of compressed data, the aggregate outbound traffic is 40 gigabytes per second, which is 320 gigabits per second (Gbps) sustained leaving the AWS data centers.
- Data transfer out cost (DTO): on AWS, 1 GB transferred to the internet costs US$ 0.09 in the first volume band and drops to around US$ 0.05 at very high volumes (figures from third-party tables; check the official pricing page for your region). Sustaining 40 GB/s over 30 days works out to about 103 petabytes of data transferred per month. A naive implementation with no bit compression could produce a network bill of hundreds of thousands of dollars before the end of the first month of operation.
The first lesson for a game architect is that saving bits is financial survival. There is no JSON, XML or plain text in the simulation loop of a game this size. Every coordinate, speed and rotation angle is compressed down to the bit level.
3. The core problem: the O(N²) explosion
There is a mathematical reason you never see 1 million players running together on the same square meter of the map: the visibility broadcast problem.
Imagine the plaza of a virtual capital city where $N$ players decide to meet and celebrate the defeat of an invasion boss. If each player moves, the server has to tell every other player present about that movement. The number of messages the server must generate and send on each tick follows the pair-combination formula:
$$M = N \times (N - 1)$$
If there are 10 players in the room, the server generates $10 \times 9 = 90$ messages per tick. At 30 ticks per second, that is 2,700 messages per second, which is trivial. If we gather 2,000 players in the same pitched battle, the formula gives:
$$M = 2{,}000 \times 1{,}999 = 3{,}998{,}000 \text{ messages per tick}$$
At 30 ticks per second, that equals almost 120 million messages per second concentrated on one machine. No commercial CPU on the planet can process that load in a single thread loop.
The chart above shows this asymptotic catastrophe. The red curve is the $O(N^2)$ quadratic growth of naive broadcast. The dashed line at 50,000 messages per tick marks the saturation capacity of a modern simulation node. With only 224 players grouped at the same point, the server crosses the critical threshold and enters a zone of permanent freeze, piling up delay in a cascade.
The green curve is the architectural rescue: spatial partitioning with area-of-interest (AoI) filtering. Instead of listening to the whole world, the client only receives data from its $K$ most relevant or spatially closest neighbors. The cost per player becomes bounded by a constant $K$, which turns the global complexity into $O(N)$. With AoI and grid-based spatial structures (quadtrees, which split the map into quadrants and are defined in the glossary), 2,000 players can coexist in the world without melting the machine.
Part 2: Physics, tick rate and transport
4. The strict budget of the tick loop
The heart of a game simulation server is an infinite loop run at a fixed cadence. We call each iteration of that loop a “tick”. On a server calibrated for 30 Hz, the total CPU time available for all the calculations in one cycle is exactly:
$$T_{\text{budget}} = \frac{1000 \text{ ms}}{30} \approx 33.33 \text{ ms}$$
In high-precision combat games with dodging, many servers run at 50 Hz or 60 Hz. At 50 Hz the window drops to 20 ms, and at 60 Hz it is 16.6 ms. The exact tick rate used by each game cited here was not verified in this review.
During that time window, the server cannot afford blocking network or disk calls. All the work has to fit comfortably inside the budget.
The figure above breaks down the slice of time used by each internal stage of a tick on a server with about 2,500 active entities in memory:
- Input ingestion (3 ms): the server drains the operating system’s network buffers, decompresses the received commands and queues the players’ intentions.
- Physics and collision simulation (12 ms): this is the heaviest stage of the routine. The engine has to move bodies in three-dimensional space, validate walkable surfaces (navmeshes) and check whether arc attacks hit valid targets.
- Combat and artificial intelligence (8 ms): buff and debuff calculations, damage reduction from armor, processing of the monsters’ (NPCs’) behavior trees and death checks.
- Spatial interest query (5 ms): updating the quadtree and computing the visibility lists, so the server knows who must see whom.
- Delta serialization and dispatch (4 ms): building the binary packets containing only the changes relative to the previous tick and sending them asynchronously to the network sockets.
Adding these stages gives 32 milliseconds of work in a peak scenario. That leaves a safety margin of only 1.33 milliseconds before the 33.33 ms limit is exceeded. If execution time goes over the budget, the server is forced to postpone the simulation of the next tick. When this happens repeatedly, the client and server clocks drift apart, and players start to witness the dreaded rubber-banding effect.
5. Why TCP does not fit: the anatomy of the UDP layer
A common question among enterprise developers is why games do not use WebSockets or plain TCP for real-time movement. After all, TCP already guarantees ordered delivery and loss handling.
The answer lies in a built-in TCP mechanism called head-of-line blocking. The TCP protocol was designed on the premise that the integrity of a continuous stream of bytes matters more than its freshness. If a packet carrying your avatar’s position at tick 100 is dropped by a congested router, the operating system’s network stack will hold the packets for ticks 101, 102 and 103 in its buffer until packet 100 is retransmitted successfully.
For a real-time game, this is lethal. The information that you were at coordinate X at tick 100 loses all its value once the clock has reached tick 104. What the client needs is the most recent coordinate now, not the old coordinate that is 200 milliseconds late.
To get around this barrier, all the large MMORPGs implement proprietary protocols or established libraries (such as RakNet, KCP, ENet or WebTransport) that run directly on top of UDP datagrams.
As the diagram above shows, the game’s UDP traffic is split internally into logical channels:
- Unreliable sequenced channel: used for continuous, ephemeral data such as movement vectors, acceleration and camera rotation. If packet 3 is lost on its way, the client simply discards it when packet 4 arrives and applies the newer delta without any interruption.
- Reliable ordered channel: reserved for high-stakes transactions that must not disappear, such as casting a spell, opening a chest or receiving critical damage. This channel implements a lean selective acknowledgment (ACK) scheme and sliding-window retransmission, without blocking the processing of movement data.
6. Authoritative combat: prediction, reconciliation and lag compensation
If the server had to receive confirmation for every button press before showing the result on the player’s screen, the game would feel extremely sluggish. If you click to walk and have to wait 80 milliseconds for a round trip to see your character take its first step, the experience feels heavy.
To solve this, games use a trio of algorithms: strict server authority, client-side prediction and lag compensation.
- Strict authority: the client never decides whether it dealt damage, picked up an item or dodged a blow. The client only sends its intention (“I pressed the attack key at timestamp T with aim vector V”). The server runs the canonical simulation and decides what actually happened.
- Client-side prediction: when you press the forward movement key, your local client immediately moves the avatar and plays the animation without waiting for the network response. It records that movement in a local queue tied to the tick identifier.
- Server reconciliation: when the server’s confirmation arrives, the client compares its predicted coordinate with the authoritative coordinate validated by the server. If they differ (because another player pushed your character at the same moment), the client discards the wrong prediction and smoothly corrects the avatar’s position through interpolation.
The figure above illustrates the lag compensation technique (also called server rewind) during an attack. When player A, with a 70 ms ping, swings at tick 100, the packet takes about 35 ms to arrive. Adding the wait for the next send and the processing time, it only enters the server around tick 102. At that moment, enemy B has already moved somewhere else.
If the server checked the hitbox at the current tick (102), the blow would hit empty air, and the player would experience the frustration of firing at someone and the shot going through their body. To correct this fairly, the world node keeps a circular buffer with the history of positions for the last 1,000 milliseconds. When it processes the command stamped T100, the server rewinds the entities’ clock, checks whether at tick 100 the victim was within the reach of the blow, and applies the damage with historical accuracy.
Part 3: World division and space
7. Partitioning models: instances, zoning and the continuous world
Dividing 1 million players means choosing how the game’s geographic space maps onto the cloud server infrastructure. Historically, the industry has explored three approaches:
- Static zoning with loading screens: the map is cut into fixed provinces. Each province runs in a dedicated process. Moving from a forest into a mountain means crossing a portal and waiting for a loading bar while the assets load. This was the classic approach of games such as EverQuest and the early versions of World of Warcraft.
- Instancing and dynamic sharding: the physical world is duplicated into identical copies called instances or shards. If 10,000 people travel to the same city, the cluster automatically creates 5 copies of the city with 2,000 people each, grouping members of the same party or guild on the same shard. World of Warcraft adopted dynamic layering in its modern expansions.
- Continuous spatial partitioning (seamless world): the supreme goal of game design. The world is one enormous, uninterrupted continent, with no loading screens at all. Multiple cloud compute nodes handle different geographic quadrants, and entities move between servers in a way that is completely invisible to the user. New World, for example, does not have documented spatial partitioning in this format, so we do not take it as an example of a continuous world.
8. The invisible border and seamless handoff
Making a player cross from one server’s territory to another’s without the game freezing or disconnecting is one of the most sophisticated problems in distributed computing.
Suppose node A handles the territory from latitude 0 to 100 and node B handles 100 to 200. What happens when two players fight exactly at coordinate 99.9? Player A is under the authority of machine A, but their sword hits player B, who is on machine B.
The standard solution is to create a replication margin (also called a ghost zone) along every territorial border.
As the diagram above details, the seamless handoff works in five coordinated steps:
- Entering the replication margin: when the player comes within 50 meters of the North sector’s border, node A detects the proximity and warns node B over a very fast internal link through AWS VPC Peering.
- Ghost entity creation: node B instantiates in its local memory a mirror copy (ghost) of the player, fed with the data replicated from node A on every tick. Node B starts simulating local collisions preemptively.
- Notifying the spatial coordinator: node A records the imminent transition in Amazon MemoryDB / Redis, which acts as the authoritative registry of spatial leases, and grants node B the lease for the sector (see the glossary).
- Atomic authority handover: when the avatar crosses the dividing line, node B promotes the ghost entity to authoritative master. Node B notifies the UDP edge gateway so that the client’s new inputs are immediately redirected to its socket.
- Cleaning up traces: node A turns its former master into a temporary ghost and, after a few seconds away, removes the entity from its working memory. The player did not experience a single frame of freezing.
9. The extreme case: time dilation in EVE Online
No study of MMORPG architecture is complete without examining the extreme case of the space game EVE Online. Unlike most games, which split players into separate instances when a region gets overcrowded, EVE Online runs on a single shared universe (single-shard universe).
When two rival corporation fleets decide to go to war over control of a strategic star system, thousands of real players with their ships, drones and missiles jump into the same solar sector, managed by a single bare-metal processing node.
With thousands of entities firing missiles and calculating orbital routes at the same time, the node’s simulation queue grows faster than the server can empty it. Rather than letting the server crash from memory overflow or drop packets at random, CCP Games created the Time Dilation (TiDi) mechanism, described in a devblog from April 2011.
When a node’s simulation queue exceeds the safe processing limit, the server deliberately slows the passage of physical time inside that specific system to as little as 10% of normal speed (1 second of game time takes 10 seconds on the real-life clock). Clients receive the instruction and slow their local physics in sync. The battle looks like it is running in slow motion, but the physics stays consistent and the node does not fall over. The cost is time: the simulation stops keeping up with the real-life clock.
Part 4: Economy, data and integrity
10. The dupe exploit nightmare and the transaction model
In a massively multiplayer game, the internal economy is as delicate as a country’s banking system. If a group of players finds an item duplication flaw (a dupe exploit), they can generate billions of coins out of nothing, break the auction market and force the developers into the drastic decision of rolling back the whole server, erasing the legitimate progress of the entire community.
The classic duplication bug almost always comes from an uncoordinated disconnect between the game’s memory and the persistent database. Consider the naive scenario:
- Player A transfers a Legendary Sword to player B through the direct trade window.
- Player B’s server successfully saves the new sword to the database.
- Player A’s server suffers an unexpected power failure or process crash before it persists the removal of the sword from A’s inventory.
- When the server restarts, player A still has the sword in their recent backup, and player B also has the sword recorded. The item has been duplicated.
To prevent this disaster, any change to item ownership or monetary value must be handled under the strict properties of ACID transactions (Atomicity, Consistency, Isolation and Durability).
The figure above lays out the dupe-proof transactional architecture built with native AWS services:
- Decoupling the simulation: the real-time combat nodes do not talk directly to the relational database to trade items. They delegate the request to a dedicated trade coordination microservice (Trade Coordinator).
- Two-way session lock: both players enter an inventory lock state while the mutual confirmation window is validated.
- Atomic transactions in Amazon DynamoDB: the final write uses the native atomic transaction feature
TransactWriteItems. In a single atomic call, DynamoDB runs a multi-table operation with a conditional check: it removes the item from A’s inventory (with a condition that checks whether the version attribute is still the expected one, the ConditionCheck) and inserts the item into B’s inventory. If any part fails, the whole operation is rolled back and neither inventory changes. The limit is 100 items and 4 MB per call, and the transaction consumes twice the write capacity, because DynamoDB performs one read for preparation and one for commit per item. - Audit ledger: the completed event is dispatched to an Amazon SQS FIFO queue, with ordering within each message group and deduplication, allowing reconciliation bots to audit wealth deviations in the metagame continuously.
11. Tiered storage architecture on AWS
Keeping 1 million active players requires balancing microsecond latency for combat with safe, durable persistence for users’ digital assets. No single database meets all these needs economically. The solution is a three-tier storage hierarchy:
| Tier | AWS technology | What it stores | Access latency | Consistency strategy |
|---|---|---|---|---|
| Tier 1: Node volatile memory | Local RAM (C++ / Rust) | XYZ coordinates, speed, aggro targets, temporary buffs | about 100 ns (DRAM access) | Local eventual consistency (canonical in the current tick) |
| Tier 2: Distributed cache | Amazon MemoryDB / ElastiCache Redis | Active sessions, presence lists, coordinates for AoI, snapshots for fast recovery | microseconds (order of magnitude) | Synchronous Multi-AZ writes with read replicas |
| Tier 3: Transactional NoSQL database | Amazon DynamoDB | Persistent inventory, character sheets, achievement history | single-digit milliseconds (order of magnitude) | Eventual reads by default, strong with ConsistentRead; ACID transactions of up to 100 items via TransactWriteItems |
| Tier 4: Relational database | Amazon Aurora PostgreSQL | Complex auction houses, guild contracts, family trees | milliseconds (depends on load) | READ COMMITTED isolation by default; SERIALIZABLE on request, with retry; global replicas |
The latency values in the table are orders of magnitude, not guarantees. They vary with item size, region and load.
The secret of this pyramid is the write policy: movement coordinates never touch Tier 3 or Tier 4. They live in Tier 1 and are reflected in Tier 2 at each safety interval. Only structural mutation events (experience gain, gold looted, equipment purchases) trigger writes to Tier 3.
Part 5: Social services and metagame
12. The communication challenge: 1 million people talking
If you think synchronizing monsters is hard, wait until you see the global chat box. In an MMORPG, players expect several text and voice channels with very different scopes:
- Proximity chat (Say / Yell): must reach only the avatars within a physical radius of 20 to 50 meters on the 3D map.
- Party and guild chat: independent of the map. Your friend may be in the deepest dungeon on another server and still needs to receive the message instantly.
- Global trade and world channels: the channel every developer dreams of turning off. Hundreds of thousands of players broadcasting buy and sell offers at the same time.
Running this logic inside the process that calculates monster physics is a sure way to drop the simulation’s frame rate. The social subsystem must be completely decoupled from the physics grid.
The figure above illustrates the scalable messaging mesh built with Amazon Managed Streaming for Apache Kafka (Amazon MSK) and Redis clusters:
- Dedicated connections: clients keep lightweight connections over WebSockets directly to chat gateways running on AWS ECS with Fargate containers. These connections do not compete with the UDP channels used for combat.
- Partitioning by channel: when a message is posted to the global trade channel, the gateway publishes it to a specific topic in Amazon MSK, partitioned by room identifier or geographic region.
- Asynchronous AI-assisted moderation: before the message is echoed across the world, an asynchronous copy is dispatched to audit workers that apply filters for improper language, anti-spam regular expressions and natural language processing (NLP) models that block scammers selling gold for real money.
- Fast fan-out: the Redis cluster receives the consolidated events and distributes the messages only to the edge nodes that have members of that guild connected, minimizing unnecessary network traffic.
13. The metagame and the coexistence of gRPC and GraphQL
Not everything in an MMORPG happens inside the game’s 3D client. Modern titles rely on rich ecosystems of satellite applications: mobile apps for managing auctions while the user is at work, web portals for competitive rankings (armories) and public APIs for communities of content creators.
At the core of these services, the engineering team has to pick the right protocols for the right problems:
- Internal gRPC for maximum throughput between backend microservices: communication between the Game World Node and the Inventory Service requires single-digit millisecond latency, ultra-efficient binary serialization through Protocol Buffers and native support for streaming.
- GraphQL for public, web and mobile clients: the screens of a companion app change often. The player may want to load only the character’s picture and gold on the home screen, but the full talent tree and equipped items on the profile screen. GraphQL offers on-demand query flexibility without requiring dozens of redundant REST routes.
The figure above shows how the two protocols coexist:
- The game world node (Game World Node) connects to the inventory microservice (
InventoryService) using pure binary gRPC. TheEquipItemmethod is invoked as a fast unary call, whileStreamItemUpdateskeeps a bidirectional channel open to push inventory changes in real time. - The player’s smartphone app queries the
Metagame GraphQL Gateway. On the auction screen, it runs a query (query playerProfile), sends a bid (mutation bidAuction) and subscribes to a real-time event stream (subscription auctionUpdates) so it is notified the moment its bid is outbid. - Both paths converge safely on Amazon Aurora PostgreSQL, which acts as the canonical relational source of truth for the game’s tradeable goods.
Part 6: Telemetry, security and costs
14. The real-time anti-cheat telemetry pipeline
In an online multiplayer game, if the client has control over the executable code on the local machine, that code will be attacked. Hackers use tools such as Cheat Engine to inject DLLs into the process memory, change the character’s speed multipliers (speedhack), freeze the skill cooldown clock (cooldown hack) or teleport straight to the treasure chest.
The first line of defense is never to trust the client for definitive calculations. Still, clients can try to fool server validation by forging input packets with distorted timestamps.
To identify cheaters safely, without generating false positives that frustrate legitimate players on unstable connections, the architecture needs an analytical telemetry pipeline running in parallel with the game simulation.
The diagram above details this streaming detection pipeline:
- Continuous telemetry emission: every second of simulation, the world node sends, for each player, a compact summary with the velocity vector, impact coordinates and command cadence to a central stream in Amazon Kinesis Data Streams (Amazon MSK also works). With 1 million players, that is about 60 million messages per minute, so the summary is per second and not per tick.
- Analytics with Apache Flink: a managed stream processing application (Amazon Managed Service for Apache Flink) consumes the stream with sliding windows of 5 seconds. The algorithm computes the real average speed the avatar covered:
$$V_{\text{real}} = \frac{|\vec{P}{t} - \vec{P}{t-\Delta t}|}{\Delta t}$$
If $V_{\text{real}}$ exceeds the maximum speed allowed for the character’s class, plus a tolerance calculated for network latency, a physical anomaly is recorded. 3. Enforcement: after accumulating three consistent mathematical anomaly flags within a one-minute interval, the anti-cheat service issues an immediate interruption command via gRPC to the world node. It disconnects the cheater from the session and moves their account to a preventive ban list. 4. Data repository for machine learning: all telemetry history is deposited in columnar Parquet format on Amazon S3 through Amazon Kinesis Data Firehose, which converts JSON to Parquet and requires a schema in the AWS Glue Data Catalog. This feeds machine learning models that refine the identification of autonomous bot behavior patterns.
15. The cloud bill: managing Data Transfer Out (DTO) costs
Building a flawless architecture that runs at 30 Hz means nothing if the company goes bankrupt when the AWS invoice arrives at the end of the first quarter.
In a massively multiplayer game, the heaviest line item is usually outbound traffic to the public internet (Data Transfer Out, or DTO). EC2 instances and databases weigh less on this bill. Compute is billed per hour of machine use, but every byte that crosses AWS’s edge routers toward the player’s home is metered like a taxi.
Consider the comparative economics of a game with 1 million concurrent players connected for 20 hours a day:
Scenario A (naive, JSON or uncompressed structs). The price of US$ 0.07/GB is fixed and hypothetical, just to compare the scenarios. The real rate drops with volume:
Average packet size: 400 bytes per tick
Frequency: 30 ticks per second
Bandwidth per player: 400 * 30 = 12,000 bytes/s (12 KB/s)
Global rate: 1,000,000 * 12 KB/s = 12,000,000 KB/s = 12 GB/s
Monthly volume (20 h/day): 12 GB/s * 3600 s * 20 h * 30 days ≈ 25,920,000 GB = 25.92 petabytes
Approximate monthly cost on AWS (at US$ 0.07/GB): US$ 1,814,400 / month
Scenario B (precision engineering: delta compression, bit packing and AoI):
Average packet size: 40 bytes per tick (90% reduction)
Frequency: 30 ticks per second
Bandwidth per player: 40 * 30 = 1,200 bytes/s (1.2 KB/s)
Global rate: 1,000,000 * 1.2 KB/s = 1,200,000 KB/s = 1.2 GB/s
Monthly volume (20 h/day): 1.2 GB/s * 3600 s * 20 h * 30 days ≈ 2,592,000 GB = 2.59 petabytes
Approximate monthly cost on AWS (at US$ 0.07/GB): US$ 181,440 / month
Applying bit compression and delta encoding rigorously saves more than 1.6 million dollars every month for the same user base. Fundamental good practices for keeping this under control include:
- Quantized compression: a rotation vector needs three 32-bit floats (96 bits in total) if sent raw. But the yaw, pitch and roll angles can be mapped with excellent precision to normalized 8-bit or 16-bit integers (quantization), reducing the payload to 24 bits (3 × 8) or 48 bits (3 × 16).
- Baseline delta compression: the server never sends the full world state on every tick. It sends only the difference (delta) relative to the last tick the client explicitly confirmed receiving via ACK.
- Routing through AWS Global Accelerator: besides reducing jitter and packet loss by injecting traffic into AWS’s private submarine fiber cables at the edge point of presence (Edge POP) closest to the user, it does not reduce the transfer charge, because it adds its own per-GB fee (Data Transfer-Premium) on top of the normal outbound rate. Latency and stability improve; the transfer bill does not drop.
Part 7: High availability and practice
16. What happens when a game node explodes
In a cloud environment with thousands of EC2 servers running in parallel, the only statistical certainty is failure. Compute instances suffer hardware faults in the data center, processes crash from unexpected memory overflows (OOM), and infrastructure maintenance happens without warning.
If a node hosting 2,500 players in the middle of a pitched battle fails, the worst possible response is to disconnect everyone, restart the process from scratch and send the avatars back to the login screen with lost items.
A modern architecture requires transparent failover at the game session level.
The figure above maps the self-healing sequence coordinated by game container orchestrators (such as Agones, an open-source project built on Kubernetes / Amazon EKS):
- Catastrophic failure: the World Node A process suffers a sudden crash and stops answering the network heartbeats.
- Socket retention at the edge: the Edge UDP Gateway notices the absence of simulation ticks from node A, but it does not close the UDP connection with the 2,500 players. The gateway holds the open sockets in temporary buffers for a few seconds, showing a subtle reconnecting indicator on the client. This window must be longer than the detection time: with checks every 1 s, 5 s gives a margin; with Agones’ default (about 15 s), the window would have to exceed that value.
- Detection and allocation by the orchestrator: Agones considers node A dead after consecutive failed health checks on the game server, and provisions a replacement node (Node C). With Agones’ defaults (check every 5 s, 3 consecutive failures), detection takes about 15 s. The figure uses a more aggressive configuration, with a check every 1 s, and therefore shows about 3 s. Teams that need faster recovery keep a warm standby.
- Memory snapshot restore: the new node C connects to Amazon MemoryDB and recovers the last consolidated state snapshot of that geographic sector, written by the application at short intervals (the figure uses 10 seconds as an example; the interval is a design decision). It cross-checks the inventory identifiers against DynamoDB to make sure no item was corrupted during the gap.
- Transparent redirection: node C tells the Edge UDP Gateway that it has taken over the sector. The gateway redirects the UDP datagram flow to node C’s new internal IP address. Simulation resumes, and the 2,500 players go back to moving normally, with no loading screens or login queues.
17. Common mistakes and anti-patterns in MMORPG architectures
Over decades of massive game development history, several classic mistakes have been repeated again and again by studios of all sizes. Knowing these traps is essential to avoid them:
- Putting the game loop behind an Application Load Balancer (ALB): the ALB works with HTTP, HTTPS and gRPC and does not accept UDP listeners, which is the transport of the loop. For UDP, AWS offers the Network Load Balancer. Trying to wrap action simulation in HTTP/REST tunnels creates unacceptable latency and exorbitant header-processing costs.
- Trusting the client’s clock for cooldowns: if you let the client declare that 10 seconds have passed to recharge a powerful spell, a malicious player will change the frequency of the operating system clock to fire meteor storms every millisecond. The cooldown clock always belongs to the server.
- Writing directly to the database on every monster kill: if 1 million players kill 5 monsters per minute, that generates more than 80,000 writes per second to the database. Doing this synchronously will bring down any database cluster. Experience and coin gains should be accumulated in memory and consolidated into the database asynchronously, in periodic batches or at key moments (map change, logout, chest opening).
- Underestimating the problem of concentration: designing the server to support a uniform density of 10 players per square kilometer and forgetting that players will inevitably gather at the gate of the main city’s castle. The system must plan for adaptive visibility limits in the quadtree for when spatial density reaches anomalous levels.
18. Practice exercises: calculation and sizing
Consolidate your knowledge by applying the lesson’s math to solve the following infrastructure design challenges:
Exercise 1: Bandwidth calculation and cluster sizing
A new action MMORPG runs a simulation rate of 50 Hz (50 ticks/s). Thanks to efficient bit compression, the average outbound payload sent to each client is kept at 35 bytes per tick.
- Calculate the outbound data rate generated by a single player in kilobytes per second (KB/s), considering only the payload.
- If the game reaches a peak of 1,000,000 concurrent players, what will the aggregate outbound bandwidth be in gigabits per second (Gbps), counting the headers of each packet (Ethernet, IPv4 and UDP)?
- How many
c7g.16xlargeEC2 instances (nominal network capacity of 30 Gbps per node) are needed so that traffic does not exceed 60% of the theoretical capacity of the network cards?
Guided answer for checking:
- Payload per player: $35 \text{ bytes} \times 50 \text{ ticks/s} = 1,750 \text{ bytes/s} = 1.75 \text{ KB/s}$.
- Payload only, 1 million players: $1.75 \text{ GB/s} \approx 14 \text{ Gbps}$. This number is optimistic, because it ignores the headers, which weigh a lot on small packets.
- Each packet occupies on the wire $35 + 14 \text{ (Ethernet)} + 20 \text{ (IPv4)} + 8 \text{ (UDP)} + 4 \text{ (FCS)} + 20 \text{ (preamble and inter-frame gap)} = 101 \text{ bytes}$. Per player: $50 \times 101 \times 8 = 40,400 \text{ bits/s}$, or 40.4 kbps. For 1 million: 40.4 Gbps.
- With 60% of 30 Gbps, each instance delivers 18 Gbps of useful throughput. $40.4 / 18 \approx 2.24$, so at least 3 instances are needed for bandwidth alone. The packet rate (50 million packets per second in total) usually calls for more nodes, spread across several Availability Zones, and the final count must be confirmed by measurement.
Exercise 2: The Quadtree saturation point
An event arena in the game has 1,200 players gathered together. The server can dispatch at most 36,000 visibility messages per tick before it starts dropping physics frames.
- If there is no interest filtering system at all (naive broadcast), how many messages are generated per tick?
- How many times was the node’s capacity exceeded in this scenario?
- To keep the server stable within the limit of 36,000 messages per tick, what is the maximum number $K$ of visible neighbors that should be configured in the Area of Interest (AoI) filter for each player?
Guided answer for checking:
- Naive broadcast: $1,200 \times (1,200 - 1) = 1,200 \times 1,199 = 1,438,800$ messages per tick.
- Overload factor: $1,438,800 / 36,000 \approx 39.97$ times above the supported limit. The server would freeze instantly.
- AoI configuration: we want $1,200 \times K \le 36,000$. Therefore, $K \le 36,000 / 1,200 = 30$. Each player can only see and receive updates from the 30 most relevant characters (by proximity and combat priority) around them.
19. Technical glossary of game systems
- CCU (Concurrent Users): the number of players connected to the system at the same instant.
- Tick rate: how often the server’s simulation loop runs its physics and combat calculations, expressed in Hertz (Hz).
- AoI (Area of Interest): a set of algorithmic techniques (usually based on spatial trees such as quadtrees or octrees) that determine which entities in the world are relevant to a specific observer.
- Client-side prediction: an algorithm in which the local client simulates and displays the result of the player’s actions before receiving the canonical validation from the network.
- Server reconciliation: the correction process in which the client undoes wrong local predictions and adjusts the avatar’s state when it receives the authoritative snapshot from the server.
- Lag compensation (server rewind): a technique in which the server temporarily rewinds the world’s positional history to validate shots and attacks at the exact moment the player fired in the past.
- Head-of-line blocking: an inherent bottleneck of TCP streams in which the loss of a single packet holds back the delivery of all subsequent packets in the operating system’s buffer.
- Seamless handoff: an imperceptible transfer of authority over an entity between two distinct physics simulation nodes, without requiring loading screens.
- Ghost entity: an in-memory replica of an entity kept on a neighboring node to guarantee visual and physical continuity at map borders.
- Dupe exploit: a vulnerability in the persistence logic that allows items or coins to be cloned through forced disconnections or concurrent, non-isolated transactions.
- Bit packing: a low-level binary compression technique that groups data at the individual bit level, without the standard byte padding.
- UDP (User Datagram Protocol): a connectionless datagram protocol with no delivery confirmation. It is the basis of the movement channels in section 5, which prefer the newest data to retransmitting old data.
- Quadtree: a tree that divides a 2D space into four quadrants and subdivides any quadrant that holds too many entities. It makes it fast to find who is near a given point.
- Heartbeat: a periodic signal a process sends to prove it is alive. When it stops arriving, the orchestrator starts to suspect a failure.
- Stateful and stateless: a stateful service keeps session context in its own memory; a stateless one does not, and each request carries what it needs.
- Lease: a temporary grant of authority over a resource. While the lease is valid, only its holder can change the resource.
- DTO (Data Transfer Out): traffic leaving AWS toward the public internet, billed per GB.
Sources and references
Consulted on November 2, 2026, unless stated otherwise.
- Amazon Web Services. DynamoDB documentation, “Transactions”: TransactWriteItems, item and size limits, isolation and capacity. https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-apis.html
- Amazon Web Services. Amazon EC2, c7g instances: network bandwidth by size (c7g.2xlarge up to 15 Gbps; c7g.16xlarge 30 Gbps). https://aws.amazon.com/ec2/instance-types/c7g/
- Amazon Web Services. AWS Global Accelerator, pricing: a fee per accelerator and Data Transfer-Premium charged on top of normal transfer. https://aws.amazon.com/global-accelerator/pricing/
- Amazon Web Services. Network Load Balancer, user guide: target groups with the UDP protocol. https://docs.aws.amazon.com/elasticloadbalancing/latest/network/introduction.html
- Amazon Web Services. Amazon Data Firehose, record format conversion: JSON to Parquet, with a schema in AWS Glue. https://docs.aws.amazon.com/firehose/latest/dev/record-format-conversion.html
- Agones. Reference: GameServer, health fields with default values (periodSeconds 5, failureThreshold 3). https://agones.dev/site/docs/reference/gameserver/
- AWS for Games. Developer’s Guide to operate game servers on Kubernetes, part 2 (Agones and EKS). Found through search; the full text was not opened in this review. https://aws.amazon.com/blogs/gametech/developers-guide-to-operate-game-servers-on-kubernetes-part-2/
- PostgreSQL Global Development Group. Documentation, “Transaction Isolation”: default READ COMMITTED level and SERIALIZABLE. https://www.postgresql.org/docs/current/transaction-iso.html
- Data transfer rates to the internet by volume band: third-party tables (for example, egresscost.com/aws/data-transfer-pricing). Not confirmed against the official AWS pricing page in this review. Check the AWS calculator before quoting a budget.
- CCP Games. “Introducing Time Dilation (TiDi)”, devblog of April 22, 2011. Found through search; the full text was not opened in this review. https://eveonline.com/article/introducing-time-dilation-tidi
- EVE University. Wiki, entry “Time Dilation” (10% speed floor). https://wiki.eveuniversity.org/Time_Dilation
- Valve Developer Community. “Lag compensation” page. Could not be opened in this review (HTTP 403). The concept of rewinding the server’s history is described in general terms in section 6. https://developer.valvesoftware.com/wiki/Lag_compensation
- Glenn Fiedler. Gaffer on Games, articles on networking and UDP. Not verified in this review. https://gafferongames.com
Related
- Event-driven architecture
- Idempotency
- Concurrency
- Big O
- CDN
- MCP