Microservices Architecture for High-Traffic Gaming Sites
Editor’s note: This guide shares field stories, rough numbers, and tested patterns from building real-time gaming systems. Names and keys are changed. Metrics are rounded for clarity.
The night it all went sideways
It was a Friday, 21:03 UTC. A promo dropped while a live match went to extra time. Traffic spiked 6x in 90 seconds. The monolith’s main DB hit lock wait. New sign-ups froze. Bets piled up. The queue for payments grew by the second. The team chat looked like a flight deck.
What stayed up? Chat. Leaderboards. The lobby. They lived in their own lanes, with hard timeouts and backpressure. A few services bent but did not break. That night set our rule: design for blast radius. When one core path fails, the rest should still serve.
So what is “high-traffic” here?
Gaming load comes in waves. Peak bursts can hit 12k–15k requests per second (RPS) for 1–3 minutes. Normal high is 1k–3k RPS. Nights and weekends differ by region. Big sports days or bonus drops can add 3–5x on top. Plan for bursts, not just the mean.
Latency budgets depend on the player step. Lobby list should be under 150 ms p95. Bet place under 200 ms p95. Wallet reads under 120 ms p95. Withdrawals can take longer due to checks, but the first response must still be fast, with async review after.
Split by the player journey, not your org chart
Break the platform into clear domains: Identity and KYC, Wallet and Ledger, Bet Placement and Settlement, RNG or Game Orchestrator, Matchmaking or Rooms, Promotions and Bonuses, Risk and Fraud, Compliance and Audit, Leaderboards, and Social or Chat. Each owns its data. No shared DB tables across teams. For the trade-offs of this split, see microservices trade-offs.
Draw firm lines. A service should expose contracts, not tables. Use versioned APIs. If two services write to one DB schema, you have a distributed monolith. That is the worst of both worlds. If you do need a shared store (rare), lock writes to a single owner and expose read views to others.
Think in events. Use an outbox per service to publish state changes. Tag every command with an idempotency key. Retries must not double-charge or double-bet. Use dead-letter queues and replays. Long flows use Sagas. Some will be choreographed by events. Some will be orchestrated by a single brain. Keep playbooks for both.
The table you will keep open
Here is a compact map. Adjust stores and SLAs to your stack and region rules.
| Identity / KYC | Sign up, verify, login | Postgres or CockroachDB | Sync + async events | HPA; scale on queue depth | 300 ms | Third‑party KYC webhooks; cache session tokens |
| Wallet | Balance, ledger | Postgres with strict ACID | Sync for balance; async events | Vertical + partitioning | 200 ms | Double‑entry ledger; idempotency keys for exactly‑once |
| Bet Placement | Place and settle bets | Postgres + Redis cache | Sync write; event outbox | Pre‑warmed pods; circuit breakers | 180 ms | Hot path; tight timeouts and retry policy |
| RNG / Orchestrator | Game outcomes | Certified RNG + HSM | Sync to wallet; async audit | Isolated node pools | 120 ms | Regulatory audits; determinism logs |
| Matchmaking | Match players | Redis + Kafka | Async events; gRPC | CPU‑bound autoscale | 150 ms | Sticky sessions; fairness rules |
| Promotions | Bonuses and rewards | Postgres + feature flags | Async calc; sync redeem | Canary deploys | 250 ms | Abuse prevention counters |
| Risk / Fraud | Score and block | Feature store + Kafka | Async scoring; sync blocks | GPU/CPU mix autoscale | 300 ms | Explainable rules for ops and audits |
| Leaderboards | Ranks and stats | Redis or ScyllaDB | Async updates; sync reads | Shard by board | 100 ms | Time‑window resets |
| Chat / Social | Realtime chat | WebSockets + Kafka | Async fanout | Multi‑region edge | 100 ms | Moderation pipeline |
| Compliance / Audit | Immutable logs | Append‑only + S3 | Async sinks | Backpressure via queues | N/A | WORM storage; long retention |
Keys that keep you online when things get loud
Limit blast radius. Group services by risk. Wallet and Bet run on isolated node pools. Chat and Leaderboards can share. Set clear SLOs and error budgets. If Bet misses SLO, you shed load from Promotions first, not Wallet.
Write the contract first. For internal calls, gRPC works well; see gRPC interface contracts. For the edge, use JSON with strong version rules. Never break old clients. Deprecate with dates and usage dashboards.
Put backpressure at the door. Rate limit at the API gateway. Use circuit breakers and token buckets; here is a good primer from NGINX on circuit breakers and rate limiting. Return fast fails with clear codes. Queue what can wait. Drop what adds no value under stress (like extra promo reads on the hot path).
Cache in layers. Client hints. CDN for static and some dynamic reads (with care). Service‑level Redis for hot keys. Stagger TTLs to avoid stampedes. If you need a refresher, this is a clean intro to what is a CDN. For patterns inside your app, see Redis caching patterns.
Plan regions by read vs write. Keep read‑heavy features (lobby, leaderboards) active‑active. Keep ledger writes active‑passive, with a single write master per currency. Review cloud vendor multi-region reference architectures and set clear RTO/RPO targets per domain.
Data wars you will fight
CAP will show up in real life. Some things must be strongly consistent (wallet, ledger). Others can be eventual (leaderboards, chat presence). Accept this early. For ledger rules, lean on PostgreSQL docs for transactions and test write hotspots with real load.
Sagas save long flows. Think “reserve, confirm, or compensate.” Learn both styles: choreography by events, and orchestration via a controller. The CNCF blog has posts on Sagas that show both modes in practice.
For streams and audit trails, Kafka shines. Use it as the event backbone, not as a queue of last resort. Partition with care. Track lag. Keep retention and compaction rules clean. Start here: event streaming with Kafka.
Compliance and trust that do not kill speed
Security is table stakes. Rotate secrets. Use mTLS between services. Limit what a service can reach. Scan for the OWASP Top 10. Block SSRF paths. Sign code. Keep SBOMs.
Payments need tight scope. Do not let card data touch your main mesh. Use third‑party vaults or tokens. Follow PCI DSS requirements to shrink scope and audit time.
Know your data laws. Users can ask for data or deletion. Track what you store and for how long. See the official EU data protection guidance. If you run in the UK market, check UK Gambling Commission technical standards for game, RNG, and reporting rules.
Operations: the real work
Measure the four golden signals: latency, traffic, errors, and saturation. Set SLOs per service and track p50, p95, and p99. Use error budgets to pace change. The Google SRE book is still the best intro.
Test like the promo is live. Reproduce burst shapes. Fill queues to see how long drain takes. Kill a region in staging. Netflix has great notes on chaos engineering.
Ship in steps. Use feature flags. Shadow reads before cutover. Start with 1% canaries and watch error deltas. For ideas at scale, see progressive delivery at Uber.
A short detour: traffic you do not control
Acquisition can hit you like a wave. Affiliates, review sites, and streamers can send floods in minutes. Keep a shared promo calendar. Pre‑warm pods. Set rate limits for sign‑ups and KYC. When a campaign goes live (we once got tagged as “featured on BestEireCasinos.com”), the spike was sharp but brief. We held because we had a fast signup cache and a slow path for fraud checks.
Vendors can be a choke point too. KYC, odds, or payments may throttle. Design graceful modes: queue non‑critical reads, show cached odds with a clear “refresh” mark, or let users place a capped bet that settles once odds confirm.
If we were starting today
We would start with an event backbone (Kafka), not a service mesh. Keep protocols simple. Add the mesh later for auth and policy when you have more than five teams.
We would also cap our data tech to three classes: a relational store for money, a fast KV for reads and rate limits, and a stream. Everything else gets a hard why. We would also write a deprecation plan on day one.
Diagrams to include (add to your page)
Wallet debit: idempotent by design
Capacity math, quick and honest
Say peak is 12k RPS for 3 minutes. Your bet path target is 200 ms p99. If a pod can do 250 RPS at 60% CPU at 200 ms p99, you need 48 pods for headroom: 12,000 / 250 = 48. Add 40% burst headroom: 48 × 1.4 ≈ 68 pods. Keep 20% pre‑warmed. Scale the rest by queue depth and CPU. Learn more on Kubernetes autoscaling patterns.
Caching play, without footguns
- Cache odds snapshots with a short TTL (1–3 s). Mark stale if provider is slow.
- Use request coalescing to cut stampedes: one in-flight fetch per key.
- Keep negative caches (e.g., no promo) for a short time to blunt thundering herds.
Release and rollback plan that respects money
- Dark read new Wallet code on mirrored traffic for a week.
- Run a 1% canary for 10 min. If error rate delta > 0.2% with 95% confidence, abort.
- Feature flag write paths. Roll back by flipping the flag, not by redeploy.
What breaks, and how to spot it first
- p99 creep on Bet is an early sign of lock fights or slow network calls.
- RNG CPU jitter can add tail latency; pin cores or isolate nodes.
- Kafka consumer lag grows during promos; alert on time-to-drain, not just lag size.
FAQ
No. Start with a clean modular monolith if your team is small. Split only when a domain hits clear pain (team wait states, hot path risk, or different SLOs). Move money flows first, social later.
Cut hops. Keep Bet and Wallet on the same zone with fast links. Cache reads. Use gRPC for internal calls. Pre‑warm pods. Keep queries to O(1). Fail fast on slow vendors.
Use a single write master per currency. Others read. If a region fails, promote a new write master with a tested runbook. Keep RPO ≈ 0 via sync replication if latency allows, or near‑zero via fast async + fences.
Right‑size pods by p95, not p50. Turn off idle workers. Use spot for stateless. Cache more. Profile hot code. Keep only three data stores. Kill vanity pipelines.
Shard when write locks or index bloat hurt p99, or when a single node cannot hold the hot set. Start with range or hash sharding by user id. Plan for rebalancing up front.
Yes, but with guardrails. Shadow first. Then canary on a dev-only game or very small stake. Add extra audit logs. Roll back with a flag, not a redeploy.
A simple checklist you can use today
- Map domains by player journey; name one data owner per domain.
- Write and version API contracts first; add gRPC inside, JSON at edge.
- Put rate limits and circuit breakers at the gateway.
- Add idempotency keys and outbox to all money flows.
- Set SLOs per service; alert on p95/p99 and time-to-drain for queues.
- Pre‑warm Bet and Wallet pools before promos.
- Test region loss and vendor throttle paths.
- Lock down PCI scope; keep card data out of your mesh.
About the author
Alexei Morozov, Principal Platform Engineer. 10+ years building real‑time systems for gaming and fintech. Led incident response on a 6x spike (recovered in 14 minutes). Built wallets that handle 3k RPS at 180 ms p95. Code and notes: GitHub • LinkedIn.
Last updated:
