Consistent Hashing : Distributed System



Consistent hashing is a specialized hashing technique that plays a pivotal role in building distributed systems, particularly in scenarios where you need to evenly distribute data across a dynamic set of nodes. Unlike traditional hashing, which can lead to significant data movement when nodes are added or removed, consistent hashing ensures minimal disruption and maintains balanced load distribution with minimal overhead.

Problem Context: Dynamic Distributed Systems

In a distributed system, data is often partitioned and distributed across multiple nodes (e.g., servers or storage devices). As nodes join or leave the system (such as in cloud-scale applications), the challenge arises in redistributing data. The goal is to minimize the reorganization of data when nodes are added or removed, ensuring that the system remains efficient and scalable. This is where consistent hashing excels.

Traditional Hashing vs. Consistent Hashing

In traditional hashing, each key is mapped directly to a node using a hash function. However, if a node is added or removed, it may require recalculating the hash values of many keys, leading to significant data movement. For instance, if we have N nodes, adding a node means a rehashing of all N keys, which can be expensive in terms of time and resources.

Consistent hashing overcomes this issue by using a circular hash ring, where nodes are positioned on the ring using a hash function. This approach ensures that when a node is added or removed, only a small number of keys need to be redistributed, reducing the amount of data that needs to be moved.

How Consistent Hashing Works

1. Circular Hash Ring: The idea is to visualize the hash space as a ring, typically represented by a range of hash values. Each node in the system is hashed to a point on this ring.


2. Data Assignment: When a key (such as a data item) needs to be stored, it is hashed to the nearest node in the clockwise direction on the ring. This ensures that each key is always mapped to a node.


3. Handling Node Addition/Removal: When a new node is added, it takes the responsibility of the data items that would hash to its location on the ring. Only the keys in the immediate proximity of the newly added node are affected. Similarly, when a node is removed, only its neighbors are responsible for rehashing and taking over its data.


4. Virtual Nodes: To improve load balancing, nodes are often mapped to multiple virtual positions on the ring. This helps ensure that data is evenly distributed, even if the number of nodes in the system is small.



Code Boilerplate for a Basic Consistent Hashing Setup

Here is a simplified example using Python to demonstrate the concept of consistent hashing:

import hashlib
from collections import defaultdict

class ConsistentHashing:
    def __init__(self, nodes=[]):
        self.ring = {}
        self.nodes = set()
        self.num_virtual_nodes = 100  # Virtual nodes for load balancing
        for node in nodes:
            self.add_node(node)

    def _hash(self, key):
        return int(hashlib.sha256(key.encode(‘utf-8’)).hexdigest(), 16)

    def add_node(self, node):
        self.nodes.add(node)
        for i in range(self.num_virtual_nodes):
            virtual_node_key = f”{node}:{i}”
            hash_value = self._hash(virtual_node_key)
            self.ring[hash_value] = node

    def get_node(self, key):
        hash_value = self._hash(key)
        closest_node = min(self.ring.keys(), key=lambda x: (x – hash_value) % (2 ** 256))
        return self.ring[closest_node]

# Example Usage
ch = ConsistentHashing(nodes=[“Node1”, “Node2”, “Node3”])
print(ch.get_node(“mykey”))  # Retrieve node for a key

Benefits of Consistent Hashing

1. Scalability: As nodes are added or removed, the amount of data movement is minimal. Only a small subset of keys will need to be reassigned.


2. Fault Tolerance: In scenarios of node failure, neighboring nodes on the ring will take over the affected node’s data, ensuring continuous availability.


3. Efficient Load Distribution: By leveraging virtual nodes, consistent hashing ensures that the load is evenly distributed, reducing the risk of hotspots.



Applications of Consistent Hashing

Distributed Caching: Systems like Memcached and Redis use consistent hashing to distribute cache entries across multiple nodes with minimal data reshuffling during node changes.

Distributed Databases: NoSQL databases such as Cassandra and Riak implement consistent hashing for partitioning data across a large number of servers.

Content Delivery Networks (CDNs): Consistent hashing helps efficiently map content to edge servers, ensuring minimal disruption when servers are added or removed.


Conclusion

Consistent hashing is an essential technique for building robust and scalable distributed systems. By minimizing data movement during node changes and ensuring even distribution of data, it enhances the efficiency of distributed databases, caching systems, and CDNs. For software engineers and researchers working in distributed systems, mastering consistent hashing is crucial to designing high-performance, fault-tolerant applications.

The article above is rendered by integrating outputs of 1 HUMAN AGENT & 3 AI AGENTS, an amalgamation of HGI and AI to serve technology education globally.

(Article By Himanshu N)