41. Burst at a fixed window boundary
A fixed-window limiter allows 100 requests per calendar minute per client. What is the most requests a client can get accepted within a 2-second span?
- A.100
- B.101
- C.200
- D.6,000
Show answer
Answer: C. 200
The client can send 100 requests at 12:00:59 and another 100 at 12:01:00, because the counter resets at the boundary. That is double the intended rate in two seconds. Sliding window logs, sliding window counters or a token bucket smooth this out.
42. Pool exhausted during payments
Checkout opens a transaction, inserts the order, calls the payment provider over HTTP (2 to 5 seconds), then commits. With a pool of 20 connections, checkout times out at peak. What is the best redesign?
- A.Raise the pool size to 500 connections and set the database max_connections high enough to cover every single app instance
- B.Use READ UNCOMMITTED so the transaction finishes faster
- C.Wait forever for a free connection instead of timing out
- D.Commit the order as pending first, call the provider with an idempotency key, then update it in a new short transaction
Show answer
Answer: D. Commit the order as pending first, call the provider with an idempotency key, then update it in a new short transaction
Each checkout holds a connection, and row locks, for the whole HTTP call, so 20 slow payments block everyone. Short transactions around local work, plus a pending state and idempotency key, keep the pool free and make retries safe. A reconciliation job can finish orders left pending after a crash.
43. One company sees another's invoices
In a multi-tenant SaaS, a new report query forgot `WHERE tenant_id = ?`. Company A saw Company B's invoices. Which approach prevents this whole class of bug?
- A.Ask reviewers to look for tenant_id in PRs
- B.Give each tenant a different colour theme
- C.Hide each tenant's report URLs from others
- D.Enforce tenant scope centrally, e.g. with RLS
Show answer
Answer: D. Enforce tenant scope centrally, e.g. with RLS
Relying on every developer to remember a filter will fail eventually. Enforce scoping in one place: a repository layer that always adds the tenant, PostgreSQL row-level security driven by a session setting, or separate schemas or databases. Add tests that try to read across tenants.
44. Keeping OAuth tokens out of the browser
A security review says a single-page app should not hold OAuth refresh tokens in JavaScript at all. Which pattern does that?
- A.A backend-for-frontend holds tokens and gives the SPA a session cookie
- B.Store the refresh token in sessionStorage instead
- C.Encrypt the refresh token with a key in the JavaScript bundle
- D.Use the implicit flow so no refresh token is issued
Show answer
Answer: A. A backend-for-frontend holds tokens and gives the SPA a session cookie
In the BFF pattern, a small server-side component runs the OAuth flow, keeps the tokens and calls APIs for the SPA. The browser only has an HttpOnly, Secure, SameSite session cookie, so an XSS bug cannot read tokens. A key inside the bundle is visible to anyone.
45. CROSSSLOT errors after moving to Cluster
After moving to Redis Cluster, MGET cart:42 wishlist:42 fails with CROSSSLOT. What is the fix if both must be read together?
- A.Increase the number of hash slots
- B.Run the same command on a replica
- C.Use hash tags, like {user:42}, in both keys
- D.Rename both keys to use only digits
Show answer
Answer: C. Use hash tags, like {user:42}, in both keys
Redis Cluster spreads keys over 16,384 slots by hashing the key name, and multi-key commands only work when all keys are in the same slot. Only the part inside {} is hashed, so keys with the same tag land together. Do not put everything under one tag, or one node gets all the load.
46. One Redis key gets half of all traffic
During a cricket final, one key holding the live score gets 300,000 reads a second, and the Redis node holding it is maxed out while others idle. What helps?
- A.Move the key to a node with more disk
- B.A brief local cache per app, or key copies
- C.Give the key a longer name to spread it
- D.Delete the key straight after every read
Show answer
Answer: B. A brief local cache per app, or key copies
A hot key always maps to one node, so adding nodes does not spread its load. A short in-process cache of a second or two in each app server removes most reads, and copies such as score:{1..10} read at random spread the rest. Read replicas can also help.
47. Keeping wallet balances only in Redis
A team wants to keep wallet balances only in Redis, because it is fast. What is the main risk?
- A.Async replication and persistence gaps can lose data
- B.Redis cannot store decimal numbers in string values
- C.Redis allows only 1,000 keys in each logical database
- D.Redis does not support atomic integer increments
Show answer
Answer: A. Async replication and persistence gaps can lose data
Redis replication is asynchronous and persistence has loss windows, so a failover can lose acknowledged writes, and memory limits cap size. For money, keep the system of record in a durable, transactional database, and use Redis for caching, rate limits or fast counters you can rebuild.
48. A join across two services' databases
With database-per-service, the orders service needs customer names for its order list, but customers live in another service's database. What is a common solution?
- A.Query the other service's tables directly
- B.Merge both services under one shared database user
- C.Ask the frontend to join the data by hand
- D.Keep a local copy of customer names updated by events
Show answer
Answer: D. Keep a local copy of customer names updated by events
Reading another service's tables couples you to its schema. Instead, call its API (with batching) or keep a small local projection of the fields you need, updated from its events. The projection is eventually consistent, which is usually fine for display names.
49. Adding a cache server without reshuffling
Cache keys are assigned with server = hash(key) % N. Going from 4 to 5 servers moves most keys and causes a flood of cache misses. What reduces this?
- A.A larger modulus such as % 1000
- B.Sorting keys before assignment
- C.Consistent hashing on a ring
- D.Using MD5 instead of the current hash
Show answer
Answer: C. Consistent hashing on a ring
With % N, changing N changes the bucket for most keys. Consistent hashing places servers and keys on a ring, so adding a server only takes over keys from its neighbour, about 1/N of the total. Virtual nodes smooth out the load.
50. What a Bloom filter can promise
A sign-up page checks a Bloom filter of taken usernames before querying the database. What can the filter say for sure?
- A."Taken" is reliable; "not taken" can sometimes be wrong
- B.Both answers are always exact, just faster than a DB
- C."Definitely not taken" is reliable; "maybe taken" can be wrong
- D.It can list every taken username on request
Show answer
Answer: C. "Definitely not taken" is reliable; "maybe taken" can be wrong
A Bloom filter sets several bits per item. If any bit for a name is unset, it was never added. If all are set, other names may have set them, so you confirm with the database. It uses far less memory than a set, and plain Bloom filters do not support deletes.
51. Stopping double charges on retries
A mobile app retries a UPI payment request when the network drops, and some customers are charged twice. What server-side fix uses a key-value store?
- A.Store each idempotency key with its result and replay it on repeats
- B.Hash the amount and reject any repeated amounts
- C.Keep a Set of customer IDs who paid today and block them
- D.Retry the bank call until it returns a success
Show answer
Answer: A. Store each idempotency key with its result and replay it on repeats
The client sends a unique idempotency key per payment attempt. The server records key → outcome (with a TTL); a retry with the same key gets the stored result instead of a new charge. The check-and-insert must be atomic, for example SET NX in Redis or a unique constraint.
52. One tenant floods the queue
A SaaS uses one job queue for all tenants. One customer uploads 2 million rows, and every other tenant's small jobs wait hours. What is a good fix?
- A.Isolate tenants so each gets a fair share of workers
- B.Add a single priority level for all small jobs
- C.Raise visibility timeout so big jobs finish first
- D.Move the large tenant's data to a bigger database
Show answer
Answer: A. Isolate tenants so each gets a fair share of workers
A shared FIFO-style queue lets one heavy tenant create head-of-line delay for everyone. Fair scheduling, such as per-tenant queues served round-robin, per-tenant concurrency limits, or SQS FIFO groups per tenant, keeps others moving. A generic priority flag does not stop the flood from filling the lanes.
53. One hot RabbitMQ queue
One RabbitMQ queue handles 40,000 messages per second and tops out, even though the cluster has idle nodes and CPU. Why, and what helps?
- A.The exchange is the bottleneck; switch to fanout
- B.A queue lives on one node and core; split it across queues
- C.Prefetch is too low; set it to unlimited
- D.The disk is too slow; turn off persistence
Show answer
Answer: B. A queue lives on one node and core; split it across queues
Each RabbitMQ queue is handled by a single Erlang process on one node, so one queue has a throughput ceiling no matter how big the cluster is. Spread load across several queues, for example with the consistent-hash exchange or sharding plugin, or use streams or super streams. Turning off persistence trades away safety.
54. A fixed concurrency limit
A service caps concurrent requests to its database at a fixed 200. On some days the database copes with 400; on others it slows down at 120. What approach handles both?
- A.A higher fixed limit of 1,000 requests
- B.Removing the limit and relying on timeouts
- C.A fixed limit of 120 for every single day
- D.A limit that adapts to observed latency
Show answer
Answer: D. A limit that adapts to observed latency
Adaptive concurrency limits (for example TCP-style AIMD or gradient algorithms, as in Netflix's concurrency-limits or Envoy) increase the limit while latency stays low and cut it when latency rises. They follow real capacity instead of a guess. Fixed limits either waste capacity or allow overload.
55. Fan-out for a celebrity account
A feed uses fan-out on write. A cricketer with 40 million followers posts, and feed writes back up for an hour. What design is common?
- A.Fan out to all 40 million followers in one transaction
- B.Fan out for normal users; merge celebrity posts at read time
- C.Stop showing celebrity posts in feeds
- D.Give the celebrity a separate database server
Show answer
Answer: B. Fan out for normal users; merge celebrity posts at read time
Hybrid feeds push posts from normal accounts to followers' feeds, but for accounts with huge follower counts they skip fan-out and fetch their recent posts when a follower opens the feed, then merge. This caps write amplification while keeping reads fast for most users.
56. Offline edits that must merge
A notes app lets users edit the same list offline on two phones and must merge changes without losing either side. What fits best?
- A.Last-write-wins on the whole document
- B.Locking the note on the first device to open it
- C.Rejecting the second phone's changes on sync
- D.A CRDT that merges concurrent edits deterministically
Show answer
Answer: D. A CRDT that merges concurrent edits deterministically
CRDTs (conflict-free replicated data types) are designed so replicas can change independently and always converge to the same state when merged, without coordination. Whole-document LWW drops one user's work, and locks do not work while offline. Libraries like Yjs and Automerge implement this.
57. Designing a wallet ledger
A payments team stores each wallet's balance as one mutable number. Audits cannot explain mismatches. What design is standard for money?
- A.An append-only double-entry ledger of postings
- B.A balance column updated with UPDATE statements
- C.A nightly batch that recalculates balances from logs
- D.A cache of balances refreshed every minute
Show answer
Answer: A. An append-only double-entry ledger of postings
In a double-entry ledger every transfer is recorded as immutable entries that debit one account and credit another, summing to zero. Balances are derived (and can be cached) from the entries, so every change is traceable and mistakes are fixed with new reversing entries, not edits.
58. Passing a class into a Task
In Swift 6 language mode, sending a mutable non-Sendable class instance from the main actor into a detached Task gives an error. Why?
- A.Both sides could mutate it at once, a data race
- B.Classes cannot be used inside any task at all
- C.Detached tasks only accept String values
- D.The class must first be marked with @objc
Show answer
Answer: A. Both sides could mutate it at once, a data race
Values crossing isolation boundaries must be Sendable, or proven safe to transfer. A mutable class shared by two concurrent contexts could race. Fixes include making it a struct, an actor, immutable and final Sendable, or not sharing it after sending.
59. Scaling stopped at a hidden limit
During a big sale, auto scaling stopped adding instances at 64 vCPUs although max size allowed more. What most likely happened, and how do you prevent it?
- A.Auto scaling is limited to 64 vCPUs for all users
- B.An account vCPU quota was hit; raise quotas ahead
- C.The load balancer refused more targets
- D.The AMI was too large to launch more copies
Show answer
Answer: B. An account vCPU quota was hit; raise quotas ahead
Accounts have service quotas, such as on-demand vCPUs per instance family per region. When reached, launches fail even if scaling allows more. Review quotas and request increases before planned peaks, and alarm on usage.
60. Two leaders after a GC pause
A worker holding a leader lease in etcd paused for 40 s in garbage collection. Its lease expired, a new leader was elected, and then the old worker woke up and wrote to storage, corrupting data. What prevents this?
- A.Make the lease longer than any possible pause
- B.Use fencing tokens: each new lease gets a higher number and storage rejects writes with an older token
- C.Check the lease once before starting the job
- D.Run the leader on a bigger machine
Show answer
Answer: B. Use fencing tokens: each new lease gets a higher number and storage rejects writes with an older token
A process cannot reliably know it has been paused, so checking the lease before writing still leaves a race. A fencing token, such as the etcd revision of the lease key, increases with every new leader, and the storage layer rejects writes carrying an older token. No lease length can rule out every pause.