This article explains consistent hashing, a crucial algorithm enabling distributed systems like Cassandra, DynamoDB, and Discord to scale efficiently. It highlights the fundamental problem with naive hashing (modulo N) in dynamic environments and demonstrates how consistent hashing addresses rebalancing issues and minimizes data movement during node additions or removals.
Read original on Medium #system-designIn distributed systems, data is often partitioned across multiple servers using a hash function. A common naive approach is `hash(key) % N`, where `N` is the number of servers. While simple, this method suffers significantly when the number of servers `N` changes. Adding or removing a single server can cause almost all keys to remap to new servers, leading to massive data migration and cache invalidations, which can cripple system performance and availability.
Consistent hashing is an algorithm designed to minimize the number of keys that need to be remapped when nodes are added or removed from a distributed hash table. Instead of mapping keys directly to server indices, it maps both servers and keys to a continuous hash ring (or circle). Each server is responsible for a segment of the ring, handling all keys that fall within its segment.
Key Benefit
When a server is added, it only takes a portion of keys from *one* existing server. When a server is removed, its keys are redistributed to its *neighboring* server on the ring, rather than across all remaining servers. This drastically reduces the data movement.
To achieve better load distribution and mitigate hotspots, consistent hashing employs the concept of "virtual nodes" (or "vnodes"). Each physical server is assigned multiple points on the hash ring. This means that if a physical server goes down, its load is distributed more evenly among many remaining servers, instead of overloading just one neighbor. Virtual nodes also help in distributing data more uniformly across the ring, reducing the impact of non-uniform hash distributions.
Conceptual Hashing Ring
Imagine a ring with values from 0 to MAX_HASH. Both server identifiers and data keys are hashed to points on this ring. To find a key's server, you traverse the ring clockwise from the key's hash value until you hit the first server's hash value. That server is responsible for the key.