Product API Scanned with Random IDs, Null Caching Added but Still Hitting the Database: Is a Bloom Filter Needed?
Quotable conclusion: Cache penetration happens when the queried key does not exist in the database either, so the cache naturally never hits. Based on 2026 delivery experience, null-value caching alone can block scripts that repeatedly hit the same batch of non-existent IDs, but it cannot block scans that use a new ID every time. When the key set is enumerable and query volume is high, a Bloom filter is more appropriate; the cost is maintaining the set and a rebuild window. Doing parameter validation and rate limiting first is usually more cost-effective than introducing a new component right away.
How cache penetration differs from cache avalanche and cache breakdown
The three have different trigger conditions: avalanche is a large number of keys expiring at the same time, breakdown is a single hot key becoming invalid, and penetration is the key not existing in the database, where a cache miss is normal. When assessing, first check the slow log to see whether origin queries repeat or are enumerable, rather than adding cache first.
- Avalanche: Many keys expire at once, and origin traffic rises across the board for a short period.
- Breakdown: A single hot key expires, and concurrency for one query spikes.
- Penetration: The key does not exist in the database, cache hit rate is low, and key types are scattered.
The mitigation approaches are not interchangeable: avalanche is handled with randomized expiration offsets and warm-up; breakdown is handled with mutually exclusive rebuild or logical expiration; penetration is handled with pre-validation, null-value caching, and set filtering. Keep the three separate, and avoid repeatedly increasing cache capacity in a penetration scenario.
What null-value caching alone can and cannot block
Null-value caching briefly stores the result of “queried and empty.” It fits scenarios with few key types where the same batch of IDs is probed repeatedly. A common practice is to set a short TTL for null values separately, with an experience range of 30 seconds to 5 minutes, to avoid long periods of reading nothing after data is backfilled.
It cannot block scans that use a new ID every time: the request keys keep changing, the cache never hits, and the database is still scanned. Also watch for null-value keys growing out of control, which can evict normal hot data. If empty-miss requests account for less than the typical range of 5%, parameter validation and rate limiting should be prioritized.
Should you add a Bloom filter? Check three things first
A Bloom filter fits scenarios where the key set is relatively stable, query volume is high, and a small false-positive rate is acceptable. If penetration is only caused by crawlers or abnormal parameters, format validation and caller rate limiting usually take effect faster.
- Quantify the ratio: Count requests that miss the cache and are also empty in the database. If the ratio is below the experience range of 5%, do validation and rate limiting first.
- Confirm the key source: Only keys from a fixed upstream or an enumerable list are suitable for pre-building a filter.
- Assess maintenance cost: The filter must be rebuilt as data changes; a common practice is an offline rebuild once a day or once an hour.
If you cannot answer one of the three, it is not advisable to add a Bloom filter first. It cannot delete a single element, so after data is deleted the key may still be judged as present; this kind of false positive should be explained to the business side in advance.
Three layers of interception: parameter validation, null-value caching, set filtering
Order them by “the farther from the database, the better”: the pre-validation layer handles obviously invalid parameters at low cost; the cache fallback layer records empty results and blocks repeated probes; the set filtering layer uses a Bloom filter to reject large numbers of impossible keys in advance. You do not need all three; add them layer by layer based on traffic and risk.
- Pre-validation layer: Validate ID length, format, and valid range, and return immediately for invalid requests; placing it at the gateway or API entry can block part of the scanning traffic.
- Cache fallback layer: Write empty results to cache as well, with a typical TTL range of 30 seconds to 5 minutes; null values should use a separate namespace from normal values to prevent misuse.
- Set filtering layer: Use a Bloom filter to judge whether a key may exist, with false-positive rate commonly kept within 1%; the cost is offline construction and periodic rebuilds.
An easily missed point is the upper limit on null-value keys. Without an eviction policy, abnormal traffic writing many non-existent keys can evict normal cache entries and actually increase database pressure.
Comparing three approaches: cost, timeline, and trade-offs
The three methods solve different problems and can be combined, but they have a priority order: rate limiting and blacklists address “who is scanning,” null-value caching addresses “repeatedly scanning the same batch of keys,” and a Bloom filter addresses “a new key every time.”
- Null-value caching: Lower development effort, commonly 1–2 days to launch; fits scenarios with few key types and high repetition; the trade-off is cache space usage when key types are many, and backfilled data must wait for the TTL to expire.
- Bloom filter: Requires build and rebuild processes, commonly 3–5 days to integrate; fits scenarios with an enumerable key set and high query volume; the trade-off is false positives and no support for deleting a single element.
- Rate limiting and blacklists: Apply rate limits at the gateway or entry by IP, account, or device, commonly 0.5–1 day to configure; fits scans with obvious source characteristics; the trade-off is reduced effectiveness with distributed sources or proxies.
In terms of cost, rate limiting and parameter validation require less investment, null-value caching is next, and a Bloom filter requires extra maintenance of build tasks and a rebuild window. In terms of effectiveness, when the key set is enumerable, the Bloom filter’s interception ratio is more stable; when the key set changes frequently, maintenance pressure rises noticeably.
Delivery experience: do the cheap things first, then add the filter
In one project, an externally exposed product query API had the constraint that keys came from an upstream product database and were enumerable, but upstream synchronization had delay, and empty-miss requests were noticeably above the experience range of 5%. The approach was to add parameter validation and 30-second null-value caching first, then build a Bloom filter with an offline task and switch using double buffering. The result was lower origin traffic, but clearing the filter directly during the rebuild window caused short-term penetration; the cost was monitoring upstream synchronization lag and keeping the old instance until the new one was available.
This experience shows that a filter is not better the earlier it is added. By typical range, validation and rate limiting first can solve most scanning traffic; when the key set is stable and the scale is large, then consider a Bloom filter and reserve a rebuild window.
When it applies and when it does not
Suitable cases for handling penetration: the API is externally exposed, query keys come from an enumerable upstream, and there is obvious abnormal parameter scanning; or the slow log already shows many repeated queries returning empty results. In such cases, pre-validation plus null-value caching usually reduces origin traffic.
Unsuitable cases: the query itself allows arbitrary strings (such as fuzzy search or open text queries), and a Bloom filter is basically unusable; the key set changes heavily every day and has no stable upstream, so maintenance cost may exceed the benefit; empty-miss requests are already low, and adding a filter only adds failure points and troubleshooting steps. The goal of penetration control is to block invalid requests up front, not to block all requests.
FAQ
Will null-value caching blow up cache space?
There is that risk, especially when there are many key types. A common practice is to set a shorter TTL separately for null values, with an experience range of 30 seconds to 5 minutes, and monitor the number of null-value keys; if it exceeds a threshold, shorten the TTL or add rate limiting.
What if a Bloom filter loses data after a restart?
An in-memory filter needs to be rebuilt after a restart. A common practice is to rebuild from the database or an offline task after startup, then release traffic; during the rebuild, use an old snapshot or let requests pass through to origin to avoid falsely blocking normal requests.
Can penetration and breakdown be handled together?
Yes, they can be handled in layers. Penetration relies on pre-validation and null-value caching, while breakdown relies on mutually exclusive rebuild or logical expiration. The two mechanisms act on different keys and usually do not conflict, but do not let a mutex serialize penetration traffic as well.
After adding a Bloom filter, it still hits the database. What should I check first?
First check whether the filter contains these keys, then verify that the rebuild window covers the time when new data was added. A common cause is that build data lags behind business writes, causing new keys to be falsely judged as non-existent.
If an API is already being repeatedly probed with non-existent keys, first measure the empty-miss ratio and key sources, then decide whether to add a filter; do not introduce a new component right away. Parameter validation and rate limiting usually cost less, and doing these two layers first can solve most scanning traffic; when the key set is stable and the scale is large, then consider a Bloom filter and reserve a rebuild window. The boundary is: for open text queries and scenarios where the key set changes at high frequency, prioritize rate limiting and degradation rather than a filter.
-
Ops changes campaign toggles weekly and asks devs for a release every time — should config move to a config center?
Date: Oct 14, 2026 Read: 6
-
List page 2 shows the last record from page 1 again—can frontend primary-key deduplication ship first?
Date: Oct 12, 2026 Read: 12
-
The same payment callback arrived three times and goods shipped twice—is a unique index alone enough?
Date: Oct 11, 2026 Read: 13
-
Hundreds of thousands of messages backed up in the queue, doubled the consumers and it still hasn't dropped — is the partition count the bottleneck?
Date: Oct 10, 2026 Read: 16
-
The ticket only has the user's phone number, but the logs show nothing but asterisks — how can on-call engineers still trace the issue?
Date: Oct 9, 2026 Read: 22




