● live results from org.experiments — real Java, real Murmur3

This page runs real algorithms from my systems experiments repo — not simulations. Each tab below calls actual, unmodified Java implementations, so what you see is the real behavior of real code, not a description of it.

Consistent Hashing
Bloom Filter
Cache Scan Resistance

Consistent Hashing: vnodes and load balance

When a server joins or leaves a cluster, you want as few keys as possible to change owners — otherwise every scaling event becomes a mass cache miss or data reshuffle. Consistent hashing solves this by placing servers and keys on the same ring; this test shows exactly how well it works, and what one tuning knob does to the result.

How the test works:
  1. Three servers (nodeA, nodeB, nodeC) are placed on a ring using real Murmur3 hashing — each server actually occupies many scattered points on the ring ("vnodes"), not just one.
  2. A 4th server joins the cluster.
  3. We measure what fraction of keys had to move to a new owner, and how evenly the remaining load is spread across the original three.
  4. This repeats 30 times and averages the results, since ring placement is randomized.
The takeaway: the fraction of keys that move when a node joins is fixed by the node count alone — vnodes can't change that. What vnodes control is load balance: more vnodes per server means more scattered, more even ownership, at the cost of a larger ring to maintain.
Keys relocated (avg of 30 trials)
Imbalance (3-node ring, busiest ÷ fair share)
Measured cv
Theoretical cv √((N-1)/(NV+1))

Sweep across a vnode range

Runs ConsistentHashing.run() at several vnode values and plots the real measured imbalance and cv against the closed-form prediction.

Bloom Filter: false-positive rate

A Bloom filter answers one question fast and cheaply: "have I definitely never seen this before?" It can never wrongly say "definitely not here" for something that was actually added — but it can occasionally, and predictably, mistake something new for something it's seen. This tests how close that mistake rate lands to what you asked for.

How the test works:
  1. A filter is built and sized for n items and a target error rate p — this decides how many bits and hash functions it needs.
  2. n items are added to it.
  3. A separate batch of items — guaranteed never added — is checked against the filter.
  4. Any of those that the filter claims "maybe present" is a false positive. The rate of that is compared to the target.
The takeaway: this is how systems like Cassandra skip disk reads for keys that don't exist — checking a small in-memory filter first is far cheaper than checking disk, and a small, known error rate is worth that speedup.
Target error rate
Measured error rate
Bit array size
Number of hash functions
False positives observed

Cache Scan Resistance

A single flood of one-time-use data can wipe out a cache's entire "hot" working set — unless the cache is smart enough to know the difference between something used once and something used often. This test shows which of four real cache designs actually survive that.

How the test works:
  1. A handful of "popular" items are read over and over, so the cache clearly registers them as important.
  2. The cache is filled up with other, unrelated items — the popular items are now the oldest untouched entries.
  3. A burst of brand-new items arrives, each used exactly once — like a bot scanning sequential records.
  4. We check: are the original popular items still there, or did the scan push them out?
The takeaway: caches that evict "whatever's oldest" (LRU, Striped, Redis-sampled) lose popular items to a big enough scan. Caffeine Lite evicts "whatever's used least often" instead — so it keeps its popular items no matter how large the scan gets.