{"version":"wmCNbbIjgRnQ","topics":["Interviews","Patterns","Case studies","Sharding","Real-time","Edge","Postgres","SQL","Redis","Queues","Streams","Consistency","Concurrency"],"cards":[{"id":"how-should-you-open-requirements-in-a-staff-level-design-intervi","topics":["Interviews"],"questionHtml":"How should you open requirements in a staff-⁠level design interview?","answerHtml":"<p>Lead with proposals, not questions.</p><ul><li>State your assumptions explicitly, so the interviewer can course-⁠correct.</li><li>An open “What are the non-⁠functional requirements?” is a <strong>negative signal</strong> at staff level.</li></ul>"},{"id":"which-clarifying-questions-are-worth-asking-in-a-design-intervie","topics":["Interviews"],"questionHtml":"Which clarifying questions are worth asking in a design interview?","answerHtml":"<p>Only those whose answer changes the design; decide everything else and move on.</p><ul><li>For example: the peak-⁠to-⁠average ratio, or how fresh the data must be.</li><li>Keep it to <strong>about 5 minutes</strong>: over-⁠clarifying reads as stalling.</li></ul>"},{"id":"sketch-a-waiting-room-that-admits-users-to-a-ticket-sale-in-batc","topics":["Patterns","Case studies","Redis"],"questionHtml":"Sketch a waiting room that admits users to a ticket sale in batches.","answerHtml":"<p>An unbounded FIFO queue of waiting users plus a pool of admission permits, both in Redis.</p><ol><li>Every so often, while permits are left, admit users from the front of the queue.</li><li>Each admitted user holds a permit while booking.</li><li>When the booking completes or the admission’s TTL expires, the permit goes back to the pool for the next batch.</li></ol>"},{"id":"how-do-you-route-requests-to-stateful-servers-such-as-websocket","topics":["Patterns","Sharding","Real-time"],"questionHtml":"How do you route requests to stateful servers, such as WebSocket servers?","answerHtml":"<p>Consistent hashing: hash a stable id, such as the client’s, onto the ring of servers, so a client keeps reaching the server that holds its state.</p><ul><li>For example, clients to the WebSocket servers that hold their connections.</li><li>When a server joins or leaves, only the clients on its arc of the ring move.</li></ul>"},{"id":"what-are-the-main-levers-for-scaling-a-read-heavy-system","topics":["Patterns"],"questionHtml":"What are the main levers for scaling a read-⁠heavy system?","answerHtml":"<p>Index, scale out, cache.</p><ul><li>Database indexing.</li><li>Horizontal scaling: more replicas or servers, spread across availability zones.</li><li>Caches: local (in-⁠process), application-⁠level and CDN.</li></ul>"},{"id":"what-are-the-options-for-pushing-live-updates-from-a-server-to-a","topics":["Real-time","Patterns"],"questionHtml":"What are the options for pushing live updates from a server to a client?","answerHtml":"<p>Polling, long polling, SSE and WebSockets, from simplest up; WebRTC for peer to peer.</p><ul><li>Polling: the client asks again on a timer.</li><li>Long polling: the server holds each request open until it has news.</li><li>SSE: one long-⁠lived HTTP response that the server keeps pushing events down.</li><li>WebSockets: one persistent, two-⁠way connection.</li></ul>"},{"id":"what-do-you-need-to-send-push-notifications-to-a-mobile-app","topics":["Patterns","Real-time"],"questionHtml":"What do you need to send push notifications to a mobile app?","answerHtml":"<p>A device token per install: Apple’s APNs and Google’s FCM address the app on each device by its token.</p><ul><li>The app obtains its token and sends it to your backend.</li><li>Store the tokens with the user, for example in the user profile.</li></ul>"},{"id":"where-should-a-fan-out-such-as-a-campaign-to-all-users-happen","topics":["Patterns"],"questionHtml":"Where should a fan-⁠out, such as a campaign to all users, happen?","answerHtml":"<p>Off the critical path, whenever possible.</p><ul><li>Accept the request, then expand campaign → users asynchronously.</li><li>The request stays fast however many users the fan-⁠out reaches.</li></ul>"},{"id":"when-would-you-use-orchestration-rather-than-choreography-betwee","topics":["Patterns"],"questionHtml":"When would you use orchestration rather than choreography between services?","answerHtml":"<p>Orchestration for complex flows: a workflow execution engine such as Temporal, Camunda or AWS Step Functions drives each step.</p><ul><li>Choreography: services react to events, published for example through SNS, with no central coordinator.</li></ul>"},{"id":"how-would-a-url-shortener-like-bitly-generate-its-short-codes","topics":["Case studies"],"questionHtml":"How would a URL shortener like Bitly generate its short codes?","answerHtml":"<p>A global sequence in Postgres, with each id encoded in <strong>Base62</strong> (0–⁠9, a–⁠z, A–⁠Z).</p><ul><li>For writes in several regions, hand out blocks of ids from the sequence.</li></ul>"},{"id":"how-would-you-scale-the-read-path-of-a-url-shortener","topics":["Case studies","Edge"],"questionHtml":"How would you scale the read path of a URL shortener?","answerHtml":"<p>Separate it from the write path and scale it on its own.</p><ul><li>Cache redirects in a CDN and in the app, but <strong>don’t cache failures</strong>.</li><li>Potentially, run the read path in several regions.</li></ul>"},{"id":"how-do-you-keep-an-auction-s-highest-bid-correct-under-concurren","topics":["Case studies","Concurrency"],"questionHtml":"How do you keep an auction’s highest bid correct under concurrent bids?","answerHtml":"<p>Use an ACID database and keep the <strong>current max bid on the auction row</strong>.</p><ul><li>Each bid locks that one row, checks it beats the max and updates it, in one transaction.</li><li>So no distributed locking is needed.</li></ul>"},{"id":"how-would-an-online-auction-push-each-new-bid-to-everyone-watchi","topics":["Case studies","Real-time"],"questionHtml":"How would an online auction push each new bid to everyone watching?","answerHtml":"<p>Server-⁠Sent Events (SSE) for bid updates.</p><ul><li>Each watcher holds one long-⁠lived HTTP response, and the server pushes every new bid down it.</li></ul>"},{"id":"how-would-an-online-auction-survive-a-spike-in-bids-without-losi","topics":["Case studies","Queues"],"questionHtml":"How would an online auction survive a spike in bids without losing any?","answerHtml":"<p>Put a message queue in front of bid processing.</p><ul><li>The queue absorbs the spike: bids wait in it until the workers catch up.</li><li>So no bid is lost when traffic surges.</li></ul>"},{"id":"how-do-you-stop-bulk-notifications-from-delaying-urgent-ones","topics":["Case studies","Queues"],"questionHtml":"How do you stop bulk notifications from delaying urgent ones?","answerHtml":"<p>Isolate the priority tiers from end to end.</p><ul><li>Separate queues and worker pools for each tier.</li><li>Separate third-⁠party provider accounts for high and low priority, so the tiers don’t share quotas.</li></ul>"},{"id":"sketch-a-distributed-rate-limiter-for-a-public-api","topics":["Case studies","Redis"],"questionHtml":"Sketch a distributed rate limiter for a public API.","answerHtml":"<p>A token bucket per client, kept in Redis as two values: <code>tokens</code> and <code>last_refill</code>.</p><ul><li>Each request runs a Lua script that refills the bucket for the time elapsed, then takes a token or rejects the request.</li><li>Redis runs the script atomically, so two requests can’t both take the last token.</li></ul>"},{"id":"how-does-consistent-hashing-place-nodes-on-the-ring","topics":["Sharding"],"questionHtml":"How does consistent hashing place nodes on the ring?","answerHtml":"<p>Each node sits at <code>hash(node_id)</code>, for example <code>hash(&quot;10.0.0.5:6379&quot;)</code>, on a ring spanning the hash’s range: 2^32 positions for a 32-⁠bit hash.</p><ul><li>The input is the list of nodes, kept strongly consistent, for example in etcd or ZooKeeper.</li></ul>"},{"id":"why-add-virtual-nodes-to-a-consistent-hashing-ring-and-how-many","topics":["Sharding"],"questionHtml":"Why add virtual nodes to a consistent-⁠hashing ring, and how many?","answerHtml":"<p>To space the nodes out more evenly: each node is placed many times, at <code>hash(node_A#001)</code>, <code>hash(node_A#002)</code> and so on.</p><ul><li>Cassandra defaults to <strong>16 virtual nodes per node</strong> (since 4.0; it was 256 before).</li></ul>"},{"id":"walk-through-how-a-client-finds-the-node-for-a-key-on-a-hash-rin","topics":["Sharding"],"questionHtml":"Walk through how a client finds the node for a key on a hash ring.","answerHtml":"<p>Hash the key with the same function, then binary-⁠search the sorted node positions for the <strong>first node at or after it</strong>, wrapping round to the start.</p><ul><li>Example: nodes <code>a=3, b=55, c=99</code> and <code>hash(value) = 42</code> give node <code>b</code>.</li><li>Clients precompute the positions from the node list and update them only when the list changes.</li></ul>"},{"id":"how-do-you-move-data-when-nodes-join-a-consistent-hashing-ring","topics":["Sharding"],"questionHtml":"How do you move data when nodes join a consistent-⁠hashing ring?","answerHtml":"<p>It depends on what the nodes hold, and approaches differ.</p><ul><li>Caches: don’t bother; let the new nodes fill up slowly.</li><li>Data stores: dual writes plus an asynchronous data transfer for a while, then flip over to the new layout.</li></ul>"},{"id":"what-is-a-hot-key-and-how-do-you-spread-its-load-across-shards","topics":["Sharding"],"questionHtml":"What is a hot key, and how do you spread its load across shards?","answerHtml":"<p>A key so popular, such as a viral post or a Taylor Swift event, that the one shard it maps to is overloaded, even with consistent hashing.</p><ul><li>Fix: split it into deterministic suffixes, <code>swift#01</code> to <code>swift#09</code>, which the mapping <code>f(id) = node</code> spreads across shards.</li><li>Each write picks a suffix at random: <code>f('swift#01') = node_a</code>, <code>f('swift#02') = node_d</code>.</li></ul>"},{"id":"what-does-splitting-a-hot-key-cost-and-what-happens-when-it-cool","topics":["Sharding"],"questionHtml":"What does splitting a hot key cost, and what happens when it cools?","answerHtml":"<p>Reads get more expensive: they must read every suffix, <code>#01</code> to <code>#09</code>, and aggregate the results.</p><ul><li>Once the key is no longer hot, its data is usually left scattered, not migrated back.</li></ul>"},{"id":"how-do-servers-know-which-hot-keys-are-split-and-into-how-many","topics":["Sharding"],"questionHtml":"How do servers know which hot keys are split, and into how many?","answerHtml":"<p>From shared config in etcd or ZooKeeper, for example <code>swift: {version: 1, buckets: 9}</code>.</p><ul><li>Servers fetch the config and cache it.</li><li>On every read and write they check the local copy and, if the key is listed, map it to its buckets.</li></ul>"},{"id":"how-do-server-sent-events-work-on-the-browser-side","topics":["Real-time"],"questionHtml":"How do Server-⁠Sent Events work on the browser side?","answerHtml":"<p><code>EventSource</code> opens one long-⁠lived HTTP GET to a stream endpoint; the server keeps the response open and pushes events down it.</p><pre><code>const s = new EventSource(\n  '/videos/123/comments/stream');\ns.onmessage = (e) =&gt;\n  renderComment(JSON.parse(e.data));\n</code></pre>"},{"id":"where-should-traffic-be-encrypted-with-tls-in-a-modern-system","topics":["Edge","Interviews"],"questionHtml":"Where should traffic be encrypted with TLS in a modern system?","answerHtml":"<p>The expected answer today is <strong>TLS everywhere</strong>, re-⁠encrypted at each hop:</p><ul><li>Client → edge: CDN, load balancer or gateway.</li><li>Load balancer → services.</li><li>Service → service, and service → database.</li></ul>"},{"id":"why-terminate-client-tls-at-the-edge-or-the-load-balancer","topics":["Edge"],"questionHtml":"Why terminate client TLS at the edge or the load balancer?","answerHtml":"<p>Handshakes are the costly part, and clients open huge numbers of short connections.</p><ul><li>The edge or load balancer absorbs all those handshakes.</li><li>Behind it, connections to services are pooled and long-⁠lived: few handshakes, and encrypting the data itself is cheap.</li></ul>"},{"id":"which-aws-load-balancers-terminate-tls-and-which-can-pass-it-thr","topics":["Edge"],"questionHtml":"Which AWS load balancers terminate TLS, and which can pass it through?","answerHtml":"<p>An <strong>ALB always terminates</strong> TLS; an NLB can do either.</p><ul><li>ALB (layer 7): HTTP and HTTPS listeners only, so HTTPS is decrypted at the ALB.</li><li>NLB (layer 4): a TLS listener terminates; a TCP listener passes the encrypted traffic through.</li><li>ELB is the name of the whole family: ALB, NLB, Gateway and Classic.</li></ul>"},{"id":"what-does-a-waf-do-and-how-much-should-you-say-about-it-in-an-in","topics":["Edge","Interviews"],"questionHtml":"What does a WAF do, and how much should you say about it in an interview?","answerHtml":"<p>A web application firewall filters HTTP requests at the edge.</p><ul><li>It blocks SQL injection, XSS, bad IPs and bot signatures, and enforces IP rate limits.</li><li>In an interview a one-⁠liner is enough: “Use a WAF as the first line of defence against common attacks and bot traffic.”</li></ul>"},{"id":"when-is-an-api-gateway-worth-it-over-a-plain-load-balancer","topics":["Edge"],"questionHtml":"When is an API gateway worth it over a plain load balancer?","answerHtml":"<p>A load balancer moves traffic; <strong>a gateway enforces policy</strong>. Use one when:</p><ul><li>The API is a product: API keys, usage plans, quotas, metering.</li><li>Many services sit behind one public entry point: authentication, rate limits, request validation.</li><li>The backend is serverless: Lambda behind HTTP (though an ALB can invoke Lambda too).</li></ul>"},{"id":"when-should-you-skip-the-api-gateway-and-use-only-a-load-balance","topics":["Edge"],"questionHtml":"When should you skip the API gateway and use only a load balancer?","answerHtml":"<p>When there’s no policy to enforce: load balancer traffic costs a fraction of gateway traffic.</p><ul><li>A single service, or internal traffic.</li><li>A high-⁠volume, latency-⁠sensitive, simple path.</li></ul>"},{"id":"how-do-you-estimate-the-size-of-a-postgres-row","topics":["Postgres"],"questionHtml":"How do you estimate the size of a Postgres row?","answerHtml":"<p>About <strong>23 bytes of header per row</strong>, padded to 24, plus a 4-⁠byte pointer to the row: roughly 28 bytes.</p><ul><li>Then add the columns, for example 8 bytes for a <code>timestamp</code>.</li></ul>"},{"id":"how-can-postgres-split-one-large-table-by-time-without-sharding","topics":["Postgres"],"questionHtml":"How can Postgres split one large table by time, without sharding?","answerHtml":"<p>With its built-⁠in table partitioning: one logical table is split into child tables by time range.</p><ul><li>For example, one child table per day, or one per month.</li></ul>"},{"id":"why-does-postgres-cope-with-hundreds-of-connections-but-not-thou","topics":["Postgres"],"questionHtml":"Why does Postgres cope with hundreds of connections but not thousands?","answerHtml":"<p>It runs <strong>one OS process per connection</strong>, and each one uses a few MB of memory.</p><ul><li>So it handles a few hundred connections well, but not thousands.</li><li>For more clients, multiplex them through a pooler such as PgBouncer.</li></ul>"},{"id":"why-put-a-connection-pooler-such-as-pgbouncer-in-front-of-a-data","topics":["Postgres"],"questionHtml":"Why put a connection pooler such as PgBouncer in front of a database?","answerHtml":"<p>A database does useful work on only about <strong>2–⁠4 queries per CPU core</strong> at a time.</p><ul><li>So thousands of connections are mostly idle.</li><li>A pooler multiplexes them onto a few real connections: PgBouncer, or Amazon RDS Proxy (managed).</li></ul>"},{"id":"how-do-you-add-full-text-search-to-a-postgres-table","topics":["Postgres"],"questionHtml":"How do you add full-⁠text search to a Postgres table?","answerHtml":"<p>Use the built-⁠in full-⁠text search, not <code>LIKE</code>, in three steps:</p><ol><li>Add a preprocessed <code>tsvector</code> column, generated and stored.</li><li>Index it with GIN, a <strong>Generalized Inverted Index</strong>.</li><li>Query it with the match operator <code>@@</code> and a <code>tsquery</code>.</li></ol>"},{"id":"how-do-you-add-a-generated-tsvector-column-for-full-text-search","topics":["Postgres","SQL"],"questionHtml":"How do you add a generated <code>tsvector</code> column for full-⁠text search?","answerHtml":"<p>A stored generated column; name the text search configuration, since the expression must be immutable:</p><pre><code>ALTER TABLE articles ADD COLUMN search_vector\n  tsvector GENERATED ALWAYS AS\n  (to_tsvector('english', content)) STORED;\n</code></pre>"},{"id":"how-do-you-index-and-query-a-tsvector-column-in-postgres","topics":["Postgres","SQL"],"questionHtml":"How do you index and query a <code>tsvector</code> column in Postgres?","answerHtml":"<p>A GIN index on the column, then match with <code>@@</code> against a query in the same configuration:</p><pre><code>CREATE INDEX articles_search_idx\n  ON articles USING GIN (search_vector);\n\nSELECT content FROM articles\nWHERE search_vector @@\n  plainto_tsquery('english', 'foo bar');\n</code></pre>"},{"id":"what-is-a-good-default-replication-setup-for-postgres","topics":["Postgres","Consistency"],"questionHtml":"What is a good default replication setup for Postgres?","answerHtml":"<p>One leader plus read replicas, with <strong>synchronous replication to at least one replica</strong>, so failover doesn’t lose acknowledged writes.</p><ul><li>For example <code>synchronous_standby_names = 'ANY 1 (s1, s2)'</code>: each commit waits until s1 or s2 confirms it.</li></ul>"},{"id":"what-can-go-wrong-when-a-postgres-leader-fails-over-to-a-replica","topics":["Postgres","Consistency"],"questionHtml":"What can go wrong when a Postgres leader fails over to a replica?","answerHtml":"<p>Two things: losing acknowledged writes, and split brain.</p><ul><li>Lost writes: much less likely with synchronous replication, but possible if the synced replica can’t be reached and another one is promoted.</li><li>Split brain: the old leader keeps serving, so two leaders accept writes.</li></ul>"},{"id":"what-does-read-your-writes-consistency-guarantee-and-what-doesn","topics":["Consistency","Postgres"],"questionHtml":"What does read-⁠your-⁠writes consistency guarantee, and what doesn’t it?","answerHtml":"<p>A client always sees <strong>its own earlier writes</strong>, and nothing more.</p><ul><li>Other clients’ writes may still be missing, so it’s far weaker than strong consistency.</li><li>In Postgres, reading from the leader gets you close to strongly consistent reads, unless it fails over between reads.</li></ul>"},{"id":"how-do-you-stop-a-deposed-postgres-leader-from-causing-split-bra","topics":["Consistency","Postgres"],"questionHtml":"How do you stop a deposed Postgres leader from causing split brain?","answerHtml":"<p>Keep a strongly consistent view of the leader in <strong>etcd</strong> (for example via Patroni), and make sure an old leader can’t write.</p><ul><li>Leases: the leader demotes itself when its lease expires, or a hardware watchdog kills the machine.</li><li>Fencing tokens: each new leader gets a higher number, and downstream resources reject writes carrying a lower one.</li></ul>"},{"id":"how-do-you-make-an-insert-skip-rows-that-would-break-a-unique-co","topics":["SQL","Postgres"],"questionHtml":"How do you make an <code>INSERT</code> skip rows that would break a unique constraint?","answerHtml":"<p><code>ON CONFLICT DO NOTHING</code>: rows that would conflict are skipped silently.</p><ul><li>To skip only one constraint’s conflicts, name it, <code>ON CONFLICT ON CONSTRAINT constraint_x</code>, or its columns, <code>ON CONFLICT (col)</code>.</li><li>Only unique and exclusion constraints count; <code>CHECK</code>, foreign key and <code>NOT NULL</code> violations still raise errors.</li></ul>"},{"id":"how-do-you-get-the-generated-id-back-from-an-insert","topics":["SQL"],"questionHtml":"How do you get the generated id back from an <code>INSERT</code>?","answerHtml":"<p>Add <code>RETURNING</code>: by default an <code>INSERT</code> returns no rows.</p><ul><li><code>INSERT ... RETURNING id, col_foo, col_bar</code> returns those columns from each inserted row.</li></ul>"},{"id":"how-do-you-run-a-single-transaction-at-a-stricter-isolation-leve","topics":["SQL","Concurrency"],"questionHtml":"How do you run a single transaction at a stricter isolation level?","answerHtml":"<p>Set the level per transaction; the others keep the default (Read Committed in Postgres).</p><ul><li><code>BEGIN ISOLATION LEVEL SERIALIZABLE;</code></li><li>Or <code>SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;</code> as the transaction’s first statement.</li></ul>"},{"id":"walk-through-how-an-sqs-message-is-processed-including-failures","topics":["Queues"],"questionHtml":"Walk through how an SQS message is processed, including failures.","answerHtml":"<p>Receive → process → delete; a received message stays hidden from other workers for its visibility timeout (30 s by default).</p><ul><li>If the worker crashes, or is still processing when the timeout expires, the message reappears for another worker.</li><li>If it keeps failing, a redrive policy moves it to a dead-⁠letter queue after <code>maxReceiveCount</code> receives.</li></ul>"},{"id":"how-long-does-sqs-keep-a-message-and-where-is-it-stored","topics":["Queues"],"questionHtml":"How long does SQS keep a message, and where is it stored?","answerHtml":"<p>Retention is a per-⁠queue setting: <strong>4 days by default</strong>, from 1 minute up to 14 days.</p><ul><li>SQS is regional: it stores messages across several availability zones in one region, with no copy in another region.</li></ul>"},{"id":"how-should-workers-poll-an-sqs-queue-efficiently","topics":["Queues"],"questionHtml":"How should workers poll an SQS queue efficiently?","answerHtml":"<p>Long-⁠poll in batches, then call again straight away.</p><ul><li>On an empty queue a receive call blocks until a message arrives, for up to 20 s.</li><li>Long polling is opt-⁠in: set a wait time, as the default is 0 s.</li><li>One call returns <strong>at most 10 messages</strong>, a hard limit, and only 1 unless you ask for more.</li></ul>"},{"id":"how-does-aws-lambda-consume-messages-from-an-sqs-queue","topics":["Queues"],"questionHtml":"How does AWS Lambda consume messages from an SQS queue?","answerHtml":"<p>Natively, in batches: for example “wait for 500 messages or 1 s, whichever comes first”.</p><ul><li>When the function exits successfully, Lambda deletes the whole batch from the queue.</li></ul>"},{"id":"how-can-sqs-hold-a-message-back-until-it-s-due-say-in-10-minutes","topics":["Queues","Case studies"],"questionHtml":"How can SQS hold a message back until it’s due, say in 10 minutes?","answerHtml":"<p>Set a per-⁠message delay, <code>DelaySeconds</code>: the message stays hidden until it’s due.</p><ul><li>The delay is capped at <strong>15 minutes</strong> (900 s), so it suits near-⁠term scheduling, such as notifications due soon.</li><li>FIFO queues support only a delay for the whole queue, not per message.</li></ul>"},{"id":"how-long-do-kinesis-and-kafka-retain-data-and-at-what-cost","topics":["Streams"],"questionHtml":"How long do Kinesis and Kafka retain data, and at what cost?","answerHtml":"<p>Kinesis: <strong>24 hours by default</strong>, up to 365 days; retention beyond 24 hours costs extra.</p><ul><li>Kafka: as long as you configure; the default is 7 days on local disk.</li><li>With Kafka’s tiered storage, older data sits cheaply on S3.</li></ul>"},{"id":"how-do-kinesis-and-kafka-keep-stored-data-durable","topics":["Streams"],"questionHtml":"How do Kinesis and Kafka keep stored data durable?","answerHtml":"<p>Kinesis replicates every record synchronously across 3 availability zones.</p><ul><li>Kafka replicates per topic: 3 replicas in 3 zones is a deployment choice (replication factor 3 at topic creation, plus <code>broker.rack</code>); <code>default.replication.factor</code> defaults to 1.</li><li>For the long term, archive to S3, designed for eleven 9s of durability.</li></ul>"},{"id":"how-does-redis-execute-commands-and-how-much-can-one-node-handle","topics":["Redis"],"questionHtml":"How does Redis execute commands, and how much can one node handle?","answerHtml":"<p>Single-⁠threaded: <strong>one command at a time, in order</strong>, each taking microseconds.</p><ul><li>One node handles ~100k writes/s; over the network, reads take under a millisecond.</li><li>Pipelining, several requests per network round trip, lifts that to ~1–⁠1.5M requests/s per node on typical hardware.</li></ul>"},{"id":"how-much-can-one-redis-node-hold-and-when-should-you-shard","topics":["Redis","Sharding"],"questionHtml":"How much can one Redis node hold, and when should you shard?","answerHtml":"<p>Tens to low hundreds of millions of keys per node.</p><ul><li>Past roughly <strong>25–⁠50 GB per node</strong>, most teams shard with Redis Cluster.</li><li>Shard too when one primary can no longer serve all of the traffic.</li></ul>"},{"id":"how-do-you-make-a-single-redis-primary-highly-available","topics":["Redis"],"questionHtml":"How do you make a single Redis primary highly available?","answerHtml":"<p>Add a replica, and <strong>Sentinel</strong> for automated failover.</p><ul><li>Primary–⁠replica replication is built in; it is asynchronous by default, so a failover can lose acknowledged writes.</li><li>Sentinel, built in but enabled separately, monitors the nodes, fails over and tells clients which node is primary.</li></ul>"},{"id":"what-are-the-ways-to-run-redis-and-how-do-they-differ","topics":["Redis","Sharding"],"questionHtml":"What are the ways to run Redis, and how do they differ?","answerHtml":"<p>A single node, a primary with replicas (plus Sentinel for failover), or a cluster.</p><ul><li>Sentinel doesn’t shard: one primary still holds all of the data.</li><li>Cluster also shards: each primary owns part of the keyspace and can have replicas for failover.</li></ul>"},{"id":"how-does-redis-cluster-decide-which-node-serves-a-key","topics":["Redis","Sharding"],"questionHtml":"How does Redis Cluster decide which node serves a key?","answerHtml":"<p>Every key hashes to one of <strong>16,384 hash slots</strong>, and each slot is assigned to a node.</p><ul><li>Nodes share the cluster state with each other via a gossip protocol.</li><li>Ask the wrong node for a key and you get a <code>MOVED</code> reply pointing at the right one.</li></ul>"},{"id":"how-do-you-make-two-redis-keys-land-on-the-same-cluster-node","topics":["Redis","Sharding"],"questionHtml":"How do you make two Redis keys land on the same cluster node?","answerHtml":"<p>Use a hash tag: only the part of the key in {braces} is hashed.</p><ul><li><code>{user:123}:posts</code> and <code>{user:123}:likes</code> hash to the same slot, so they live on the same node.</li></ul>"},{"id":"what-naming-convention-should-you-use-for-redis-keys","topics":["Redis"],"questionHtml":"What naming convention should you use for Redis keys?","answerHtml":"<p><code>object-⁠type:id:field</code>, for example <code>user:1001:profile</code>, <code>session:abc123</code> or <code>rate:api:user:1001</code>.</p><ul><li>Put a version prefix in keys you’ll migrate: <code>v2:user:1001</code>.</li></ul>"},{"id":"what-does-redis-do-by-default-when-memory-is-full","topics":["Redis"],"questionHtml":"What does Redis do by default when memory is full?","answerHtml":"<p><strong>Nothing is evicted.</strong> The default policy is <code>noeviction</code>: once <code>maxmemory</code> is reached, writes fail with an OOM error; reads still work.</p><ul><li>On 64-⁠bit, <code>maxmemory</code> defaults to 0 (no limit), so set one.</li><li>For a cache, configure <code>allkeys-⁠lru</code> (or <code>allkeys-⁠lfu</code>).</li><li>ElastiCache and Redis Cloud default to <code>volatile-⁠lru</code>: LRU among keys with a TTL.</li></ul>"},{"id":"why-should-you-add-random-jitter-to-cache-ttls-in-redis","topics":["Redis"],"questionHtml":"Why should you add random jitter to cache TTLs in Redis?","answerHtml":"<p>So that keys written together don’t all expire together.</p><ul><li>Synchronised expiry sends a stampede of cache misses to the database at once.</li><li>A small random offset per key spreads the expiries out.</li></ul>"},{"id":"how-do-you-build-a-simple-distributed-lock-with-redis","topics":["Redis","Concurrency"],"questionHtml":"How do you build a simple distributed lock with Redis?","answerHtml":"<p><code>SET seat:42 &lt;token&gt; NX EX 60</code>: an atomic set-⁠if-⁠absent with a TTL.</p><ul><li><code>NX</code> sets the key only if it doesn’t exist yet, so only one client gets the lock.</li><li><code>EX 60</code> expires the key after 60 s, so a crashed holder can’t keep it forever.</li><li>Use a random token per attempt; release only if the key still holds yours: <code>DELEX seat:42 IFEQ &lt;token&gt;</code> (Redis 8.4+) or a Lua script.</li></ul>"},{"id":"what-is-redis-good-for-besides-caching-and-with-which-features","topics":["Redis"],"questionHtml":"What is Redis good for besides caching, and with which features?","answerHtml":"<p>Locks, rate limiting, leaderboards, geospatial search, event sourcing and Pub/Sub.</p><ul><li>Locks: an atomic set-⁠if-⁠absent with a TTL.</li><li>Rate limiting: a counter you increment, or sorted sets for a sliding window.</li><li>Leaderboards: sorted sets.</li><li>Event sourcing: streams, Redis’s append-⁠only logs.</li></ul>"},{"id":"how-far-does-redis-pub-sub-scale-and-what-doesn-t-it-guarantee","topics":["Redis","Real-time"],"questionHtml":"How far does Redis Pub/Sub scale, and what doesn’t it guarantee?","answerHtml":"<p>Subscribing and unsubscribing are instant and cheap: tens of thousands of channels per server and millions in total are fine.</p><ul><li>Delivery is at most once: a subscriber that is offline or disconnected misses the message.</li><li>In a cluster, sharded Pub/Sub (<code>SPUBLISH</code>, Redis 7.0+) keeps each channel within its shard.</li></ul>"},{"id":"why-doesn-t-waiting-for-redis-replicas-give-you-strong-consisten","topics":["Redis","Consistency"],"questionHtml":"Why doesn’t waiting for Redis replicas give you strong consistency?","answerHtml":"<p><code>WAIT</code> only improves durability; a network partition can still cause split brain.</p><ul><li>Two nodes can each believe they’re the leader and accept writes independently, or grant the same lock twice.</li><li>Strong consistency needs <strong>a consensus protocol</strong> that lets only one side keep accepting writes.</li></ul>"},{"id":"how-do-you-prevent-deadlocks-when-transactions-lock-several-rows","topics":["Concurrency"],"questionHtml":"How do you prevent deadlocks when transactions lock several rows?","answerHtml":"<p>Acquire locks in one <strong>globally sorted order</strong>.</p><ul><li>Deadlock: A transfers x → y and B transfers y → x. A locks x, B locks y, and each waits for the other.</li><li>Sorted: both lock x first. B waits; A locks y, finishes and releases; then B locks x and y.</li></ul>"},{"id":"how-does-optimistic-concurrency-control-work","topics":["Concurrency"],"questionHtml":"How does optimistic concurrency control work?","answerHtml":"<p>Write only if a value you read hasn’t changed since, checked in the same atomic step as the write.</p><ul><li>Typically a version, or a monotonically increasing business value: <code>UPDATE ... SET ..., version = 8 WHERE id = 1 AND version = 7</code>.</li><li>If it has changed (no row updated), abort and retry from the beginning.</li></ul>"}]}