Overview
A complete, production-grade implementation of the Chord protocol for distributed hash tables. This project demonstrates deep understanding of distributed systems, peer-to-peer networks, and consistent hashing. Supports dynamic node join/leave operations with automatic ring stabilization.
Problem Statement
Traditional centralized systems don’t scale. Distributed hash tables (DHTs) enable decentralized data storage and lookup. Chord is a foundational algorithm that guarantees O(log N) lookup time in a P2P network of N nodes—critical for scalable, fault-tolerant systems.
Solution & Approach
Implemented the complete Chord protocol with:
- Finger table routing - Each node maintains pointers at exponential distances for efficient lookup
- Consistent hashing - SHA-1 based key partitioning ensures balanced load distribution
- Stabilization protocol - Automatic ring repair when nodes join/leave
- Concurrent operation - Multi-threaded support for simultaneous requests
Key Features & Achievements
- ✅ O(log N) lookup complexity - Efficient routing through finger table
- ✅ Dynamic membership - Nodes can join/leave without system downtime
- ✅ Ring consistency - Automatic stabilization maintains invariants
- ✅ Concurrent operations - Thread-safe multi-node simulation
- ✅ Full protocol compliance - Implements all Chord specifications
- ✅ Comprehensive testing - Multi-node simulation with synthetic workloads
Code Snippets
Chord Node Implementation (Python):
import hashlib
import socket
from threading import Thread
import time
class ChordNode:
def __init__(self, node_id, port, m=160):
"""Initialize a Chord node in the ring"""
self.node_id = node_id # SHA-1 hash
self.port = port
self.m = m # Number of bits in key space
self.successor = None
self.finger_table = [None] * m # Exponential pointers
self.data_store = {} # Key-value storage
# Start stabilization thread
Thread(target=self.stabilize_ring, daemon=True).start()
def find_successor(self, key_id):
"""Route to successor responsible for key (O(log N))"""
if self.in_range(key_id, self.node_id, self.successor.node_id):
return self.successor
# Use finger table for efficient routing
closest_node = self.closest_preceding_node(key_id)
return closest_node.find_successor(key_id)
def closest_preceding_node(self, key_id):
"""Find closest node in finger table preceding key"""
for i in range(self.m - 1, -1, -1):
finger = self.finger_table[i]
if finger and self.in_range(finger.node_id, self.node_id, key_id):
return finger
return self
def stabilize_ring(self):
"""Periodic stabilization to handle node joins/leaves"""
while True:
# Check if successor is alive
if not self.is_alive(self.successor):
# Find new successor
self.successor = self.find_successor(self.node_id + 1)
# Update finger table entries
for i in range(self.m):
start = (self.node_id + 2**i) % (2**self.m)
self.finger_table[i] = self.find_successor(start)
time.sleep(STABILIZATION_INTERVAL)
def in_range(self, key, start, end):
"""Check if key is in range (start, end] on the ring"""
if start < end:
return start < key <= end
else:
return key > start or key <= end
def is_alive(self, node):
"""Check if a node is responsive"""
try:
socket.create_connection((node.ip, node.port), timeout=1)
return True
except:
return False
Key Distribution with Consistent Hashing:
def put(self, key, value):
"""Store value at responsible node"""
key_id = hash(key) % (2**self.m)
successor = self.find_successor(key_id)
successor.data_store[key] = value
def get(self, key):
"""Retrieve value from responsible node"""
key_id = hash(key) % (2**self.m)
successor = self.find_successor(key_id)
return successor.data_store.get(key)
def delete(self, key):
"""Delete key from responsible node"""
key_id = hash(key) % (2**self.m)
successor = self.find_successor(key_id)
if key in successor.data_store:
del successor.data_store[key]
return True
return False
Technologies Used
Languages: Python 3
Networking: Socket programming, TCP/IP, Multi-threading
Cryptography: SHA-1 hashing for key partitioning
Testing & Simulation: Multi-node network simulation, synthetic workloads
Development Tools: Git, Pytest for testing
Architecture Highlights
Ring-based P2P Network
├── Node A (successor pointers)
├── Node B (finger table routing)
├── Node C (stabilization)
└── Dynamic join/leave handling
- Finger Table: Log(N) pointers enabling efficient routing
- Stabilization: Background process maintains ring integrity
- Key Lookup: Routes through finger table in O(log N) hops
- Replication: Keys distributed across successor nodes
What I Learned
- Deep understanding of distributed systems fundamentals
- Consistent hashing and its application to P2P systems
- Network programming with sockets and TCP/IP
- Concurrency and thread-safe distributed algorithms
- System design principles for scalability and fault tolerance
Use Cases
- Distributed caching (memcached-style)
- P2P file sharing networks (BitTorrent, IPFS)
- Blockchain peer discovery
- Load balancing in microservices
- Decentralized key-value stores
Status: Completed & Tested
Duration: ~2 weeks
Lines of Code: ~500 (core implementation)
GitHub: https://github.com/KarinaNi/chord-dht
Live Demo: [Coming soon]