Skip to content

Consistent Hashing


Definition

Consistent Hashing Definition


How It Works

// CONSISTENT HASHING IMPLEMENTATION

class ConsistentHash<T> {
    private final TreeMap<Long, T> ring = new TreeMap<>();
    private final int virtualNodes;  // Replicas per server
    private final HashFunction hashFunction;

    ConsistentHash(int virtualNodes) {
        this.virtualNodes = virtualNodes;
        this.hashFunction = Hashing.murmur3_128();
    }

    // Add a server to the ring
    void addNode(T node) {
        for (int i = 0; i < virtualNodes; i++) {
            long hash = hash(node.toString() + "#" + i);
            ring.put(hash, node);
        }
    }

    // Remove a server from the ring
    void removeNode(T node) {
        for (int i = 0; i < virtualNodes; i++) {
            long hash = hash(node.toString() + "#" + i);
            ring.remove(hash);
        }
    }

    // Find the server for a key
    T getNode(String key) {
        if (ring.isEmpty()) {
            return null;
        }

        long hash = hash(key);

        // Find next server clockwise
        Map.Entry<Long, T> entry = ring.ceilingEntry(hash);
        if (entry == null) {
            // Wrap around to first server
            entry = ring.firstEntry();
        }
        return entry.getValue();
    }

    private long hash(String key) {
        return hashFunction.hashString(key, StandardCharsets.UTF_8).asLong();
    }
}

Virtual Nodes

Virtual Nodes


Adding/Removing Nodes

Adding and Removing Nodes


Use Cases

// USE CASES FOR CONSISTENT HASHING

// 1. DISTRIBUTED CACHING (Memcached, Redis Cluster)
class DistributedCache {
    private final ConsistentHash<CacheNode> ring;

    Object get(String key) {
        CacheNode node = ring.getNode(key);
        return node.get(key);
    }

    void put(String key, Object value) {
        CacheNode node = ring.getNode(key);
        node.put(key, value);
    }
}

// 2. LOAD BALANCING
class ConsistentLoadBalancer {
    private final ConsistentHash<Server> ring;

    // Route user to consistent server (sticky sessions)
    Server getServerForUser(String userId) {
        return ring.getNode(userId);
    }
}

// 3. DATABASE SHARDING
class ShardRouter {
    private final ConsistentHash<DatabaseShard> ring;

    DatabaseShard getShard(String entityId) {
        return ring.getNode(entityId);
    }
}

// 4. CONTENT DELIVERY NETWORKS (CDNs)
// Route requests to consistent edge servers

// 5. DISTRIBUTED STORAGE (Amazon Dynamo, Cassandra)
// Determine which nodes store each key

// Benefits in all cases:
// - Minimal data movement when scaling
// - Predictable key location
// - Easy horizontal scaling

Replication with Consistent Hashing

Replication with Consistent Hashing


Tips & Tricks

Tips and Tricks


  • *