Introduction
Imagine you’re building a chat application like Discord that needs to handle millions of users simultaneously. How do you distribute all that traffic across multiple servers without overwhelming any single machine? The answer lies in a clever technique called “sharding.”
In this lesson, we’ll explore how Discord uses a simple mathematical formula to route billions of messages per day across their server cluster. More importantly, we’ll build it ourselves using modern Java and watch it work in real-time through a visual dashboard.
The Problem: Why Simple Solutions Break at Scale
Let’s start with how most developers would approach this problem. Here’s a typical solution using Spring Boot:
@Service
public class GuildRouter {
@Autowired
private GatewayManager gatewayManager;
private Map<Long, Integer> guildToShard = new ConcurrentHashMap<>();
public Integer getShardForGuild(Long guildId) {
return guildToShard.computeIfAbsent(guildId,
id -> Math.abs(id.hashCode()) % gatewayManager.getShardCount());
}
}This code looks clean and works fine for small applications. But there’s a critical problem that only appears when you scale up to millions of users.
The Hidden Cost of Objects
Every time this code processes a guild ID, it creates Java objects. Specifically:
The guild ID gets “boxed” into a
Longobject (24 bytes)The shard number gets “boxed” into an
Integerobject (16 bytes)The HashMap creates a
Nodeobject to store the mapping (additional 8+ bytes)
For a single request, this seems tiny. But at Discord’s scale, processing 100,000 events per second means:
100,000 new objects created every second
4.8 million bytes (4.8 MB) allocated every second
Java’s garbage collector runs every 2 seconds to clean up this mess
When garbage collection runs, it pauses your entire application. Users see their messages freeze. WebSocket connections timeout. Chaos ensues.


