Clandestined Rendezvous Hashing
Clandestined is a Python library that implements rendezvous hashing, also known as highest random weight (HRW) hashing. It provides a distributed algorithm for choosing a node from a set of available nodes, ensuring that a minimal number of mappings change when nodes are added or removed. It's built upon the murmur3 hash function. The current version is 1.1.0, and the project's release cadence has been infrequent since its last update in 2016.
Warnings
- breaking The `murmur_seed` keyword argument for `Cluster` and `RendezvousHash` constructors was renamed to `seed`.
- breaking Calling `Cluster.remove_zone`, `Cluster.remove_node`, or `RendezvousHash.remove_node` with a non-existent ID now raises a `ValueError` instead of silently failing.
- breaking Support for custom hash functions (passing a callable to `__init__`) was retracted for the 1.0.0 milestone.
- gotcha Behavior for hash collisions was updated in 1.0.0rc1. In the event of a hash collision between node IDs, the winner is now chosen by `max(str(node_id_1), str(node_id_2))`, providing a deterministic tie-breaking mechanism.
- gotcha The library's `requires_python` field is `UNKNOWN` on PyPI, and its last significant update was in 2016. While some Python 3 compatibility was added in 1.0.1, its compatibility with very modern Python versions (e.g., Python 3.9+) or complex environments might be limited due to the age of the codebase and its C extension (`_murmur3`).
Install
-
pip install clandestined
Imports
- RendezvousHash
from clandestined import RendezvousHash
- Cluster
from clandestined import Cluster
Quickstart
from clandestined import RendezvousHash
# Initialize with a list of node IDs
rh = RendezvousHash(['node-a', 'node-b', 'node-c'])
# Find the appropriate node for a given key
key_to_hash = 'user_session_123'
assigned_node = rh.find_node(key_to_hash)
print(f"Key '{key_to_hash}' assigned to: {assigned_node}")
# Add a new node
rh.add_node('node-d')
new_assigned_node = rh.find_node(key_to_hash)
print(f"After adding node-d, key '{key_to_hash}' assigned to: {new_assigned_node}")
# Remove a node
rh.remove_node('node-a')
final_assigned_node = rh.find_node(key_to_hash)
print(f"After removing node-a, key '{key_to_hash}' assigned to: {final_assigned_node}")