A read-heavy service caches product data in Redis with a 60s TTL. A single hot product gets 50k req/s. At the TTL boundary, latency spikes and the primary DB briefly saturates every minute. Which mitigation BOTH prevents the DB dogpile AND avoids serving stale data for the full extra TTL?
- A. Increase the TTL to 600s so expiries happen less often
- B. Use a per-key mutex/lock so only one request recomputes on miss while others wait or serve the last value ✓
- C. Switch the cache eviction policy from LRU to LFU
- D. Add a random 0-60s jitter to each key's TTL at write time
Correct answer: B. A recompute lock (single-flight) collapses the stampede so only one request hits the DB while others wait, without extending staleness like a longer TTL would.
A Kafka consumer reads a record, processes it (charges a card), then commits its offset. It crashes AFTER the side effect but BEFORE the offset commit. On restart, what happens and what is the correct fix?
- A. The record is skipped because Kafka auto-advances offsets on crash; enable auto-commit
- B. The record is reprocessed (double charge); make processing idempotent using a dedup key so replays are safe ✓
- C. Kafka's exactly-once transaction on the consumer poll guarantees no reprocessing; no fix needed
- D. The consumer group rebalance drops the partition permanently; increase session.timeout.ms
Correct answer: B. With at-least-once semantics an uncommitted offset causes redelivery, so the side effect must be made idempotent (e.g., a unique transaction key) to tolerate replays.
Client A acquires a distributed lock in Redis (TTL 10s), then stalls for 15s on a stop-the-world GC pause. The lock expires and Client B acquires it and writes to shared storage. A wakes up believing it still holds the lock and also writes. Which mechanism prevents the resulting corruption?
- A. A longer lock TTL of 60s so GC pauses fit inside it
- B. Fencing tokens: each lock grant carries a monotonically increasing number that the storage layer rejects if lower than the last accepted ✓
- C. Redlock across five Redis nodes to increase lock durability
- D. Setting the Redis lock with NX and a random value checked at release time
Correct answer: B. Only a fencing token enforced at the resource makes the stale writer's request rejected, since any time-based TTL can still be violated by an arbitrarily long pause.
A payments table is sharded by shard = user_id % N. Analytics runs SELECT SUM(amount) WHERE merchant_id = ? for a merchant whose transactions are spread across all shards. What is the fundamental problem and the standard remedy?
- A. The query is fine; each shard has an index on merchant_id so it is a single-shard lookup
- B. It is a cross-shard scatter-gather; maintain a secondary index or read model keyed by merchant_id (e.g., via CQRS/materialized view) ✓
- C. Rehash the whole cluster using consistent hashing to co-locate the merchant
- D. Wrap the aggregate in a 2PC transaction so all shards return a consistent sum
Correct answer: B. The partition key is user_id, so a merchant query fans out to every shard; the fix is a separate index/read model partitioned by merchant_id, not a distributed transaction.
In Raft, a leader receives a client write and replicates the entry to a minority of followers before crashing. A new leader is elected from a node that never saw that entry. What is guaranteed about the un-replicated entry?
- A. It is guaranteed committed because the old leader acknowledged writing it locally
- B. It may be silently overwritten because it was never committed (never on a majority) and was not acked to the client ✓
- C. It is automatically recovered from the old leader's disk during the next election
- D. Raft blocks all new writes until the old leader rejoins and re-sends it
Correct answer: B. An entry is only committed once stored on a quorum; an entry present on only a minority can be overwritten by a new leader, which is why it was never acknowledged to the client.
Consider this Java snippet run by two threads sharing a long counter field `count` (no volatile, no lock): `count++;`. Beyond the obvious lost-update race, why is `count` specifically dangerous on a 32-bit JVM even for a single read?
- A. Longs are always atomic in the JVM so there is no additional risk
- B. Non-volatile 64-bit long/double reads and writes may be split into two 32-bit operations, so a reader can observe a torn value ✓
- C. The JIT compiler promotes count to a register making it thread-local automatically
- D. Garbage collection can relocate the long and corrupt its bytes
Correct answer: B. The JLS permits non-volatile long/double stores to be performed as two 32-bit writes, so a concurrent reader can see a word-tearing (half-updated) value.
You add a node to a load-balancing tier that uses plain `hash(key) % N` for routing to caches. After N goes from 8 to 9, what fraction of keys remap, and what does consistent hashing with virtual nodes fix?
- A. About 1/9 remap; consistent hashing mainly reduces memory usage
- B. Nearly all keys remap because the modulus changed; consistent hashing limits remapping to ~1/N of keys and virtual nodes smooth load distribution ✓
- C. Exactly the keys on the new node remap; consistent hashing eliminates all remapping
- D. No keys remap because hashing is deterministic; virtual nodes only help with replication
Correct answer: B. Changing the modulus reshuffles almost every key, whereas consistent hashing only moves keys near the added node (~1/N) and virtual nodes even out skew.
A service is on a G1 GC JVM with a 32GB heap and users report periodic multi-second stalls correlated with rising old-gen occupancy and eventual Full GCs. Heap dumps show a growing HashMap used as an in-process cache with no eviction. What is the most accurate diagnosis?
- A. G1 is misconfigured; switch to the throughput (Parallel) collector to remove pauses
- B. A memory leak: the unbounded cache retains objects, defeating generational collection until a Full GC compacts the whole heap ✓
- C. The pauses are normal young-gen collections; increase Xmn to fix them
- D. Network backpressure is stalling threads; the GC correlation is coincidental
Correct answer: B. An unbounded map holds strong references so objects are never reclaimed, old-gen fills, and G1 falls back to costly Full GCs — a classic leak, not a collector-tuning issue.
Two microservices, Orders and Inventory, must both succeed or both roll back when placing an order. The team wants high availability and avoids blocking. Between an orchestrated Saga and 2PC, which statement correctly captures the trade-off?
- A. 2PC is preferred because Sagas cannot roll back once a step commits
- B. A Saga uses compensating transactions and stays available under partition, but sacrifices isolation, allowing intermediate states other reads can observe ✓
- C. 2PC and Saga both guarantee full ACID isolation across services
- D. A Saga guarantees linearizability across both services without extra work
Correct answer: B. Sagas trade global isolation for availability by using compensations per step, so intermediate uncommitted-looking states are visible, unlike blocking 2PC.
You must ship a breaking change to a shared Protobuf/JSON contract consumed by dozens of independently deployed services you cannot upgrade atomically. Which rollout strategy is safe?
- A. Reuse the existing field number but change its type, then deploy producer and all consumers simultaneously
- B. Add the new field as optional alongside the old, dual-write both, migrate consumers, then remove the old field in a later release ✓
- C. Delete the old field immediately and rely on consumers to ignore unknown fields
- D. Bump the top-level version and force every consumer to redeploy within the same maintenance window
Correct answer: B. Backward/forward-compatible evolution requires additive changes and an expand-migrate-contract sequence so old and new consumers coexist during rollout.