To detect hot keys in a high-rate stream within a sliding window, use a time-bucketed counting approach with approximate counters (Count-Min Sketch) per key to save memory and a fixed number of recent buckets to implement a sliding window. Below is a simple in-process prototype using exact bucketed counts (easy to replace with sketches). After code I explain scaling and false-positive reduction.python
import time
from collections import defaultdict, deque
class HotKeyDetector:
def __init__(self, window_secs=60, bucket_secs=1, threshold=1000):
self.window_secs = window_secs
self.bucket_secs = bucket_secs
self.buckets = int(window_secs // bucket_secs)
self.threshold = threshold
# deque of dicts, each dict: key -> count for that bucket
self.ring = deque([defaultdict(int) for _ in range(self.buckets)], maxlen=self.buckets)
self.bucket_start = int(time.time() // bucket_secs)
def _rotate(self):
now_bucket = int(time.time() // self.bucket_secs)
while self.bucket_start < now_bucket:
self.ring.append(defaultdict(int)) # drop oldest, add new empty bucket
self.bucket_start += 1
def ingest(self, key, timestamp=None):
if timestamp is None:
timestamp = time.time()
# assume timestamps non-decreasing or near-real-time; else compute appropriate bucket index
self._rotate()
idx = -1 # newest bucket
self.ring[idx][key] += 1
def is_hot(self, key):
# sum counts across buckets
total = 0
for b in self.ring:
total += b.get(key, 0)
if total > self.threshold:
return True
return False
def top_hot_keys(self):
agg = defaultdict(int)
for b in self.ring:
for k,v in b.items():
agg[k] += v
return [k for k,v in agg.items() if v > self.threshold]
Key points:- Uses fixed-size ring of 1s buckets to implement sliding window efficiently (O(1) per ingest if using newest bucket).- For memory at scale replace per-bucket dicts with Count-Min Sketch instances to get O(1) memory per bucket with controlled error.Scaling across partitions (FAANG-scale):- Partition stream by key hash into N partitions (Kafka topic with partitioning). Each partition runs an independent detector for keys assigned.- Maintain a lightweight aggregator / coordinator that receives hot-key signals from partitions and merges counts or applies voting (e.g., require >k partitions reporting the same key or combine sketches) to avoid partition-local spikes being mistaken as global hot keys.- Use hierarchical aggregation: local partition detectors → regional aggregators (merge CMS) → global detector.Reducing false positives:- Use Count-Min Sketch with multiple hash functions and conservative update or median-of-estimates to lower overestimation.- Apply a significance filter: require sustained exceedance across multiple consecutive windows or rate-of-change checks.- Apply backpressure/validation: sample actual requests for candidate hot keys and compute exact counts for confirmation before triggering heavy mitigation (e.g., throttling).- Tune sketch size and hashing to meet target error rate based on expected cardinality.Complexity:- Per-event: O(1) amortized (rotate occasionally), memory O(buckets * per-bucket-state). With CMS memory becomes O(buckets * width).Edge cases:- Late or out-of-order timestamps — compute bucket index by timestamp and accept bounded lateness or use watermarking.- Very high cardinality — use CMS and sharding.