Step 1 of 5 · Reading · ~4 min
Read
Production Use
Production Monitoring
A Bloom filter that is overloaded does not crash and does not log an error. It keeps answering, only with more false positives, until every lookup is a MAYBE and the expensive check behind it runs on every request. After this lesson your program reports a filter's health the way an operator needs it: how full it is, how many keys it really holds, what error rate it should have, what error rate it actually has, and whether to rebuild.
Four cheap signals
- load =
n_added / capacity. It is the fraction of the plannednthat has been used. Above 1.0 the filter was sized for the wrongn. It counts everyADD, so duplicates inflate it. - fill =
bits set / m. At the optimalkand exactly the plannedn, the fill is about 0.5 (that is what the optimalkmeans). Clearly above that, the filter is past its design point. Fill ignores duplicates, because adding a key twice sets no new bits. - theoretical FP =
(1 - e^(-k*n_added/m))^k, the formula from the false-positive lesson at the number of adds so far. - actual FP, measured: periodically look up keys you know were never added (use a reserved prefix) and count how often the answer is MAYBE. Compare against the target. A hit counts only if the filter wrongly said MAYBE.
Fill also gives a count that is immune to duplicates. Solving fill = 1 - e^(-k*n/m) for n gives
estimated distinct keys = -(m / k) * ln(1 - fill)
(FULL if fill is 1, where the logarithm is undefined). If n_added is far above the estimate, callers are re-adding the same keys.
A worked example
A filter sized for 50 keys at 0.02: m = 408, k = 6. As keys are added (and 400 never-added keys are probed each time):
| adds | load | fill | theoretical FP | measured FP | estimated keys |
|---|---|---|---|---|---|
| 10 | 0.20 | 0.1324 | 0.0000 | 0.0025 | 10 |
| 25 | 0.50 | 0.2966 | 0.0008 | 0.0050 | 24 |
| 50 | 1.00 | 0.5196 | 0.0199 | 0.0250 | 50 |
| 75 | 1.50 | 0.6642 | 0.0889 | 0.0725 | 74 |
| 100 | 2.00 | 0.7696 | 0.2088 | 0.1675 | 100 |
| 150 | 3.00 | 0.8799 | 0.4965 | 0.4700 | 144 |
Fill passes about 0.5 right at capacity. Past capacity the error rate climbs fast: the theoretical rate here is 0.4965 at 150 adds, many times the target.
A health rule
A filter is healthy when load <= 1.0 and, once at least 10 probes have run, actual FP <= 2 * target. Otherwise report DEGRADED with the reasons: OVER_CAPACITY when the load is above 1.0, FP_TOO_HIGH when there are at least 10 probes and the measured rate is more than twice the target. Fewer than 10 probes is too little data to judge a rate, so it never triggers FP_TOO_HIGH. Even with 10 or more probes the measured rate is noisy, which is why the rule allows a factor of 2 before it complains.
When and how to rebuild
- Load above 1.0: schedule a rebuild at a larger
nduring quiet hours. - Measured FP above target at normal load: suspect the hash (skewed or adversarial keys) and switch to a stronger or keyed one.
- Rebuild without downtime: keep two filters, write to both, and swap reads once the new one is warm; or version the filters and let readers prefer the newest. A scalable filter avoids rebuilds at the price of memory.
Common mistakes
- Counting a probe as a hit when the filter says NO. A hit is a MAYBE for a key that was never added.
- Dividing by zero in
ACTUAL_FPbefore any probe; the answer is0.0000. - Judging the rate on fewer than 10 probes.
- Treating
n_addedas the number of distinct keys. Duplicates raise load but not fill. - Using
>=where the rule says>: a filter loaded to exactly its capacity is healthy.
Your exercise
The starter creates the filter and handles ADD. You implement PROBE, the five gauges (LOAD, FILL, ACTUAL_FP, THEORETICAL_FP, ESTIMATE) and HEALTHY.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…