Overview
What this concept solves
The ring methods all share one assumption: you keep a structure (the ring, the vnode list) and look keys up against it. Rendezvous hashing throws that away. There is no ring and no stored positions. Instead, for every key you ask each server one question — 'what's your score for this key?' — and the highest score wins. That's the entire algorithm.
The score is just a hash of the two names combined: score = hash(server + key). Because the hash mixes both the server's name and the key's name, every (server, key) pair gets its own pseudo-random number between 0 and 1. The server with the biggest number for a given key owns that key. It's also called HRW — Highest Random Weight — for exactly this reason.
The magic is what happens when a server leaves. A key only moves if the server that left was its winner. In that case the key simply falls to whoever had the second-highest score — and no other key is touched, because their winners didn't change. You get minimal, surgical reassignment without ever placing anything on a ring.
Mechanics
How it works
Score everyone, pick the max
- For the key you're placing, loop over every server.
- For each server, compute
score = hash(server_name + key_name). - Keep the server with the highest score. That server owns the key.
- To replicate to R servers, just take the top R scores instead of the top 1.
Each key decides independently, so the work is O(N) per lookup — you score all N servers. There's no ring to keep sorted and no virtual nodes to manage; the only state is the list of server names. For small to medium N this is wonderfully simple.
Why removal is so clean
Imagine a key's scores ranked: alpha (0.91), gamma (0.62), beta (0.40). alpha wins. Remove alpha and the ranking is just gamma (0.62), beta (0.40) — gamma takes over. Crucially, every key whose winner wasn't alpha sees no change at all, because dropping alpha doesn't alter anyone else's scores. The prototype shows this directly: the second-place bar is already visible before you remove the leader.
Weighting is easy too
To make a bigger server take more keys, multiply (or transform) its score so it wins more often — a small formula change, no extra ring positions. This is why rendezvous is popular when you want capacity-awareness without the bookkeeping of virtual nodes.
The cost is the O(N) scan
Because every lookup scores every server, rendezvous gets expensive when N is large (thousands of nodes). For big fleets people either cap N, use it only at a small top layer, or switch to a method with cheaper lookups (jump hash, Maglev). For tens of servers, the scan is nothing.
Interactive prototype
Run it. Break it. Tune it.
Sandboxed simulation embedded right in the page. No setup, no install.
About this simulation
Each key runs its own little lottery: every server computes a score of hash(server + key), and the highest score wins. Click any key chip to see its bars — the tallest one (badged WINS) is its server. Remove a server with the ✕ and watch only its keys jump to their second-place bar; everyone else is untouched.
Hands-on
Try these on your own
Open the prototype above, run each experiment, predict the answer, then verify.
Read a lottery
Click any key chip. The bars show every server's hash(server + key) score for that key; the tallest, badged WINS, is the owner. Try a few keys — each has a totally different winner because each runs its own independent lottery.
Remove the winner, watch second place take over
Pick a key, note its winner and its second-place bar. Now click the ✕ on that winning server's card. The key (and only keys it was winning) flips to second place — the narration tells you how many moved and how many were untouched.
Add servers and watch balance hold
Use Add server and +5 keys. Notice the per-server counts stay fairly even without any virtual nodes — and adding a server only pulls over the keys whose new ticket beats their old winner. No global reshuffle, no ring.
In practice
When to use it — and what you give up
When to reach for it
- Small or medium clusters — a handful to a few hundred servers, where an O(N) scan per key is cheap.
- You want weights without vnodes — capacity-aware placement falls out of a small tweak to the score.
- You need the top-R for replication — picking the R highest scores gives a natural, stable replica set.
- Caching layers — its original use (CARP, web proxy caches): clients independently agree on which cache holds an object, with no coordination.
Pros
- No ring, no virtual nodes — the only state is the list of server names.
- Naturally even distribution, even with few servers (no lumpy arcs to fix).
- Removal is surgical: only the leaving server's keys move, each to its second choice.
- Weights and top-R replication come from tiny formula changes.
Cons
- O(N) per lookup — you score every server — so it scales poorly to very large N.
- More hashing work per lookup than a ring's single binary search.
- Less common in off-the-shelf infrastructure than the ring, so fewer ready-made libraries.
- Still hash-based, so balance is statistical, not exactly equal.
Reference
Code & further reading
A minimal reference implementation and pointers worth bookmarking.
// Rendezvous (HRW) hashing: score every server, pick the highest.
package main
import "sort"
type Rendezvous struct {
servers []string
}
func (r *Rendezvous) hash(s string) uint32 {
var h uint32 = 2166136261
for i := 0; i < len(s); i++ {
h ^= uint32(s[i])
h *= 16777619
}
return h
}
// score combines server + key, so each pair gets its own number
func (r *Rendezvous) score(server, key string) uint32 {
return r.hash(server + "|" + key)
}
func (r *Rendezvous) GetServer(key string) (string, bool) {
best, bestScore, found := "", uint32(0), false
for _, s := range r.servers {
v := r.score(s, key)
if !found || v > bestScore {
bestScore, best, found = v, s, true
}
}
return best, found // O(N): we looked at every server
}
// Top-R servers => a natural replica set
func (r *Rendezvous) GetReplicas(key string, n int) []string {
sorted := append([]string(nil), r.servers...)
sort.Slice(sorted, func(i, j int) bool {
return r.score(sorted[i], key) > r.score(sorted[j], key)
})
if n > len(sorted) {
n = len(sorted)
}
return sorted[:n]
}
func main() {
rv := &Rendezvous{servers: []string{"alpha", "beta", "gamma"}}
rv.GetServer("user:42") // the highest-scoring server
rv.GetReplicas("user:42", 2) // its primary + backup
}References & further reading
4 sources- Articleen.wikipedia.org
Wikipedia — Rendezvous (HRW) hashing
The clearest reference: the algorithm, the weighted variant, and the O(N) vs O(log N) tradeoff against the ring.
- Papersemanticscholar.org
Thaler & Ravishankar — Using Name-Based Mappings to Increase Hit Rates (1998)
The original paper that introduced HRW, motivated by distributed web caching — the same problem that birthed consistent hashing.
- Articledzone.com
DZone — Consistent Hashing vs. Rendezvous Hashing
A side-by-side comparison: when the ring's O(log N) lookup beats HRW's even distribution, and vice versa.
- Specietf.org
IETF draft — Weighted HRW and its applications
How weighting is added to HRW in practice, and where it's used in networking (load distribution across links/next-hops).
Knowledge check
Did the prototype land?
Quick questions, answers revealed on submit. Sign in to save your best score.
question 01 / 03
How does rendezvous hashing decide which server owns a key?
question 02 / 03
When a server is removed, which keys move and where?
question 03 / 03
What is the main downside of rendezvous hashing?
0/3 answered
Was this concept helpful?
Tell us what worked, or what to improve. We read every note.