Start by clarifying requirements: what granularity (ad, campaign, advertiser), time windows, cap values, and scale. Then design a two-tier system: a fast in-memory read path (e.g., Redis or local cache) for cap checks, and an asynchronous write path (e.g., Kafka + stream processing) for impression logging. Discuss data modeling, consistency trade-offs, and how to handle hot keys and failures.
Pro tip: Emphasize that the read path must be sub-10ms p99, so precompute and cache counts per user per entity per window; use approximate counting (e.g., Redis HyperLogLog) if exact counts aren't critical, and consider local caching with eventual consistency to reduce latency.
Ask about the number of users, ads, campaigns, advertisers, daily impressions, and the required accuracy of cap enforcement. Determine if caps are per user per ad/campaign/advertiser and the time windows (e.g., 1 hour, 1 day).
Choose a key structure like user_id:entity_type:entity_id:window_start to store counts. Use a fast in-memory store (Redis) for read path, and a durable store (Cassandra, Bigtable) for write path and analytics.
At serve time, check counts from Redis (or local cache) with a single multi-get. Use pipelining, connection pooling, and possibly local caching with short TTL to achieve sub-10ms p99. Handle cache misses by falling back to durable store or defaulting to allow.
Log impressions asynchronously to a distributed queue (Kafka). Consumers aggregate counts and update Redis and durable store. Use windowing (e.g., sliding windows) and batch updates to reduce load. Ensure idempotency to avoid double counting.
Discuss consistency vs. latency: eventual consistency may allow slight over-serving. Plan for Redis failures (fallback to local cache or allow all), hot keys (sharding by user), and data retention (TTL on keys).
AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.