Skip to content

parasiitism/consistent_hashing_python

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Consistent Hashing Python

Python badge Hash ring badge Virtual nodes badge Replication badge

A small, colorful Python project for exploring how keys find servers on a hash ring.

Why This Exists

I wanted to understand what really happens when servers are added or removed from a distributed system.

The usual hashing idea is simple:

hash(key) % number_of_servers

That works until the number of servers changes. Add one new server and the modulo value changes. Suddenly, many keys may point somewhere else.

Consistent hashing takes a calmer path:

Put servers on a ring.
Put keys on the same ring.
Move clockwise from the key until a server is found.

That one idea makes the system much less jumpy when servers join or leave.

The Mental Picture

flowchart LR
    K1["user-1"] --> H1["hash(user-1)"]
    H1 --> R["Hash Ring"]
    R --> C{"First server clockwise?"}
    C --> S1["server-A"]

    K2["order-9"] --> H2["hash(order-9)"]
    H2 --> R
    C --> S2["server-B"]

    K3["payment-7"] --> H3["hash(payment-7)"]
    H3 --> R
    C --> S3["server-C"]

    classDef key fill:#FEF3C7,stroke:#F59E0B,color:#111827,stroke-width:2px;
    classDef hash fill:#DBEAFE,stroke:#2563EB,color:#111827,stroke-width:2px;
    classDef ring fill:#F3E8FF,stroke:#7C3AED,color:#111827,stroke-width:3px;
    classDef server fill:#D1FAE5,stroke:#059669,color:#111827,stroke-width:2px;

    class K1,K2,K3 key;
    class H1,H2,H3 hash;
    class R,C ring;
    class S1,S2,S3 server;
Loading

What Is Implemented

The project has one main class:

ConsistentHashRing

It supports:

add_node(node)
remove_node(node)
get_node(key)
get_nodes(key, count)

The ring keeps three important structures:

Structure Purpose
ring Maps hash position to real server
sorted_hashes Keeps all ring positions sorted for clockwise lookup
nodes Stores the real servers currently available

Virtual Nodes

One real server appears multiple times on the ring.

With replicas = 3, server-A becomes:

server-A:0
server-A:1
server-A:2

Each label gets a different hash position, but all of them point back to server-A.

This helps spread keys more evenly.

flowchart TB
    A["server-A"] --> A0["server-A:0"]
    A --> A1["server-A:1"]
    A --> A2["server-A:2"]

    B["server-B"] --> B0["server-B:0"]
    B --> B1["server-B:1"]
    B --> B2["server-B:2"]

    A0 --> R["Sorted Hash Ring"]
    A1 --> R
    A2 --> R
    B0 --> R
    B1 --> R
    B2 --> R

    classDef real fill:#FFE4E6,stroke:#E11D48,color:#111827,stroke-width:2px;
    classDef virtual fill:#E0F2FE,stroke:#0284C7,color:#111827,stroke-width:2px;
    classDef ring fill:#DCFCE7,stroke:#16A34A,color:#111827,stroke-width:3px;

    class A,B real;
    class A0,A1,A2,B0,B1,B2 virtual;
    class R ring;
Loading

Lookup Flow

flowchart TD
    A["Input key"] --> B["Hash the key"]
    B --> C["Find first ring position >= key hash"]
    C --> D{"Position found?"}
    D -- "Yes" --> E["Return mapped server"]
    D -- "No" --> F["Wrap to first ring position"]
    F --> E

    classDef start fill:#FEF3C7,stroke:#F59E0B,color:#111827,stroke-width:2px;
    classDef action fill:#DBEAFE,stroke:#2563EB,color:#111827,stroke-width:2px;
    classDef decision fill:#F3E8FF,stroke:#7C3AED,color:#111827,stroke-width:2px;
    classDef result fill:#D1FAE5,stroke:#059669,color:#111827,stroke-width:2px;

    class A start;
    class B,C,F action;
    class D decision;
    class E result;
Loading

Replication

get_nodes(key, count) walks clockwise and collects distinct real servers.

Example idea:

get_nodes("user-1", 3)

Could return:

["server-A", "server-D", "server-C"]

That gives one primary server and additional backup servers.

Project Layout

consistent_hashing_python/
  src/
    hash_ring.py
    __init__.py
  tests/
    test_hash_ring.py
  docs/
    flow_diagram.md
  simulation.py
  README.md

Run The Simulation

python simulation.py

The simulation shows:

Initial key mapping
Movement after removing a server
Movement after adding a server
Replica selection

Run Tests

python -m unittest discover -s tests

Current result:

Ran 10 tests
OK

My Favorite Part

The neat part is that the system does not panic when the server list changes.

When a node disappears, only the keys owned by that node need a new home. When a node appears, it takes over just part of the ring. The rest of the keys stay exactly where they were.

That is the quiet power of consistent hashing.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages