<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[System Overflow - Master System Design]]></title><description><![CDATA[Master System Design Interviews.]]></description><link>https://blog.systemoverflow.com</link><image><url>https://substackcdn.com/image/fetch/$s_!JGdu!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e1ac73a-22e8-4297-9692-962a010b649a_512x512.png</url><title>System Overflow - Master System Design</title><link>https://blog.systemoverflow.com</link></image><generator>Substack</generator><lastBuildDate>Mon, 25 May 2026 04:26:31 GMT</lastBuildDate><atom:link href="https://blog.systemoverflow.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[System Overflow]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[contact@systemoverflow.com]]></webMaster><itunes:owner><itunes:email><![CDATA[contact@systemoverflow.com]]></itunes:email><itunes:name><![CDATA[System Overflow]]></itunes:name></itunes:owner><itunes:author><![CDATA[System Overflow]]></itunes:author><googleplay:owner><![CDATA[contact@systemoverflow.com]]></googleplay:owner><googleplay:email><![CDATA[contact@systemoverflow.com]]></googleplay:email><googleplay:author><![CDATA[System Overflow]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[What Interviewers Actually Look For: A System Design Rubric by Level]]></title><description><![CDATA[System Design Rurbric by Level]]></description><link>https://blog.systemoverflow.com/p/what-interviewers-actually-look-for</link><guid isPermaLink="false">https://blog.systemoverflow.com/p/what-interviewers-actually-look-for</guid><dc:creator><![CDATA[System Overflow]]></dc:creator><pubDate>Thu, 05 Feb 2026 14:19:28 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!XKMg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff73f64df-6623-476d-9762-56112db37b53_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>What exactly is the interviewer writing on their scorecard while you design a URL shortener on the whiteboard?</p><p>It is not a checklist of technologies. It is not whether you mentioned Kafka or Redis. Every interviewer at a serious tech company is evaluating you across a set of dimensions, and the expected depth on each dimension changes based on the level you are interviewing for.</p><p>The problem is that nobody publishes these rubrics. Companies keep them internal. So candidates end up guessing what &#8220;Senior-level depth&#8221; means versus &#8220;Mid-level depth,&#8221; and they calibrate against blog posts and YouTube videos that are often written by people who have never actually conducted these interviews.</p><p>What follows is a concrete <a href="https://www.systemoverflow.com/interview-rubric">rubric</a>. No hand-waving. No &#8220;it depends.&#8221; For each dimension of a system design interview, here is exactly what is expected at Junior, Mid-Level, Senior, and Staff+ levels.</p><h2>How to Use This Rubric</h2><p>Before we dive in, a few things to understand about how interview leveling works.</p><p>Levels reflect interview expectations, not years of experience. A sharp engineer with 3 years of experience can interview at Senior level if they have worked on the right problems. A 10-year engineer can interview at Mid-Level for a domain they have never worked in. The rubric describes what you need to demonstrate, not who you need to be.</p><blockquote><p><em><strong>Key insight:</strong> Interviewers are not looking for you to hit every single point at your target level. They are looking for a pattern. If you consistently demonstrate Senior-level thinking across most dimensions, you will get a Senior rating even if you miss a few specifics.</em></p></blockquote><p>The rubric covers nine dimensions. Not every interview will test all of them. A 45-minute round might only touch five or six. But understanding all nine helps you recognize what the interviewer is probing for and adjust your depth accordingly.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!XKMg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff73f64df-6623-476d-9762-56112db37b53_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!XKMg!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff73f64df-6623-476d-9762-56112db37b53_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!XKMg!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff73f64df-6623-476d-9762-56112db37b53_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!XKMg!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff73f64df-6623-476d-9762-56112db37b53_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!XKMg!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff73f64df-6623-476d-9762-56112db37b53_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!XKMg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff73f64df-6623-476d-9762-56112db37b53_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f73f64df-6623-476d-9762-56112db37b53_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:474229,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.systemoverflow.com/i/186974920?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff73f64df-6623-476d-9762-56112db37b53_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!XKMg!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff73f64df-6623-476d-9762-56112db37b53_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!XKMg!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff73f64df-6623-476d-9762-56112db37b53_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!XKMg!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff73f64df-6623-476d-9762-56112db37b53_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!XKMg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff73f64df-6623-476d-9762-56112db37b53_1536x1024.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.systemoverflow.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.systemoverflow.com/subscribe?"><span>Subscribe now</span></a></p><h2>1. Communication and Structure</h2><p>This is the dimension that most candidates underestimate. It is also the one that interviewers evaluate from the very first minute.</p><p>At the <strong>Junior level</strong>, the bar is straightforward: state your approach before you start drawing, explain components as you add them, respond to questions clearly, and ask for feedback at major decision points. You are showing that you can think out loud and collaborate.</p><p>At the <strong>Mid-Level</strong>, you should propose a structured approach upfront. Something like: &#8220;I will start with requirements, then sketch the high-level design, then deep dive into the areas that matter most.&#8221; You time-box each section, summarize before moving on, and keep the whiteboard organized. This shows you have done this before.</p><p>At the <strong>Senior level</strong>, you drive the interview. You are not waiting for the interviewer to direct you. You adjust depth based on their signals. When you hit a decision point, you offer multiple options with trade-offs instead of just picking one. You proactively identify which areas deserve a deep dive.</p><p>At <strong>Staff+</strong>, you frame the problem before solving it. You teach while designing, explaining the &#8220;why&#8221; unprompted. You navigate ambiguity without needing guidance. And critically, you connect technical decisions to business outcomes. &#8220;We need eventual consistency here because the business can tolerate a 5-second delay on friend counts, and strong consistency would cost us 3x in latency.&#8221;</p><blockquote><p><em><strong>Why this matters so much:</strong> An engineer who builds a perfect system but cannot explain their reasoning is risky to hire. Communication is not a soft skill in system design. It is how interviewers determine whether you actually understand what you built or just memorized patterns.</em></p></blockquote><h2>2. Requirements and Estimation</h2><p>This is where experienced engineers separate themselves from those who have only read about system design.</p><p><strong>Junior:</strong> Ask 3-5 clarifying questions before designing. Identify core functional requirements. Confirm user types and basic use cases. Acknowledge that scale matters, even if you cannot calculate it precisely.</p><p><strong>Mid-Level:</strong> Cover both functional and non-functional requirements systematically. Estimate DAU, QPS, and storage from the constraints given. Identify whether the system is read-heavy or write-heavy and explain the implications. Do basic math: QPS = DAU x actions per user / 86,400.</p><p><strong>Senior:</strong> Do back-of-envelope calculations for storage, bandwidth, cache size, and server count. Identify latency SLAs (p50 and p99) and consistency requirements. Prioritize requirements as P0 versus P1 to scope the problem. Most importantly, use your estimates to justify design choices. &#8220;At 10K QPS, we need sharding because a single PostgreSQL instance tops out around 5K writes per second.&#8221;</p><p><strong>Staff+:</strong> Challenge assumptions in the requirements. &#8220;Do we really need real-time updates, or would near-real-time with a 2-second delay be acceptable?&#8221; Estimate cost implications of design choices. Identify phased delivery milestones. Anticipate how scale will evolve: current state, 6 months out, 2 years out.</p><h2>3. High-Level Design</h2><p>The high-level design is where most candidates spend the majority of their time. Ironically, it is also where the level differences are most visible.</p><p><strong>Junior:</strong> Show a clear client, API server, and database. Draw request flows with arrows. Identify the need for authentication. Demonstrate basic separation of concerns. This is the minimum viable architecture.</p><p><strong>Mid-Level:</strong> Add a load balancer, stateless app servers, and database replicas. Include a cache layer with a clear invalidation trigger. Use a CDN for static content. Separate read and write paths when the access patterns justify it.</p><p><strong>Senior:</strong> Define service boundaries with clear responsibilities. Introduce async processing via message queues for heavy operations. Match storage types to access patterns. Maybe you need a relational database for transactional data, a document store for user profiles, and a search index for full-text queries. Each choice should have a reason.</p><p><strong>Staff+:</strong> Show multi-region topology with data flow. Identify single points of failure and their mitigations. Include observability integration points. Make deployment and rollback strategy visible in the design. At this level, the architecture tells a story about how the system operates, not just how it processes requests.</p><h2>4. API Design</h2><p>With the high-level architecture sketched, the next question is how services talk to each other and to the outside world. API design is often treated as an afterthought, but it reveals a lot about how a candidate thinks about system boundaries and contracts.</p><p><strong>Junior:</strong> Define REST endpoints for core operations. Use correct HTTP methods. Sketch request and response structures. Mention authentication.</p><p><strong>Mid-Level:</strong> Follow resource naming conventions. Include pagination with cursor or offset. Define a consistent error response format. Show awareness of rate limiting.</p><p><strong>Senior:</strong> Design for idempotency on mutations using idempotency keys. Define a versioning strategy for API evolution. Choose appropriate async patterns: webhooks, polling, or streaming. Define API gateway responsibilities.</p><p><strong>Staff+:</strong> Separate internal APIs from external APIs. Define backward compatibility guarantees. Analyze batch versus single-item trade-offs. Consider client SDK implications. At this level, you are designing APIs that other teams will build against for years.</p><h2>5. Data Model</h2><p>The data model is where interviewers probe your understanding of how data actually behaves at scale.</p><p><strong>Junior:</strong> Identify main entities with attributes. Define primary keys. Show basic relationships (one-to-many, many-to-many). Use reasonable field types.</p><p><strong>Mid-Level:</strong> Make a SQL versus NoSQL choice with reasoning. Define indexes for frequent query patterns. Explain denormalization decisions. Handle many-to-many relationships appropriately.</p><p><strong>Senior:</strong> Select partition keys with reasoning. Prevent hot partitions. Consider read versus write optimized schemas (CQRS when appropriate). Define data lifecycle: TTL, archival, and deletion policies.</p><p><strong>Staff+:</strong> Define cross-service data boundaries and ownership. Specify consistency guarantees at the entity level. Plan for schema evolution and backward compatibility. Address compliance considerations like PII handling, retention policies, and audit trails.</p><blockquote><p><em><strong>A pattern interviewers notice:</strong> Junior and Mid-Level candidates design data models that work. Senior candidates design data models that scale. Staff+ candidates design data models that evolve. The difference is in what you optimize for: correctness, performance, or longevity.</em></p></blockquote><h2>6. Scalability</h2><p>Once the data model is defined, the interview typically shifts to how the system handles growth. Scalability questions reveal whether you have actually operated systems under load or just studied the theory.</p><p><strong>Junior:</strong> Understand horizontal versus vertical scaling. Know that caching reduces database load. Recognize that stateless services can be replicated. Explain what a load balancer does.</p><p><strong>Mid-Level:</strong> Use read replicas for read-heavy workloads. Implement cache-aside with TTL and invalidation strategy. Move work off the critical path with async processing. Use connection pooling for database efficiency.</p><p><strong>Senior:</strong> Implement database sharding with consistent hashing. Use partitioned queues for parallel processing. Know write scaling strategies: sharding and batching. Implement back-pressure and load shedding to protect the system under stress.</p><p><strong>Staff+:</strong> Design cell-based architecture to limit blast radius. Implement multi-region active-active with conflict resolution. Define a capacity planning methodology. Design graceful degradation tiers so the system loses features, not availability, under overload.</p><h2>7. Reliability and Fault Tolerance</h2><p>This is where production experience shows most clearly. Engineers who have been woken up at 3 AM think about failure differently than those who have not.</p><p><strong>Junior:</strong> Understand that redundancy prevents single points of failure. Know that backups exist for data recovery. Retry on transient failures. Use timeouts to prevent hanging.</p><p><strong>Mid-Level:</strong> Implement database replication for high availability. Use health checks with auto-restart. Apply exponential backoff with jitter on retries. Design graceful degradation when dependencies fail.</p><p><strong>Senior:</strong> Discuss CAP trade-offs for specific components in your design. Use circuit breakers to prevent cascade failures. Make operations idempotent for safe retries. Define RTO and RPO requirements and explain how your design meets them.</p><p><strong>Staff+:</strong> Isolate failure domains. Show awareness of consensus protocols for coordination. Define data durability guarantees including replication factor and sync versus async replication. Define SLIs that map directly to user experience, not just server metrics.</p><h2>8. Trade-offs Discussion</h2><p>Reliability and scalability are not free. Every design decision is a trade-off. The question is whether you recognize it and can articulate it.</p><p><strong>Junior:</strong> Acknowledge that trade-offs exist. Identify at least one bottleneck. Explain why you chose your approach over alternatives. Be open to suggestions from the interviewer.</p><p><strong>Mid-Level:</strong> Articulate 2-3 explicit trade-offs you made during the design. Compare alternatives with pros and cons. Identify the primary bottleneck and how to mitigate it. Explain your consistency versus availability choice.</p><p><strong>Senior:</strong> Quantify trade-offs when possible. &#8220;This adds 50ms of latency but gives us 10x throughput.&#8221; Anticipate how bottlenecks shift at higher scale. Explain what you are NOT building and why. Factor operational complexity into your decisions.</p><p><strong>Staff+:</strong> Do build versus buy analysis for components. Weigh engineering cost against system complexity. Consider the reversibility of decisions. Identify technical debt you are intentionally taking on and define the conditions under which it should be paid off.</p><blockquote><p><em><strong>The Staff+ signal:</strong> When a candidate says &#8220;this decision is easy to reverse if our assumptions are wrong, so I would start here and re-evaluate in 3 months,&#8221; the interviewer is hearing exactly what they want to hear. It shows maturity, pragmatism, and real-world judgment.</em></p></blockquote><h2>9. Deep Dive Ability</h2><p>The deep dive is the final test. It is where interviewers push past your preparation and find the edges of your knowledge.</p><p><strong>Junior:</strong> Explain your design choices when asked. Walk through a request end-to-end. Answer &#8220;what happens when X?&#8221; questions. Admit gaps in knowledge honestly. Honesty about what you do not know is always better than bluffing.</p><p><strong>Mid-Level:</strong> Explain cache invalidation in detail. Walk through failure scenarios. Handle &#8220;what if component X fails?&#8221; questions. Be able to zoom into any component you drew and explain how it works internally.</p><p><strong>Senior:</strong> Proactively offer to deep dive on complex areas without being asked. Explain edge cases like race conditions and split brain scenarios. Handle &#8220;what happens at 10x scale?&#8221; with specific, concrete changes to your design. Discuss operational concerns: how do you monitor this? How do you debug a slow request?</p><p><strong>Staff+:</strong> Explain an incremental migration path from v1 to v2. Handle &#8220;what would you do with unlimited resources?&#8221; without falling into the infinite resources trap. Discuss how to validate the design before committing to a full build. Identify the biggest risks and define mitigation strategies for each.</p><h2>Putting It All Together</h2><p>Here is the pattern across all nine dimensions:</p><ul><li><p><strong>Junior</strong> demonstrates awareness. They know the concepts exist and can apply them when prompted.</p></li><li><p><strong>Mid-Level</strong> demonstrates competence. They can apply concepts systematically and make reasonable choices.</p></li><li><p><strong>Senior</strong> demonstrates depth. They anticipate problems, quantify decisions, and think about operations.</p></li><li><p><strong>Staff+</strong> demonstrates judgment. They challenge assumptions, think about evolution, and connect technical decisions to business outcomes.</p></li></ul><p>The jump from Junior to Mid-Level is about breadth: covering more ground. The jump from Mid-Level to Senior is about depth: going further into each area. The jump from Senior to Staff+ is about judgment: knowing what matters and what does not.</p><p>If you are preparing for an interview, use this rubric to calibrate. Record yourself doing a mock interview, then score yourself on each dimension. The gaps will be obvious. Focus your preparation on the dimensions where you are below your target level, not on the ones where you are already strong.</p><p>And remember: the goal is not to memorize this rubric. The goal is to develop the thinking patterns that make these behaviors natural. When you genuinely understand why partition key selection matters, you do not need to remember that it is a &#8220;Senior-level expectation.&#8221; It just comes out because it is part of how you think about systems.</p><blockquote><p><em><strong>Score yourself against the full interactive rubric on <a href="https://www.systemoverflow.com/interview-rubric">System Overflow</a> before your next interview.</strong> All 9 dimensions, all 4 levels, in one page. Identify exactly where to focus your preparation.</em></p></blockquote><div><hr></div><p>Learn system design @ <a href="https://www.systemoverflow.com">System Overflow</a></p>]]></content:encoded></item><item><title><![CDATA[How OpenAI Runs ChatGPT on a Single PostgreSQL Primary]]></title><description><![CDATA[One primary, 50 read replicas, 800 million users. Here&#8217;s what makes it work.]]></description><link>https://blog.systemoverflow.com/p/how-openai-runs-chatgpt-on-a-single</link><guid isPermaLink="false">https://blog.systemoverflow.com/p/how-openai-runs-chatgpt-on-a-single</guid><dc:creator><![CDATA[System Overflow]]></dc:creator><pubDate>Sat, 24 Jan 2026 06:13:54 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!rBo6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6fe09f37-e8e3-4afa-8b0a-5a5b29360c35_1408x768.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Most engineers assume that at OpenAI&#8217;s scale, you&#8217;d need a distributed database. Sharded Postgres, CockroachDB, or Spanner. Something designed from the ground up for horizontal scaling.</p><p>OpenAI runs ChatGPT on a single PostgreSQL primary with 50 read replicas. One writer handling all writes for 800 million users.</p><p>Understanding why this works reveals something important about database scaling: the bottleneck you assume you have often isn&#8217;t the bottleneck you actually have.</p><h2>Why Single-Primary Can Work</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!rBo6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6fe09f37-e8e3-4afa-8b0a-5a5b29360c35_1408x768.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!rBo6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6fe09f37-e8e3-4afa-8b0a-5a5b29360c35_1408x768.png 424w, https://substackcdn.com/image/fetch/$s_!rBo6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6fe09f37-e8e3-4afa-8b0a-5a5b29360c35_1408x768.png 848w, https://substackcdn.com/image/fetch/$s_!rBo6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6fe09f37-e8e3-4afa-8b0a-5a5b29360c35_1408x768.png 1272w, https://substackcdn.com/image/fetch/$s_!rBo6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6fe09f37-e8e3-4afa-8b0a-5a5b29360c35_1408x768.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!rBo6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6fe09f37-e8e3-4afa-8b0a-5a5b29360c35_1408x768.png" width="1408" height="768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6fe09f37-e8e3-4afa-8b0a-5a5b29360c35_1408x768.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:768,&quot;width&quot;:1408,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1104871,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://blog.systemoverflow.com/i/185610781?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6fe09f37-e8e3-4afa-8b0a-5a5b29360c35_1408x768.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!rBo6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6fe09f37-e8e3-4afa-8b0a-5a5b29360c35_1408x768.png 424w, https://substackcdn.com/image/fetch/$s_!rBo6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6fe09f37-e8e3-4afa-8b0a-5a5b29360c35_1408x768.png 848w, https://substackcdn.com/image/fetch/$s_!rBo6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6fe09f37-e8e3-4afa-8b0a-5a5b29360c35_1408x768.png 1272w, https://substackcdn.com/image/fetch/$s_!rBo6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6fe09f37-e8e3-4afa-8b0a-5a5b29360c35_1408x768.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.systemoverflow.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.systemoverflow.com/subscribe?"><span>Subscribe now</span></a></p><p>The key insight is that ChatGPT&#8217;s workload is overwhelmingly read-heavy. Users send messages, but the system reads far more than it writes: fetching conversation history, loading user preferences, checking permissions, retrieving model configurations.</p><p>For read-heavy workloads, you don&#8217;t need to distribute writes. You need to distribute reads. And PostgreSQL&#8217;s streaming replication makes this straightforward: one primary handles all writes, and up to 50 read replicas serve read traffic across multiple geographic regions.</p><blockquote><p><em><strong>The math:</strong> With an overwhelmingly read-heavy workload and 50 replicas, each replica handles only a fraction of total read traffic. The primary focuses on writes. This is a fundamentally different scaling model than trying to distribute writes across shards.</em></p></blockquote><p>This architecture delivers low double-digit millisecond p99 latency and five-nines availability. In the past 12 months, OpenAI has had exactly one SEV-0 PostgreSQL incident, and that was during the ImageGen launch when 100 million new users signed up in a single week.</p><h2>The Real Bottlenecks</h2><p>If single-primary works so well, why doesn&#8217;t everyone do it? Because making it work requires solving problems that most teams never encounter at smaller scale.</p><p><strong>Connection limits.</strong> Azure PostgreSQL maxes out at 5,000 connections per instance. With hundreds of application servers, each maintaining connection pools, you hit this limit fast. OpenAI solved this with PgBouncer, a connection pooler that sits between applications and PostgreSQL. In transaction pooling mode, connections are returned to the pool after each transaction, allowing thousands of application connections to share hundreds of database connections. This dropped average connection time from 50ms to 5ms.</p><p><strong>Cache miss storms.</strong> OpenAI uses a caching layer to serve most reads. But when cache hit rates drop unexpectedly, the burst of misses can overwhelm PostgreSQL. Their solution: cache locking. When multiple requests miss on the same cache key, only one request fetches from the database. The others wait for the cache to be repopulated. This prevents a single cache failure from cascading into a database outage.</p><p><strong>Expensive queries.</strong> One 12-table join was responsible for multiple high-severity incidents. A spike in this single query could saturate CPU and slow down the entire service. The fix wasn&#8217;t just optimizing the query. It was recognizing that complex joins are an anti-pattern for OLTP workloads. If you need a 12-way join, break it into smaller queries and join in the application layer. Also: never trust your ORM. Always review the SQL it generates.</p><h2>PostgreSQL&#8217;s MVCC Problem</h2><p>While reads scale well, writes expose PostgreSQL&#8217;s fundamental limitation: its multiversion concurrency control (MVCC) implementation.</p><p>When you update a row in PostgreSQL, even a single field, the database doesn&#8217;t modify the existing row. It copies the entire row to create a new version. The old version becomes a &#8220;dead tuple&#8221; that remains in the table until vacuum cleans it up.</p><blockquote><p><em><strong>The cascade effect:</strong> Write amplification means you&#8217;re writing more data than you think. Dead tuples mean reads must scan past obsolete versions. Tables and indexes bloat, consuming more storage and slowing queries. Autovacuum struggles to keep up under heavy write loads, requiring careful tuning.</em></p></blockquote><p>This is why OpenAI doesn&#8217;t try to scale writes on PostgreSQL. Instead, they&#8217;ve migrated write-heavy workloads to sharded systems like Azure CosmosDB. The workloads that remain on PostgreSQL are ones where read-heavy patterns make the single-primary architecture viable.</p><p>They&#8217;ve also banned adding new tables to PostgreSQL entirely. New features must use the sharded systems by default. This prevents the gradual accumulation of write-heavy workloads that would eventually overwhelm the primary.</p><h2>Protecting the Primary</h2><p>With only one writer, the primary is a single point of failure. OpenAI&#8217;s mitigation strategy has multiple layers.</p><p><strong>Offload everything possible.</strong> Any read that doesn&#8217;t require transactional consistency with writes goes to a replica. This means that even if the primary fails, most user-facing requests continue working. Write failures are still serious, but the blast radius is smaller.</p><p><strong>Hot standby.</strong> The primary runs in high-availability mode with a continuously synchronized standby ready to take over. Azure has optimized this failover to remain safe even under extremely high load.</p><p><strong>Workload isolation.</strong> Requests are split into priority tiers and routed to separate instances. A new feature launch with inefficient queries won&#8217;t degrade the performance of critical requests. Different products are isolated from each other so that one product&#8217;s traffic spike doesn&#8217;t affect another.</p><p><strong>Rate limiting everywhere.</strong> Limits are enforced at the application layer, connection pooler, proxy, and query level. The ORM layer can block specific query patterns entirely. When a surge of expensive queries hits, targeted load shedding allows rapid recovery without affecting other traffic.</p><h2>Scaling Read Replicas</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!k98H!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcdecfb79-4127-4b43-a12a-dc25970a2949_1408x768.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!k98H!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcdecfb79-4127-4b43-a12a-dc25970a2949_1408x768.png 424w, https://substackcdn.com/image/fetch/$s_!k98H!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcdecfb79-4127-4b43-a12a-dc25970a2949_1408x768.png 848w, https://substackcdn.com/image/fetch/$s_!k98H!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcdecfb79-4127-4b43-a12a-dc25970a2949_1408x768.png 1272w, https://substackcdn.com/image/fetch/$s_!k98H!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcdecfb79-4127-4b43-a12a-dc25970a2949_1408x768.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!k98H!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcdecfb79-4127-4b43-a12a-dc25970a2949_1408x768.png" width="1408" height="768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cdecfb79-4127-4b43-a12a-dc25970a2949_1408x768.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:768,&quot;width&quot;:1408,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1012237,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.systemoverflow.com/i/185610781?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcdecfb79-4127-4b43-a12a-dc25970a2949_1408x768.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!k98H!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcdecfb79-4127-4b43-a12a-dc25970a2949_1408x768.png 424w, https://substackcdn.com/image/fetch/$s_!k98H!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcdecfb79-4127-4b43-a12a-dc25970a2949_1408x768.png 848w, https://substackcdn.com/image/fetch/$s_!k98H!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcdecfb79-4127-4b43-a12a-dc25970a2949_1408x768.png 1272w, https://substackcdn.com/image/fetch/$s_!k98H!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcdecfb79-4127-4b43-a12a-dc25970a2949_1408x768.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Adding read replicas seems simple: spin up more instances, point them at the primary, done. At OpenAI&#8217;s scale, it&#8217;s more complicated.</p><p>The primary streams Write Ahead Log (WAL) data to every replica. With 50 replicas, that&#8217;s 50 separate streams consuming network bandwidth and CPU on the primary. Each additional replica adds more pressure. You can&#8217;t scale replicas indefinitely without eventually overwhelming the writer you&#8217;re trying to protect.</p><p>OpenAI is working with Azure on cascading replication, where intermediate replicas relay WAL to downstream replicas instead of every replica connecting directly to the primary. This would allow scaling to over 100 replicas without proportionally increasing primary load. But it adds operational complexity around failover management, so it&#8217;s still in testing.</p><h2>Schema Changes at Scale</h2><p>In a normal PostgreSQL deployment, you might run ALTER TABLE without much thought. At OpenAI&#8217;s scale, schema changes are a production risk.</p><p>Some seemingly minor changes, like altering a column type, trigger a full table rewrite. The database locks the table, copies every row to a new version with the updated schema, then swaps the tables. For a table with billions of rows, this can take hours and block writes the entire time.</p><p>OpenAI&#8217;s rules are strict:</p><ul><li><p>Only lightweight schema changes are permitted (adding nullable columns, dropping columns that don&#8217;t trigger rewrites)</p></li><li><p>Schema changes have a 5-second timeout. If it can&#8217;t complete in 5 seconds, it fails.</p></li><li><p>Index creation must use CONCURRENTLY to avoid locking</p></li><li><p>Backfilling table fields is rate-limited. Filling a new column can take over a week, but it doesn&#8217;t impact production.</p></li></ul><h2>When This Architecture Breaks Down</h2><p>OpenAI&#8217;s approach works because their workload matches specific assumptions. Change those assumptions, and the architecture fails.</p><p><strong>Write-heavy workloads don&#8217;t fit.</strong> If your application is 50% writes instead of 5% writes, a single primary becomes the bottleneck immediately. You need sharding or a database designed for distributed writes.</p><p><strong>Strong consistency requirements complicate reads.</strong> Reading from replicas means accepting replication lag. If your application requires reading your own writes immediately, those reads must go to the primary, reducing the benefit of replicas.</p><p><strong>Operational complexity is high.</strong> Managing 50 replicas across multiple regions, tuning PgBouncer, implementing cache locking, enforcing query patterns, rate limiting at every layer: this requires significant engineering investment. For smaller teams, a managed distributed database might be simpler even if it&#8217;s theoretically less efficient.</p><h2>The Deeper Lesson</h2><p>OpenAI&#8217;s PostgreSQL architecture isn&#8217;t a universal template. It&#8217;s an example of matching architecture to workload characteristics.</p><p>They could have sharded from the start. Many engineers would have assumed sharding was necessary at their scale. Instead, they analyzed their actual workload, recognized it was read-heavy, and built an architecture optimized for that pattern. The result is simpler than a sharded system (one writer, no distributed transactions, no cross-shard queries) while still handling 800 million users.</p><p>The lesson isn&#8217;t that sharding is bad or that single-primary is always better. It&#8217;s that scaling decisions should be driven by workload analysis, not assumptions about what &#8220;web scale&#8221; requires. The architecture that works depends on your read/write ratio, consistency requirements, query patterns, and team capacity.</p><p>Sometimes the boring solution, PostgreSQL with read replicas, scales further than you&#8217;d expect. You just have to solve the right problems.</p><div><hr></div><p><strong>Source:</strong> <a href="https://openai.com/index/scaling-postgresql/">Scaling PostgreSQL to 800 Million Users</a> - OpenAI Engineering Blog</p><p>Learn more about database scaling and system design @ <a href="https://www.systemoverflow.com">System Overflow</a></p>]]></content:encoded></item><item><title><![CDATA[The System Design Interview Playbook]]></title><description><![CDATA[How to navigate the System Design interview that decide your next role]]></description><link>https://blog.systemoverflow.com/p/the-system-design-interview-playbook</link><guid isPermaLink="false">https://blog.systemoverflow.com/p/the-system-design-interview-playbook</guid><dc:creator><![CDATA[System Overflow]]></dc:creator><pubDate>Sun, 11 Jan 2026 15:02:51 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!_0ld!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2df42ea5-f2ff-427a-a5b6-3bbb512d497f_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Most engineers misunderstand what system design interviews actually test. They memorize architectures, prepare solutions, and walk in ready to present. Then they get rejected.</p><p>This guide comes from hundreds of interviews at FAANG+ companies, on both sides of the table. No theory. No &#8220;draw these boxes.&#8221; Just what actually works.</p><h2>What System Design Interviews Actually Test</h2><p>Here is the truth. System design interviews are one of the best ways to interview a senior+ engineer. But they are also one of the most misused interview formats in our industry.</p><p>In some companies, system design has been reduced to a box-arranging exercise. Draw some rectangles, connect them with arrows, throw in a load balancer and a cache, and call it a day. This is not what a real system design interview looks like at serious tech companies.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_0ld!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2df42ea5-f2ff-427a-a5b6-3bbb512d497f_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_0ld!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2df42ea5-f2ff-427a-a5b6-3bbb512d497f_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!_0ld!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2df42ea5-f2ff-427a-a5b6-3bbb512d497f_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!_0ld!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2df42ea5-f2ff-427a-a5b6-3bbb512d497f_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!_0ld!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2df42ea5-f2ff-427a-a5b6-3bbb512d497f_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_0ld!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2df42ea5-f2ff-427a-a5b6-3bbb512d497f_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2df42ea5-f2ff-427a-a5b6-3bbb512d497f_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:998158,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://blog.systemoverflow.com/i/184196127?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2df42ea5-f2ff-427a-a5b6-3bbb512d497f_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!_0ld!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2df42ea5-f2ff-427a-a5b6-3bbb512d497f_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!_0ld!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2df42ea5-f2ff-427a-a5b6-3bbb512d497f_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!_0ld!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2df42ea5-f2ff-427a-a5b6-3bbb512d497f_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!_0ld!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2df42ea5-f2ff-427a-a5b6-3bbb512d497f_1536x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>At FAANG+ companies and for senior roles, system design tests both the breadth and depth of your knowledge. Done right, you cannot game this interview by memorizing solutions like you might for coding problems on LeetCode. Even if you have seen the exact question before, a skilled interviewer will find the gaps in your understanding.</p><blockquote><p><em><strong>The real test:</strong> System design interviews reveal whether you have actually built and operated systems at scale, or whether you have just read about them. You cannot fake experience when someone starts asking about failure modes and operational concerns.</em></p></blockquote><p>This is what makes system design the best filter for identifying engineers with real working experience. The patterns of thought, the instincts about what can go wrong, the awareness of operational costs - these things only come from having been there and done that.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.systemoverflow.com&quot;,&quot;text&quot;:&quot;Master System Design Interviews&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.systemoverflow.com"><span>Master System Design Interviews</span></a></p><h2>What to Expect in the Room</h2><p>System design rounds typically run either 45 minutes or 60 minutes. Here is something critical that many candidates miss: there is no way anyone can finish a perfect system design in that time. Interviewers know this. They do not expect a flawless solution.</p><p>What they expect is a demonstration of how you think through problems. They want to see your process, your trade-off analysis, and your ability to make reasonable decisions under constraints.</p><p>Every interviewer has specific areas they care about. Maybe they are deeply interested in database choices. Maybe they want to explore caching strategies. Maybe they are focused on consistency guarantees. Your job is to pick up on these signals and engage with them.</p><p><strong>Here is a mistake that shows up constantly:</strong> candidates come in with a prepared script. They have memorized a solution for &#8220;Design Twitter&#8221; or &#8220;Design Uber&#8221; and they recite it regardless of what the interviewer asks. By the end, the candidate feels great because they covered everything they prepared. Then they get rejected because they never gave the interviewer a chance to deep dive into the areas they actually cared about.</p><p>There is another problem with ignoring signals. Once you start digging into an area that the interviewer does not care about, it is very hard to come out of it cleanly. You lose time, you lose momentum, and you end up rushing through the parts that actually matter.</p><p>System design is a discussion, not a monologue. You are designing together with the interviewer, and you are leading that discussion. But you have to engage with them and build the solution collaboratively. If you just keep talking and dump everything you know, you will fail even if your technical knowledge is solid.</p><h2>Time Management: The Silent Killer</h2><p>Time management separates good candidates from great ones. Without a structure, you will either spend 30 minutes on requirements gathering and run out of time for the actual design, or you will rush through everything and miss critical depth.</p><p>Keep in mind that a 45-minute interview is not really 45 minutes of design time. You lose 2-3 minutes at the start for introductions and 2-3 minutes at the end for your questions about the company and team. So you are really working with about 40 minutes.</p><p>Here is a rough breakdown that works for most 45-minute interviews:</p><ul><li><p><strong>Introductions:</strong> 2-3 minutes</p></li><li><p><strong>Understanding and requirements:</strong> 5 minutes</p></li><li><p><strong>High-level design (big picture):</strong> 10 minutes</p></li><li><p><strong>Deep dives:</strong> 20-22 minutes</p></li><li><p><strong>Your questions about the team/company:</strong> 2-3 minutes</p></li></ul><p>For 60-minute interviews, you get more breathing room. Spend 8-10 minutes on requirements, 12-15 minutes on the big picture, and 30-35 minutes on deep dives. The extra 15 minutes mostly goes into deeper exploration.</p><p>The key insight here is that you need to know where you are at all times. If you are 20 minutes in and still discussing requirements, something has gone wrong. If you are 35 minutes in and have not started any deep dives, you are in trouble.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!rGbZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7cf74ca4-d32c-4653-a75e-425bd4f683b8_1426x669.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!rGbZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7cf74ca4-d32c-4653-a75e-425bd4f683b8_1426x669.png 424w, https://substackcdn.com/image/fetch/$s_!rGbZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7cf74ca4-d32c-4653-a75e-425bd4f683b8_1426x669.png 848w, https://substackcdn.com/image/fetch/$s_!rGbZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7cf74ca4-d32c-4653-a75e-425bd4f683b8_1426x669.png 1272w, https://substackcdn.com/image/fetch/$s_!rGbZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7cf74ca4-d32c-4653-a75e-425bd4f683b8_1426x669.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!rGbZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7cf74ca4-d32c-4653-a75e-425bd4f683b8_1426x669.png" width="1426" height="669" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7cf74ca4-d32c-4653-a75e-425bd4f683b8_1426x669.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:669,&quot;width&quot;:1426,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:221606,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.systemoverflow.com/i/184196127?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7cf74ca4-d32c-4653-a75e-425bd4f683b8_1426x669.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!rGbZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7cf74ca4-d32c-4653-a75e-425bd4f683b8_1426x669.png 424w, https://substackcdn.com/image/fetch/$s_!rGbZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7cf74ca4-d32c-4653-a75e-425bd4f683b8_1426x669.png 848w, https://substackcdn.com/image/fetch/$s_!rGbZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7cf74ca4-d32c-4653-a75e-425bd4f683b8_1426x669.png 1272w, https://substackcdn.com/image/fetch/$s_!rGbZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7cf74ca4-d32c-4653-a75e-425bd4f683b8_1426x669.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>The Structure That Works</h2><p>Having a structure is important, but do not treat it as the only way. You can adapt and improvise as long as you are confident about your approach. That said, here is the structure that works for most people.</p><h3>Phase 1: Understanding the Question</h3><p>Take 2-3 minutes, sometimes even 5 minutes, to just read and understand the question. Do not start talking immediately. Do not start drawing boxes. Just read.</p><p>This sounds obvious, but countless candidates miss critical parts of the question because they are too eager to start showing off their knowledge. The question often contains hints about what matters. A question that mentions &#8220;millions of users&#8221; is telling you that scale matters. A question that mentions &#8220;real-time&#8221; is telling you that latency matters. Read carefully.</p><h3>Phase 2: Gathering Requirements</h3><p>This is where many candidates go wrong. They either ask too many questions before showing any independent thinking, or they make too many assumptions without clarifying anything.</p><p>Here is the right approach: use a two-step process.</p><p><strong>Step one:</strong> Write down your understanding of the functional requirements. List what you think the system needs to do based on the question. This shows the interviewer that you can analyze a problem and form your own understanding.</p><p><strong>Step two:</strong> Ask clarifying questions about missing information. Now that you have demonstrated your thinking, ask about gaps and ambiguities.</p><blockquote><p><em><strong>Why this order matters:</strong> If you start asking questions before writing anything down, the interviewer has no way to judge your understanding of the problem. They do not want to spoon-feed you requirements. They want to see what you can figure out on your own first.</em></p></blockquote><p>Do the same for non-functional requirements. State your understanding of what matters (latency, throughput, consistency, availability), then ask for clarification.</p><p>By the end of this phase, you and the interviewer should agree on both functional and non-functional requirements. This alignment is critical because everything else builds on it.</p><h3>Reading the Signals</h3><p>Here is something subtle but important. During requirements gathering, you will start to sense which parts of the problem the interviewer cares about.</p><p>Say you are designing a system like Pastebin. You ask about authentication requirements. If the interviewer says &#8220;any authentication is fine&#8221; or &#8220;not a primary concern for this problem,&#8221; that is a clear signal. They do not want you to spend time on authentication. They have something else in mind.</p><p>These signals are everywhere if you pay attention. When an interviewer leans in or asks follow-up questions, they are interested. When they give quick, dismissive answers, they want to move on. Learn to read these cues.</p><h3>Phase 3: The Big Picture</h3><p>The big picture is the skeleton of your design without getting into the details of anything. You are showing how requests flow, how data moves through the system, what components exist, but you are not making concrete technology choices yet.</p><p>Think of it as drawing a map before deciding which roads to take. You want the interviewer to see the overall shape of your solution before you start optimizing specific parts.</p><p>This phase should take 10-15 minutes. The key is to explicitly tell the interviewer what you are doing: &#8220;I am going to draw a high-level picture first to show the overall flow, and then we can dive deeper into specific components.&#8221;</p><p>This communication matters. The interviewer needs to understand your process. If you start drawing boxes without explaining your approach, they might think you are already in the details when you are just sketching the outline.</p><h3>Phase 4: Deep Dives</h3><p>This is where the real interview happens. By now, you either know which sections to explore deeply, or the interviewer will tell you explicitly.</p><p>But here is what separates good candidates from great ones: do not just wait for the interviewer to direct you. The most important thing that should come out of your system design interview is your proactive thinking.</p><p>The best area to show this is <strong>failure modes</strong>. Instead of waiting for the interviewer to ask &#8220;what happens if this service goes down,&#8221; you should identify failure scenarios yourself and present them.</p><div class="pullquote"><p>This component is a single point of failure. If it goes down, here is what breaks. To mitigate this, we could do X or Y. I would recommend Y because...</p></div><p>This is what real senior+ engineers do. They do not wait for problems to be pointed out. They anticipate them.</p><h2>The Infinite Resources Trap</h2><p>This is the most common pitfall, especially from candidates who have read a lot but have not built much.</p><p>They will throw in every technology they have heard of. Kafka for messaging. Redis for caching. Elasticsearch for search. Cassandra for writes, PostgreSQL for reads. A separate analytics pipeline. Machine learning for recommendations. CDN for static content. Multiple regions for availability.</p><p>And they never stop to think: who is going to operate all of this? What happens when Kafka has a partition issue at 3 AM? How do you debug a request that touches seven different services? What is the cost of running all this infrastructure?</p><blockquote><p><em><strong>The reality check:</strong> An engineer who has spent sleepless nights on production incidents knows the importance of system reliability and manageability. An engineer who has only read about these systems will happily add complexity without understanding the operational cost.</em></p></blockquote><p>Real experience shows in how you think about operations. Do you consider what happens when things fail? Do you think about the on-call engineer who will debug this at 2 AM? Do you understand that every additional component is another thing that can break?</p><p>This is why system design interviews are so effective at identifying real experience. You cannot fake this perspective. An engineer trying to portray themselves as experienced without having actually been there will fail. Either you have been burned by complexity and learned to respect simplicity, or you have not. There is no middle ground.</p><h2>What Changes at Each Level</h2><p>System design interviews are calibrated differently depending on the level you are interviewing for. Understanding these differences helps you focus on what matters.</p><h3>Software Engineer (SWE)</h3><p>At this level, interviewers want to see that you understand the basics. Can you break down a problem? Do you know what a load balancer does? Can you explain why you need a cache?</p><p>The expectations are:</p><ul><li><p>Clear problem decomposition</p></li><li><p>Understanding of basic components (databases, caches, queues)</p></li><li><p>Ability to make simple trade-off decisions</p></li><li><p>Awareness that scale and reliability matter</p></li></ul><p>You are not expected to design a globally distributed system. You are expected to show foundational knowledge and the ability to reason through problems.</p><h3>Senior Software Engineer (SSE)</h3><p>Now the bar goes up. You should be able to design a complete system end-to-end. Trade-off discussions become more important. You need to explain why you chose PostgreSQL over Cassandra, not just pick one randomly.</p><p>The expectations are:</p><ul><li><p>End-to-end system design capability</p></li><li><p>Clear articulation of trade-offs</p></li><li><p>Understanding of scaling strategies</p></li><li><p>Awareness of operational concerns</p></li><li><p>Ability to estimate capacity and identify bottlenecks</p></li></ul><p>At this level, interviewers start probing your depth. They want to see that you have actually worked with these systems, not just read about them.</p><h3>Staff Engineer</h3><p>Staff level is where quality of judgment becomes the primary evaluation criteria. This is what you are paid for at this level, not how much code you write or how fast you ship.</p><p>There will be scenarios where you have to choose between X and Y, and the right answer is not obvious. Maybe both options have significant trade-offs. Maybe the data is incomplete.</p><p>It is perfectly fine to say &#8220;I do not know which is better at this point, but I would collect more data on A, B, and C before deciding. Based on what we know now, I am leaning toward X because...&#8221;</p><p>This is what interviewers want to see. They want to know how you handle ambiguity and make decisions with incomplete information.</p><p>The expectations are:</p><ul><li><p>Excellent judgment on complex trade-offs</p></li><li><p>Ability to handle ambiguity gracefully</p></li><li><p>Understanding of organizational and team impacts</p></li><li><p>Proactive identification of risks and failure modes</p></li><li><p>Clear communication of reasoning</p></li></ul><h3>Senior Staff and Principal</h3><p>At this level, the scope expands beyond the system itself. You are expected to think about multi-year technical strategy, cross-team dependencies, and organizational implications.</p><p>Interviewers might ask questions like: &#8220;How would you migrate from the current system to this new design?&#8221; or &#8220;What team structure would you need to build and maintain this?&#8221; or &#8220;How does this fit with the company&#8217;s broader technical direction?&#8221;</p><p>The expectations are:</p><ul><li><p>Strategic thinking about technical direction</p></li><li><p>Understanding of multi-team coordination</p></li><li><p>Ability to design for long-term evolution</p></li><li><p>Migration and adoption strategy</p></li><li><p>Influence and alignment skills</p></li></ul><p>The system design itself is almost secondary. What matters is how you think about building technology organizations and making decisions that affect hundreds of engineers.</p><h2>What a Good Interviewer Looks Like</h2><p>Knowing what a good interviewer does helps you recognize a fair interview and adjust when you are not getting one.</p><p><strong>They guide without giving answers.</strong> If you are stuck, a good interviewer will drop hints or ask clarifying questions to nudge you forward. They will not let you flounder in silence, but they will not hand you the solution either.</p><p><strong>They adapt to your level.</strong> A good interviewer is not trying to prove how hard the question is. They are trying to find where your knowledge ends. If you are clearly handling something well, they will push deeper. If you are struggling, they might simplify or redirect.</p><p><strong>They tell you what they want.</strong> Vague interviewers who give no feedback and just watch you struggle are not running a fair evaluation. Good interviewers will say things like &#8220;let us focus on the database layer&#8221; or &#8220;walk me through the failure scenarios.&#8221; They give you direction.</p><p><strong>They take notes instead of judging in real-time.</strong> If an interviewer seems distracted or checked out, that is a red flag. Good interviewers are engaged, listening, and writing things down.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.systemoverflow.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.systemoverflow.com/subscribe?"><span>Subscribe now</span></a></p><h2>Common Mistakes to Avoid</h2><p>The same mistakes show up over and over again. Here is what to avoid:</p><ol><li><p><strong>Starting to draw before understanding the problem.</strong> Take time to read and think. The eager candidate who starts drawing immediately often misses critical requirements.</p></li><li><p><strong>Asking questions without showing your own thinking.</strong> Always demonstrate your understanding first, then ask for clarification. Do not expect the interviewer to define the problem for you.</p></li><li><p><strong>Ignoring the interviewer&#8217;s signals.</strong> If they seem uninterested in a topic, move on. If they keep asking follow-up questions, go deeper. Read the room.</p></li><li><p><strong>Treating it as a presentation instead of a conversation.</strong> System design is collaborative. Engage with your interviewer. Ask for their input. Respond to their questions.</p></li><li><p><strong>Assuming infinite resources.</strong> Every technology choice has costs. Every additional component adds complexity. Show that you understand operational reality.</p></li><li><p><strong>Not managing time.</strong> Know where you should be at each point in the interview. If you are running behind, adjust.</p></li><li><p><strong>Avoiding saying &#8220;I don&#8217;t know.&#8221;</strong> Pretending to know something you do not know is worse than admitting uncertainty. Good engineers know their limits.</p></li><li><p><strong>Forgetting about failure modes.</strong> Production systems fail. Show that you think about what happens when things go wrong.</p></li></ol><h2>Preparation That Actually Works</h2><p>Everyone asks how to prepare for system design interviews. Here is what actually works, based on patterns from successful candidates.</p><p><strong>Build things.</strong> There is no substitute for actual experience. If you have never operated a system at scale, you will have blind spots that preparation cannot fill. Side projects, open source contributions, or taking on infrastructure work at your current job all help.</p><p><strong>Read postmortems.</strong> Companies publish detailed analyses of outages. These are gold mines for understanding how real systems fail and how experienced engineers think about reliability.</p><p><strong>Study real architectures.</strong> Many companies have published blog posts about their systems. Read about how Netflix handles streaming, how Uber manages rides, how Slack handles messaging. Understand the decisions they made and why.</p><p><strong>Practice with mock interviews.</strong> Find someone to practice with. The experience of explaining your thinking out loud, under time pressure, with someone asking questions, is very different from thinking through a problem alone.</p><p><strong>Focus on fundamentals.</strong> You do not need to know every database and every message queue. You need to deeply understand when to use different types of storage, how to handle consistency and availability trade-offs, how caching works, and how to scale systems.</p><h2>The Bigger Picture</h2><p>System design interviews exist because building software at scale is hard. The problems you encounter at 10,000 users are different from 10 million users. The decisions you make early can haunt you for years. The cost of getting it wrong is measured in downtime, lost revenue, and frustrated users.</p><p>What interviewers are really trying to understand is: <strong>can this person make good decisions about complex systems?</strong> Can they reason about trade-offs? Do they understand what they do not know? Will they build something that works, or something that looks good on a whiteboard but falls apart in production?</p><p>The engineers who do well in these interviews are the ones who have learned from experience. They have seen things break. They have debugged production issues at 3 AM. They have dealt with the consequences of poor architectural decisions. That experience shows in how they think and what they worry about.</p><blockquote><p><em><strong>You cannot fake experience. But you can build it.</strong></em></p></blockquote><p>How? Start paying attention to how the systems you work with actually behave. Ask questions about why things were built the way they were. Volunteer for on-call rotations. Read internal incident reports. Over time, you will develop the instincts that make system design interviews feel like natural conversations instead of tests.</p><p>That is the goal. Not to memorize answers, but to develop genuine understanding. When you have that, the interview stops being a test and starts being a conversation about systems you actually know how to build.</p><div><hr></div><p>Master System Design @ <a href="https://www.systemoverflow.com">System Overflow</a></p>]]></content:encoded></item><item><title><![CDATA[How Meta Built DrP: Automated Root Cause Analysis at Scale]]></title><description><![CDATA[Building a scalable investigation platform that codifies tribal knowledge into automated playbooks, reducing MTTR through programmable workflows and ML-powered analysis.]]></description><link>https://blog.systemoverflow.com/p/how-meta-built-drp-automated-root</link><guid isPermaLink="false">https://blog.systemoverflow.com/p/how-meta-built-drp-automated-root</guid><dc:creator><![CDATA[System Overflow]]></dc:creator><pubDate>Mon, 05 Jan 2026 14:46:26 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!voPE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F757161d0-66d0-4d55-ab22-074300ea406e_2816x1536.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When an alert fires at 3 AM, your on-call engineer faces a daunting task. They need to check dozens of metrics, correlate events across systems, identify which dependency failed, and determine root cause before escalating further. At Meta&#8217;s scale, running 50,000 automated analyses daily across 300+ teams, this manual process doesn&#8217;t just cause engineer burnout. It directly impacts system availability.</p><p>Meta built <a href="https://arxiv.org/abs/2512.04250">DrP</a> to solve this exact problem. Over five years in production, processing 1.5 million analyzer runs and 250K alerts every 30 days, <strong>DrP has reduced mean time to resolve (MTTR) by 20% on average</strong>. Teams that comprehensively adopted the platform achieved 50-80% reductions. But DrP isn&#8217;t just about automation. It&#8217;s a case study in how to capture tribal knowledge, build extensible investigation workflows, and create a system that compounds value as more teams adopt it.</p><p>You&#8217;ll learn how Meta approached the core challenges of automated incident investigation: building an expressive SDK for diverse investigation patterns, scaling execution to handle thousands of concurrent analyses, and integrating seamlessly into existing workflows.</p><div><hr></div><h2><strong>The Challenge: Investigation Workflows That Don&#8217;t Scale</strong></h2><p>Meta&#8217;s infrastructure spans thousands of services with complex dependencies. When a metric degrades, the investigation typically follows a decision tree. Is it a configuration change? Did a dependency fail? Is it isolated to one region? Traditional approaches fail at this scale for three reasons.</p><p>First, <strong>playbooks become outdated immediately</strong>. Engineers document investigation steps in wikis or runbooks, but these grow stale as systems evolve. A service that used to call three dependencies now calls twelve. The configuration format changed. By the time the next incident hits, your carefully documented playbook leads to dead ends.</p><p>Second, <strong>ad-hoc scripts don&#8217;t compose</strong>. Individual teams write Python scripts or SQL queries to automate parts of their investigations. But these scripts are point solutions. They hardcode assumptions about data locations, assume specific metric names, and can&#8217;t be chained together. When you need to investigate a dependency&#8217;s dependency, you&#8217;re back to manual work.</p><blockquote><p><em><strong>At scale, the real problem isn&#8217;t any single incident. It&#8217;s the combinatorial explosion of investigation paths across hundreds of services.</strong></em></p></blockquote><p>Think of it like a choose-your-own-adventure book where every page is written by a different author using a different language. You can&#8217;t jump between chapters. Each investigation starts from scratch.</p><p>Third, <strong>tribal knowledge remains locked in engineers&#8217; heads</strong>. Your senior engineer knows that when metric X drops, you should check configuration Y in region Z. But that knowledge disappears when they&#8217;re on vacation or leave the team. New on-call engineers spend hours rediscovering patterns that experts recognize instantly.</p><div><hr></div><h2><strong>Meta&#8217;s Solution Architecture</strong></h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!voPE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F757161d0-66d0-4d55-ab22-074300ea406e_2816x1536.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!voPE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F757161d0-66d0-4d55-ab22-074300ea406e_2816x1536.png 424w, https://substackcdn.com/image/fetch/$s_!voPE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F757161d0-66d0-4d55-ab22-074300ea406e_2816x1536.png 848w, https://substackcdn.com/image/fetch/$s_!voPE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F757161d0-66d0-4d55-ab22-074300ea406e_2816x1536.png 1272w, https://substackcdn.com/image/fetch/$s_!voPE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F757161d0-66d0-4d55-ab22-074300ea406e_2816x1536.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!voPE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F757161d0-66d0-4d55-ab22-074300ea406e_2816x1536.png" width="1456" height="794" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/757161d0-66d0-4d55-ab22-074300ea406e_2816x1536.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:794,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:5457887,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.systemoverflow.com/i/183532597?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F757161d0-66d0-4d55-ab22-074300ea406e_2816x1536.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!voPE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F757161d0-66d0-4d55-ab22-074300ea406e_2816x1536.png 424w, https://substackcdn.com/image/fetch/$s_!voPE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F757161d0-66d0-4d55-ab22-074300ea406e_2816x1536.png 848w, https://substackcdn.com/image/fetch/$s_!voPE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F757161d0-66d0-4d55-ab22-074300ea406e_2816x1536.png 1272w, https://substackcdn.com/image/fetch/$s_!voPE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F757161d0-66d0-4d55-ab22-074300ea406e_2816x1536.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.systemoverflow.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.systemoverflow.com/subscribe?"><span>Subscribe now</span></a></p><p>DrP addresses these challenges through a platform approach rather than a tool approach. Instead of replacing human investigation, it provides infrastructure to capture, scale, and automate investigation workflows.</p><h3><strong>The SDK: Codifying Investigation Logic</strong></h3><p>At the core is DrP&#8217;s SDK, which lets engineers author <strong>analyzers</strong> (automated investigation playbooks) in Python or PHP. The SDK provides a <strong>Context class</strong>, a key-value dictionary for storing investigation parameters like alert ID, service name, threshold violations, and telemetry data locations. Input APIs capture and validate these parameters, while any inferred values can be dynamically added during execution.</p><p>Critically, DrP provides <strong>declarative, strongly typed APIs</strong> to query data sources including time series databases, analytical databases, data warehouses, and log databases. Instead of writing raw SQL strings that are difficult to maintain and debug, engineers use type-safe APIs tailored to common investigation patterns. This eliminates hardcoded queries and enables easy reuse across analyzers.</p><p>After analysis completes, outputs are captured in a structured <strong>Findings class</strong> that supports flexible rendering and evidence inclusion. Findings can output plain text or machine-readable formats including Thrift payloads with self-describing schemas. These structures facilitate metadata addition for standardized UI widgets and custom React components, enabling downstream processing and analytics.</p><h3><strong>Analysis Libraries: Scaling Investigation Intelligence</strong></h3><p>Services generate massive amounts of observability data. DrP includes scalable analysis algorithms based on statistical and ML techniques:</p><p><strong>Dimensional analysis</strong> helps isolate issues across multiple dimensions (region, endpoint, cluster). For the most frequent repeated investigations, a pre-aggregation layer can reduce dataset size by up to 500X, significantly speeding up real-time, latency-sensitive investigations.</p><p><strong>ML-based event isolation</strong> addresses a common cause of incidents: code changes and config deployments. The library ranks thousands of code and config change events using signals like text matching, time correlation with alerts, and on-call context. On average, this filters out the majority of uninteresting events, surfacing the most suspicious ones with confidence annotations explaining the ranking.</p><p><strong>Time series correlation</strong> helps identify relationships between metrics across different services and data sources.</p><blockquote><p><em><strong>The analysis libraries provide both rule-based and ML-based techniques, but pure ML systems have limitations in data quality and customization. Meta learned that combining rule-based suggestions from community expertise with AI, augmented by dashboards for visualization, works better than purely automated approaches.</strong></em></p></blockquote><h3><strong>Analyzer Chaining: Composing Investigations</strong></h3><p>Services depend on other services. When investigating a frontend issue, you often need to check if backend dependencies are healthy. DrP solves this with <strong>analyzer chaining</strong>, allowing analyzers to call other analyzers in a sequence or DAG (Directed Acyclic Graph).</p><p>Key capabilities include: passing inputs and context to dependent analyzers with temporary overrides for additional parameters; flexible outputs via the Findings class that calling analyzers can parse for relevant information; and lazy import of analyzers for dynamic chaining without upfront latency. Cross-platform support allows chaining between PHP and Python analyzers.</p><p>This promotes analyzer reuse, with over 21% of analyzers using chaining. Using lines of code as a measure, analyzer chaining provides 3x improvement for typical service debugging use cases. Power users report 5-10x faster development after migrating from ad-hoc solutions.</p><h3><strong>The Scalable Backend</strong></h3><p>DrP maintains 99.9% backend availability while processing massive scale. The backend uses a MySQL-backed queue store with fields for request ID, timestamp, analyzer identifier, context, and status. Worker tiers run executors that parse requests and run analyzers in sandbox environments, with results returning asynchronously via callbacks.</p><p>A key challenge: with 2000+ analyzers constantly in churn, packaging all into one binary increases size and load time, and creates noisy neighbor issues where one analyzer failure affects others. Instead, DrP creates smaller <strong>analyzer groups</strong> based on expected affinity, each with its own binary.</p><p>When a request arrives, the system identifies the analyzer group, dynamically fetches the binary, and launches it as a subprocess. Since 85% of traffic comes from the top 10% of analyzers, those binaries are pre-loaded at startup while others are lazy-loaded. For the most frequently used analyzers, they&#8217;re embedded directly in the executor binary for negligible overhead. This provides a balance of quick startup and acceptable delays for dynamic fetching.</p><h3><strong>Workflow Integration: Bringing Analysis to Engineers</strong></h3><p>DrP integrates directly into Meta&#8217;s alerting and incident management systems. When an alert triggers, it auto-executes associated analyzers without engineer intervention. Investigation results appear immediately on the alert page, providing context before the on-call engineer even acknowledges the page. The process from alert to analysis output typically takes a few minutes, providing near real-time analysis.</p><p>This integration is crucial. If engineers need to log into a separate system, select an analyzer, and wait for results, adoption suffers. By embedding DrP into existing workflows, Meta ensures the path of least resistance is using automated investigation. Additionally, a standalone UI and CLI are available for ad-hoc investigations, used by over 450 unique users per week.</p><h3><strong>Post-Processing: Closing the Loop</strong></h3><p>After analysis completes, DrP&#8217;s post-processing tier executes automated actions based on results: creating incident tickets with pre-filled context, generating PRs to fix configuration drift, annotating alerts with likely root causes, or triggering remediation workflows.</p><p>The <strong>DrP Insights</strong> system periodically analyzes historical analyzer outputs to identify and rank top alert causes, helping teams prioritize reliability improvements. Instead of just reacting to individual incidents, teams can see aggregated patterns and invest in fixing root causes.</p><div><hr></div><h2><strong>Quality Assurance: The Backtesting Framework</strong></h2><p>Testing analyzers is challenging. There&#8217;s no good way to record past incidents, and unit tests miss coverage due to dynamic investigation paths. Meta developed a <strong>novel backtesting mechanism</strong>: they retain inputs and outputs from past analyses (default 30 days), enabling integration tests on historical data for modified analyzers.</p><p>These tests filter out non-logic errors, highlighting actual code change issues. Automated in the PR review process, they block PRs until errors are fixed. Combined with canary testing that runs a sample of production traffic before deployment, this has greatly improved analyzer quality and prevented deployment of buggy analyzers.</p><div><hr></div><h2><strong>Trade-offs and Lessons Learned</strong></h2><p><strong>Assist versus full automation</strong>: Meta initially aimed for complete automation but pivoted to an assistive approach. Statistical and ML analysis have limitations and produce false positives. Engineers don&#8217;t always trust fully automated systems. And keeping analyzers updated with evolving systems is difficult. DrP now offers insights and recommendations that engineers validate, balancing automation with human expertise.</p><blockquote><p><em><strong>Adoption depth matters more than usage. Teams with fewer than 5 analyzers see 10-15% MTTR improvement. Teams with 10+ analyzers consistently achieve 50-80% reductions. One team reduced MTTR from 771 hours to 139 hours (82% improvement) after building 136 analyzers.</strong></em></p></blockquote><p><strong>Data quality is everything</strong>: Seamless investigation requires quality data and metadata in telemetry systems. Meta faced issues correlating data from different sources and lacked structured metadata for service dependencies or data lineage, limiting downstream correlations.</p><p><strong>Community-driven development</strong>: DrP&#8217;s success came from democratizing analyzer development. The team bootstrapped adoption by building analyzers for common investigations (services infrastructure, hardware), then developed the SDK for teams to build custom analyzers and chain them together. The engaged community effort was essential for scaling across 300+ teams.</p><p><strong>Analyzer maintenance</strong>: Like any software, analyzers need long-term maintenance. Teams need to estimate the right time to invest. If investigations are simple and repetitive, dashboards may be more effective. As complexity and team size grow, analyzers add more value.</p><div><hr></div><h2><strong>System Design Patterns Worth Noting</strong></h2><p>DrP demonstrates several architectural patterns that appear frequently in system design:</p><p><strong>Workflow orchestration with DAGs</strong>: The analyzer chaining model mirrors how systems like Airflow or Temporal handle complex workflows. Each analyzer is a node that can invoke dependencies, pass context, and aggregate results. This pattern appears whenever you need to coordinate multi-step processes with dependencies.</p><p><strong>Queue-based async processing</strong>: The MySQL-backed queue with worker pools is a classic pattern for handling variable load. Requests are decoupled from execution, allowing the system to handle bursts (like widespread incidents triggering hundreds of alerts) without blocking callers.</p><p><strong>Lazy loading for scale</strong>: Pre-loading the top 10% of analyzers that handle 85% of traffic while lazy-loading the rest is a practical application of the Pareto principle. This pattern applies to any system with skewed access patterns, from CDN caching to database connection pools.</p><p><strong>Structured output contracts</strong>: The Findings class with Thrift schemas enables loose coupling between analyzers and consumers (UIs, post-processors, other analyzers). This is the same principle behind API contracts and schema registries in event-driven architectures.</p><div><hr></div><p><em>Based on Meta Engineering blog: </em><a href="https://engineering.fb.com/2025/12/19/data-infrastructure/drp-metas-root-cause-analysis-platform-at-scale/">DrP: Meta&#8217;s Root Cause Analysis Platform at Scale</a></p><p>Master system design concepts @ <strong><a href="https://www.systemoverflow.com">System Overflow</a></strong></p>]]></content:encoded></item><item><title><![CDATA[How Dropbox Designed Evaluation-First Infrastructure for Conversational AI]]></title><description><![CDATA[Using Dropbox Dash as a case study to design datasets, metrics, and evaluation platforms that gate LLM deployments like CI.]]></description><link>https://blog.systemoverflow.com/p/how-dropbox-designed-evaluation-first</link><guid isPermaLink="false">https://blog.systemoverflow.com/p/how-dropbox-designed-evaluation-first</guid><dc:creator><![CDATA[System Overflow]]></dc:creator><pubDate>Fri, 02 Jan 2026 10:25:17 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!FTeC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e2aeb5a-689a-434e-976d-56ea51f0248f_2816x1536.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Most teams evaluate LLM applications the way they evaluated traditional ML: compute an accuracy score, eyeball some examples, and ship. Then production hallucinations start appearing, and nobody can trace which change caused them.</p><p>Dropbox faced this problem with <a href="https://dash.dropbox.com/">Dash</a>, their conversational AI that answers questions about files, wikis, and connected tools. Their solution was to treat evaluation as infrastructure, not an afterthought. This article breaks down how they designed it.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.systemoverflow.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.systemoverflow.com/subscribe?"><span>Subscribe now</span></a></p><h2>Why Traditional Metrics Failed</h2><p>Dash is not a single model. It is a pipeline:</p><pre><code>user query &#8594; intent classification &#8594; document retrieval &#8594; ranking &#8594; prompt construction &#8594; LLM inference &#8594; safety filters</code></pre><p>Each stage is non-deterministic. Changing retrieval parameters alters which documents reach the model. That interacts with the prompt template. Which affects how often the model cites sources correctly. You cannot reason about quality by looking at any component in isolation.</p><p>Early on, Dropbox engineers relied on classic NLP metrics: BLEU, ROUGE, BERTScore, embedding similarity. These measure surface overlap or semantic proximity, not production correctness.</p><blockquote><p><em><strong>The core problem:</strong> A high ROUGE score can hide a hallucinated filename. Strong embedding similarity can correspond to an answer that ignored the question. These metrics cannot answer: did the response actually come from the user&#8217;s documents? Were claims supported by retrieved context? Were the correct files cited?</em></p></blockquote><p>As soon as Dropbox tried to use these metrics to gate real deployments, they broke down.</p><h2>The Flight Control Analogy</h2><p>Consider how you would certify a new autopilot system. You would never approve it only by checking that steering roughly matches a reference trajectory. You also need alarms for altitude, fuel, structural stress, and dozens of other dimensions.</p><p>An LLM evaluation system works the same way. It must be a <strong>network of alarmed checks</strong>, not a single similarity score. Quality is multi-dimensional and context-dependent, but your system must compress it into automated checks that decide whether a change can ship.</p><p>Dropbox had additional constraints:</p><ul><li><p>Evaluate on both public benchmarks and Dropbox-specific content</p></li><li><p>Every model, retriever, or prompt change must behave like production code with tests wired into CI</p></li><li><p>Scale evaluation to many experiments without drowning in manual labeling</p></li></ul><h2>The Three-Layer Architecture</h2><p>Dropbox built an evaluation platform that wraps the LLM application. It has three layers: curated datasets, LLM-powered metrics, and a CI-integrated orchestration platform.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FTeC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e2aeb5a-689a-434e-976d-56ea51f0248f_2816x1536.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FTeC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e2aeb5a-689a-434e-976d-56ea51f0248f_2816x1536.png 424w, https://substackcdn.com/image/fetch/$s_!FTeC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e2aeb5a-689a-434e-976d-56ea51f0248f_2816x1536.png 848w, https://substackcdn.com/image/fetch/$s_!FTeC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e2aeb5a-689a-434e-976d-56ea51f0248f_2816x1536.png 1272w, https://substackcdn.com/image/fetch/$s_!FTeC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e2aeb5a-689a-434e-976d-56ea51f0248f_2816x1536.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FTeC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e2aeb5a-689a-434e-976d-56ea51f0248f_2816x1536.png" width="1456" height="794" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4e2aeb5a-689a-434e-976d-56ea51f0248f_2816x1536.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:794,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:5568836,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.systemoverflow.com/i/183218943?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e2aeb5a-689a-434e-976d-56ea51f0248f_2816x1536.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!FTeC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e2aeb5a-689a-434e-976d-56ea51f0248f_2816x1536.png 424w, https://substackcdn.com/image/fetch/$s_!FTeC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e2aeb5a-689a-434e-976d-56ea51f0248f_2816x1536.png 848w, https://substackcdn.com/image/fetch/$s_!FTeC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e2aeb5a-689a-434e-976d-56ea51f0248f_2816x1536.png 1272w, https://substackcdn.com/image/fetch/$s_!FTeC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e2aeb5a-689a-434e-976d-56ea51f0248f_2816x1536.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.systemoverflow.com/pricing&quot;,&quot;text&quot;:&quot;Upgrade to Pro - 10% EXTRA OFF&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.systemoverflow.com/pricing"><span>Upgrade to Pro - 10% EXTRA OFF</span></a></p><h3>Layer 1: Dataset Curation</h3><p>Dropbox combined two sources:</p><p><strong>Public QA datasets.</strong> Natural Questions, MS MARCO, and MuSiQue stress-test retrieval, multi-document answers, and multi-hop reasoning. These provide reproducible baselines.</p><p><strong>Internal datasets from Dash usage.</strong> From logs, they created representative query sets (anonymized, ranked real queries) and representative content sets (popular files, docs, connected sources). From that content, they generated synthetic questions and answers using LLMs, covering tables, images, tutorials, and factual lookups.</p><p>Together, these datasets approximate the long tail of real usage in a reproducible form you can re-run in every experiment.</p><h3>Layer 2: LLM-as-Judge Metrics</h3><p>Classic metrics still run as quick sanity checks. But the core of the system is <strong>LLM-as-judge</strong>.</p><p>A judge model receives four inputs: the user query, the candidate answer from Dash, the retrieved context, and optionally a hidden reference answer. It scores specific dimensions:</p><pre><code>{
&#8220;factual_accuracy&#8221;: 4,
&#8220;citation_correctness&#8221;: 1,
&#8220;clarity&#8221;: 5,
&#8220;formatting&#8221;: 4,
&#8220;explanation&#8221;: &#8220;Answer was accurate but referenced a source not in context.&#8221;
}</code></pre><p>Dropbox treats these judges like software modules: versioned, tuned against small human-labeled calibration sets, and periodically re-checked for agreement with human evaluators.</p><blockquote><p><strong>Key insight:</strong> Evaluating the evaluators becomes part of the loop. Judge models can drift or develop blind spots. Periodic human spot-checks keep them calibrated.</p></blockquote><h3>Layer 3: Evaluation Platform as CI</h3><p>The platform works like CI for LLM behavior. A central store holds datasets and judge configurations. An orchestrator runs suites against any pipeline version or prompt template.</p><p><strong>The test pyramid:</strong></p><ul><li><p><strong>Pull requests</strong> &#8212; Fast regression subset, blocks merge on failures</p></li><li><p><strong>Staging and nightly</strong> &#8212; Full curated suites</p></li><li><p><strong>Production</strong> &#8212; Sampled live traffic re-run through judges to monitor drift</p></li></ul><p>The same evaluation logic runs everywhere, giving consistency and traceability across experiments and releases.</p><h2>Enforcement Levels</h2><p>Not all metrics are equal. Dropbox separates them into three tiers:</p><ol><li><p><strong>Boolean gates</strong> &#8212; Hard fails. Examples: &#8220;citations present&#8221;, &#8220;source file exists&#8221;. A single failure blocks deployment.</p></li><li><p><strong>Scalar budgets</strong> &#8212; Thresholds that cannot regress. Examples: minimum source F1, p95 latency ceiling, cost per query. Changes that degrade these are blocked.</p></li><li><p><strong>Rubric scores</strong> &#8212; Softer properties like tone, narrative quality, formatting. Tracked in dashboards but do not block deployment.</p></li></ol><p>This separation prevents promising experiments from being blocked by minor rubric regressions while still protecting users from factuality and citation failures.</p><h2>Trade-offs</h2><p>Dropbox&#8217;s choices came with clear trade-offs.</p><p><strong>LLM judges add cost and drift risk.</strong> They provide flexibility: you can encode complex rubrics and adapt to new tasks without training task-specific scorers. But they are another model that can degrade. Dropbox uses smaller, specialized judge models when possible and relies on human spot-checks for calibration.</p><p><strong>CI integration slows iteration.</strong> Wiring evaluations into every pull request increases reliability but can bottleneck development if suites are too heavy. Dropbox addresses this with the test pyramid: tiny fast subsets for PRs, full suites for staging and nightly runs.</p><p><strong>Hard gates can block good changes.</strong> A change might hurt one metric while improving others. Separating boolean gates, scalar budgets, and rubric scores gives flexibility. Safety-critical dimensions block; UX dimensions inform.</p><p><strong>Requires representative data.</strong> This approach assumes you can collect internal usage data and have some human labeling capacity. In domains with sparse data or strict privacy rules, you may need heavier reliance on public datasets and synthetic generation.</p><h2>When This Pattern Applies</h2><p><strong>Use evaluation-as-infrastructure when:</strong></p><ul><li><p>Your LLM system has multiple interacting stages (retrieval, ranking, generation)</p></li><li><p>Quality is multi-dimensional (accuracy, citations, latency, cost)</p></li><li><p>You need to gate deployments on behavior, not just unit tests</p></li><li><p>Multiple engineers iterate on prompts, models, and retrievers in parallel</p></li><li><p>You have access to representative usage data or can generate synthetic queries</p></li></ul><p><strong>You can skip this complexity when:</strong></p><ul><li><p>Your LLM usage is simple (single prompt, no retrieval)</p></li><li><p>Quality can be measured with a single metric</p></li><li><p>You have low deployment frequency and can manually review each change</p></li></ul><h2>The Takeaway</h2><p>Dropbox&#8217;s work on Dash shows that for LLM applications, evaluation is core system design, not an afterthought. By curating realistic datasets, using LLMs as structured judges, and wiring evaluations into CI and production, they turned a fragile text box into a monitored, testable system.</p><p>The patterns connect directly to classic system design: test pyramids, observability, deployment gates. The difference is that LLM behavior is probabilistic, so your checks must be probabilistic too. Treat datasets as versioned assets. Design judge prompts as reusable modules. Wrap your pipeline in an evaluation platform that can say no to unsafe changes.</p><div><hr></div><p><strong>Reference:</strong> <a href="https://dropbox.tech/machine-learning/practical-blueprint-evaluating-conversational-ai-at-scale-dash">A practical blueprint for evaluating conversational AI at scale</a>.<br>Learn more about ML System Design @ <a href="https://www.systemoverflow.com">System Overflow</a></p>]]></content:encoded></item><item><title><![CDATA[Parquet Internals: Why Your File Format Choice Determines Query Speed]]></title><description><![CDATA[How columnar storage, encoding, and statistics work together to speed up your queries.]]></description><link>https://blog.systemoverflow.com/p/parquet-internals-why-your-file-format</link><guid isPermaLink="false">https://blog.systemoverflow.com/p/parquet-internals-why-your-file-format</guid><dc:creator><![CDATA[System Overflow]]></dc:creator><pubDate>Tue, 30 Dec 2025 16:24:28 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!7ZEr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F074e8872-1b40-451a-b851-6428bd750e3b_2816x1536.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Most engineers treat <a href="https://www.systemoverflow.com/learn/data-storage-formats/parquet-internals">Parquet</a> as a black box. Write DataFrame, read DataFrame, hope it&#8217;s fast. But the difference between a well-configured Parquet setup and a naive one can be the difference between queries that take seconds and queries that take minutes.</p><p>Understanding what happens inside the file is how you unlock that performance.</p><h2>Why Storage Layout Matters</h2><p>At the logical level, data is simple: tables with rows and columns. But how you physically arrange bytes on disk has massive performance implications.</p><p>Consider a typical analytics query: &#8220;What&#8217;s the average order value by country?&#8221; You need two columns out of a wide table with dozens of fields.</p><p><strong>Row-wise storage</strong> (how traditional databases work) lays data out like this:</p><pre><code>[row1_col1, row1_col2, ... row1_colN] [row2_col1, row2_col2, ... row2_colN] ...</code></pre><p>To read your two columns, you scan through every column for every row. Most of that I/O is wasted on data you&#8217;ll immediately discard.</p><p><strong>Columnar storage</strong> inverts the layout:</p><pre><code>[row1_col1, row2_col1, row3_col1, ...] [row1_col2, row2_col2, ...] ...</code></pre><p>Now reading two columns means reading two contiguous blocks. You only touch the data you actually need. Query engines call this projection pushdown, and columnar formats make it efficient.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7ZEr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F074e8872-1b40-451a-b851-6428bd750e3b_2816x1536.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7ZEr!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F074e8872-1b40-451a-b851-6428bd750e3b_2816x1536.png 424w, https://substackcdn.com/image/fetch/$s_!7ZEr!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F074e8872-1b40-451a-b851-6428bd750e3b_2816x1536.png 848w, https://substackcdn.com/image/fetch/$s_!7ZEr!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F074e8872-1b40-451a-b851-6428bd750e3b_2816x1536.png 1272w, https://substackcdn.com/image/fetch/$s_!7ZEr!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F074e8872-1b40-451a-b851-6428bd750e3b_2816x1536.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7ZEr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F074e8872-1b40-451a-b851-6428bd750e3b_2816x1536.png" width="1456" height="794" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/074e8872-1b40-451a-b851-6428bd750e3b_2816x1536.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:794,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:4748388,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.systemoverflow.com/i/182967954?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F074e8872-1b40-451a-b851-6428bd750e3b_2816x1536.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!7ZEr!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F074e8872-1b40-451a-b851-6428bd750e3b_2816x1536.png 424w, https://substackcdn.com/image/fetch/$s_!7ZEr!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F074e8872-1b40-451a-b851-6428bd750e3b_2816x1536.png 848w, https://substackcdn.com/image/fetch/$s_!7ZEr!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F074e8872-1b40-451a-b851-6428bd750e3b_2816x1536.png 1272w, https://substackcdn.com/image/fetch/$s_!7ZEr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F074e8872-1b40-451a-b851-6428bd750e3b_2816x1536.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.systemoverflow.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.systemoverflow.com/subscribe?"><span>Subscribe now</span></a></p><p></p><blockquote><p><strong>The tradeoff:</strong> Row-wise storage excels at transactional workloads (insert a record, update a field). Columnar storage excels at analytical workloads (aggregate millions of rows, but only a few columns). Different access patterns, different optimal layouts.</p></blockquote><h2>The Locality Problem with Pure Columnar</h2><p>Imagine reconstructing a single row from a 100GB columnar file with 10 columns. Column A is in the first 10GB. Column B is 10GB away. Column J is 90GB away. You&#8217;ve lost all data locality.</p><p>Modern hardware is built around locality. CPU caches, memory prefetching, disk read-ahead - they assume if you read address X, you&#8217;ll want X+1 soon. Scattered access defeats these optimizations.</p><p>Parquet solves this with a <strong>hybrid model</strong>: divide rows into groups (typically 128MB), then store each group in columnar format. You get columnar benefits within each group, plus locality across groups.</p><h2>Inside a Parquet File</h2><p>A Parquet dataset is often a directory containing multiple .parquet files. Within each file:</p><p><strong>Row Groups</strong> are horizontal partitions, typically 128MB each. They contain a subset of rows with all their columns.</p><p><strong>Column Chunks</strong> are vertical partitions within a row group. Each chunk contains all values for one column in that group.</p><p><strong>Data Pages</strong> are the actual storage units within column chunks - encoded values plus metadata like min/max statistics.</p><p><strong>Footer</strong> stores all metadata: schema, row group locations, and statistics. Reading the footer first lets you plan which parts of the file to actually read.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!rtpo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec8b6646-ae5b-4e29-9292-d759718eef8c_2816x1536.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!rtpo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec8b6646-ae5b-4e29-9292-d759718eef8c_2816x1536.png 424w, https://substackcdn.com/image/fetch/$s_!rtpo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec8b6646-ae5b-4e29-9292-d759718eef8c_2816x1536.png 848w, https://substackcdn.com/image/fetch/$s_!rtpo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec8b6646-ae5b-4e29-9292-d759718eef8c_2816x1536.png 1272w, https://substackcdn.com/image/fetch/$s_!rtpo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec8b6646-ae5b-4e29-9292-d759718eef8c_2816x1536.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!rtpo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec8b6646-ae5b-4e29-9292-d759718eef8c_2816x1536.png" width="1456" height="794" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ec8b6646-ae5b-4e29-9292-d759718eef8c_2816x1536.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:794,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:5242767,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.systemoverflow.com/i/182967954?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec8b6646-ae5b-4e29-9292-d759718eef8c_2816x1536.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!rtpo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec8b6646-ae5b-4e29-9292-d759718eef8c_2816x1536.png 424w, https://substackcdn.com/image/fetch/$s_!rtpo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec8b6646-ae5b-4e29-9292-d759718eef8c_2816x1536.png 848w, https://substackcdn.com/image/fetch/$s_!rtpo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec8b6646-ae5b-4e29-9292-d759718eef8c_2816x1536.png 1272w, https://substackcdn.com/image/fetch/$s_!rtpo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec8b6646-ae5b-4e29-9292-d759718eef8c_2816x1536.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>How Parquet Compresses Data</h2><p>Columnar layout enables compression techniques that don&#8217;t work well on row-wise data. When values from the same column sit together, they share the same type and often similar distributions.</p><p>Parquet applies three techniques in sequence:</p><p><strong>1. Dictionary Encoding</strong></p><pre><code>Original: [&#8221;USA&#8221;, &#8220;France&#8221;, &#8220;Germany&#8221;, &#8220;Netherlands&#8221;, &#8220;Netherlands&#8221;, &#8220;Netherlands&#8221;]

Dictionary: {0: &#8220;USA&#8221;, 1: &#8220;France&#8221;, 2: &#8220;Germany&#8221;, 3: &#8220;Netherlands&#8221;}
Encoded: [0, 1, 2, 3, 3, 3]</code></pre><p>Repeated string values become small integer references. Within each row group, a &#8220;country&#8221; column stores each unique value just once in its dictionary.</p><p><strong>2. Run-Length Encoding</strong></p><pre><code>Before: [3, 3, 3]
After: (value=3, count=3)</code></pre><p>Consecutive identical values collapse into (value, count) pairs. Especially powerful on sorted data where similar values cluster.</p><p><strong>3. Bit Packing</strong></p><pre><code>4 unique values in dictionary = 2 bits needed per reference (not 32)</code></pre><p>With a small dictionary, each reference needs only log2(dictionary_size) bits instead of a full integer.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!L2mj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9838d4b2-758b-435e-a030-b53988751755_2816x1536.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!L2mj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9838d4b2-758b-435e-a030-b53988751755_2816x1536.png 424w, https://substackcdn.com/image/fetch/$s_!L2mj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9838d4b2-758b-435e-a030-b53988751755_2816x1536.png 848w, https://substackcdn.com/image/fetch/$s_!L2mj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9838d4b2-758b-435e-a030-b53988751755_2816x1536.png 1272w, https://substackcdn.com/image/fetch/$s_!L2mj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9838d4b2-758b-435e-a030-b53988751755_2816x1536.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!L2mj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9838d4b2-758b-435e-a030-b53988751755_2816x1536.png" width="1456" height="794" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9838d4b2-758b-435e-a030-b53988751755_2816x1536.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:794,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:4622701,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.systemoverflow.com/i/182967954?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9838d4b2-758b-435e-a030-b53988751755_2816x1536.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!L2mj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9838d4b2-758b-435e-a030-b53988751755_2816x1536.png 424w, https://substackcdn.com/image/fetch/$s_!L2mj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9838d4b2-758b-435e-a030-b53988751755_2816x1536.png 848w, https://substackcdn.com/image/fetch/$s_!L2mj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9838d4b2-758b-435e-a030-b53988751755_2816x1536.png 1272w, https://substackcdn.com/image/fetch/$s_!L2mj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9838d4b2-758b-435e-a030-b53988751755_2816x1536.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><blockquote><p><strong>Watch out:</strong> Dictionary encoding has a size limit per column chunk. If you exceed it (too many unique values), Parquet falls back to plain encoding and loses compression benefits. Fix this by increasing dictionary page size or decreasing row group size.</p></blockquote><p>On top of encoding, Parquet supports page-level compression (Snappy, GZIP, LZ4). A benchmark from S3: reading 10GB uncompressed took ~14 seconds; the same data with Snappy compression took ~8 seconds. Smaller files mean less I/O, even accounting for decompression CPU cost.</p><h2>Skipping Data with Statistics</h2><p>Compression reduces file size. But the bigger wins come from not reading data at all.</p><p>Every row group stores min/max statistics in the footer. For a query like <code>WHERE user_id &gt; 1000</code>, Parquet checks each row group before reading:</p><blockquote><p><strong>Row Group 0</strong> (min: 0, max: 900)<br>&#8594; <strong>SKIP</strong> - max value 900 is below 1000</p><p><strong>Row Group 1</strong> (min: 850, max: 2100)<br>&#8594; <strong>READ</strong> - range overlaps with predicate</p><p><strong>Row Group 2</strong> (min: 1, max: 400)<br>&#8594; <strong>SKIP</strong> - max value 400 is below 1000</p></blockquote><p>Each skipped row group is 128MB you don&#8217;t read. On sorted data, row group skipping can eliminate most of your I/O.</p><p><strong>Important:</strong> This only works well when data is sorted or clustered on the filter column. Randomly distributed data produces wide min/max ranges that overlap with most predicates, defeating the optimization.</p><p>For equality predicates (<code>WHERE country = 'Germany'</code>), Parquet offers <strong>dictionary filtering</strong>: check if the value exists in the column chunk&#8217;s dictionary before reading any data pages. If it&#8217;s absent, skip with certainty.</p><h2>The Small Files Problem</h2><p>Every Parquet file has overhead: connection setup, reader instantiation, footer parsing. With a few large files, this overhead is negligible. With thousands of small files, it dominates query time.</p><pre><code><strong>Benchmark (10GB dataset on S3):</strong>

16 files: ~12.5 seconds
1,024 files: ~19 seconds

Same data, 50% slower due to file overhead.</code></pre><p>Small files accumulate naturally. Hourly ETL jobs create a new file each run. Streaming ingestion creates small batches. Partitioning on high-cardinality columns fragments data across directories. After months, you have tens of thousands of files.</p><p>The opposite extreme is also problematic. One team consolidated 250GB into a single file. A simple <code>COUNT(*)</code> went from 5 minutes to over an hour. The culprit: footer processing. Massive files have massive metadata (thousands of row groups), and Parquet&#8217;s footer parsing isn&#8217;t optimized for that scale.</p><blockquote><p><strong>Sweet spot:</strong> Target files in the 128MB to 1GB range. Compact small files periodically. Split oversized files.</p></blockquote><h2>Directory Partitioning</h2><p>When you know your query patterns upfront, embed predicates in the directory structure:</p><pre><code>/data/events/
  date=2024-01-15/
    part-00000.parquet
  date=2024-01-16/
    part-00000.parquet</code></pre><p>A query filtering on date doesn&#8217;t open irrelevant directories. Predicate evaluation becomes file listing.</p><p>The tradeoff: partitioning on high-cardinality columns (user_id, timestamp) creates thousands of directories with tiny files. Use partitioning for low-cardinality columns you frequently filter on (date, region, status).</p><h2>Practical Optimization Checklist</h2><p><strong>Reduce file size:</strong></p><ul><li><p>Enable compression (Snappy is usually the right default)</p></li><li><p>Monitor dictionary encoding fallback on high-cardinality columns</p></li><li><p>Only SELECT columns you need - projection pushdown requires it</p></li></ul><p><strong>Enable data skipping:</strong></p><ul><li><p>Sort data on commonly filtered columns for tighter min/max ranges</p></li><li><p>Use typed predicates matching column types (avoid implicit casting)</p></li><li><p>Partition by low-cardinality, frequently-filtered columns</p></li></ul><p><strong>Manage file count:</strong></p><ul><li><p>Compact small files from incremental writes</p></li><li><p>Avoid single massive files (footer parsing bottleneck)</p></li><li><p>Consider Delta Lake or Iceberg for automatic compaction and better metadata handling</p></li></ul><h2>The Takeaway</h2><p>Parquet&#8217;s performance comes from a set of deliberate tradeoffs: columnar layout for projection pushdown, encoding for compression, statistics for skipping. These optimizations are automatic, but they only work well when your data organization matches your access patterns.</p><p>Sort your data on filter columns. Keep file sizes reasonable. Select only the columns you need. The format will do the rest.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.systemoverflow.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.systemoverflow.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><p>Go deeper on data engineering fundamentals @ <a href="https://www.systemoverflow.com">System Overflow</a> </p>]]></content:encoded></item><item><title><![CDATA[🚀 Announcing: Data Engineering Track on System Overflow]]></title><description><![CDATA[We've just launched our third learning track: Data Engineering.]]></description><link>https://blog.systemoverflow.com/p/announcing-data-engineering-track</link><guid isPermaLink="false">https://blog.systemoverflow.com/p/announcing-data-engineering-track</guid><dc:creator><![CDATA[System Overflow]]></dc:creator><pubDate>Sun, 28 Dec 2025 13:27:28 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Kg77!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8c3f1fc-aa66-495d-8824-4bd23bc91d8c_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>System Overflow now has three complete tracks: <strong>System Design, ML Design, and Data Engineering.</strong></p><div><hr></div><h2>Why Data Engineering?</h2><p>Modern applications generate <strong>massive data volumes</strong>. Whether you&#8217;re building real-time analytics, ML pipelines, or data warehouses, you need to design systems that can <strong>ingest, transform, and serve data reliably at scale</strong>.</p><p>Data Engineering interviews test your ability to make design decisions under constraints. System Overflow focuses on the trade-offs and patterns that matter in real interviews.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Kg77!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8c3f1fc-aa66-495d-8824-4bd23bc91d8c_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Kg77!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8c3f1fc-aa66-495d-8824-4bd23bc91d8c_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!Kg77!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8c3f1fc-aa66-495d-8824-4bd23bc91d8c_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!Kg77!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8c3f1fc-aa66-495d-8824-4bd23bc91d8c_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!Kg77!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8c3f1fc-aa66-495d-8824-4bd23bc91d8c_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Kg77!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8c3f1fc-aa66-495d-8824-4bd23bc91d8c_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a8c3f1fc-aa66-495d-8824-4bd23bc91d8c_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2422312,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://blog.systemoverflow.com/i/182746071?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8c3f1fc-aa66-495d-8824-4bd23bc91d8c_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Kg77!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8c3f1fc-aa66-495d-8824-4bd23bc91d8c_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!Kg77!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8c3f1fc-aa66-495d-8824-4bd23bc91d8c_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!Kg77!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8c3f1fc-aa66-495d-8824-4bd23bc91d8c_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!Kg77!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8c3f1fc-aa66-495d-8824-4bd23bc91d8c_1536x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h2>What&#8217;s Inside the Track</h2><h3>&#127919; 12 Core Areas &#8226; 90+ Topics &#8226; 400+ Learning Cards</h3><p><strong>Data Modeling &amp; Schema Design</strong><br>Dimensional modeling, normalization trade-offs, time-series patterns, slowly changing dimensions</p><p><strong>Data Pipelines &amp; Orchestration</strong><br>DAG-based orchestration (Airflow, Prefect), idempotency, backfills, cross-pipeline dependencies</p><p><strong>Storage Formats &amp; Optimization</strong><br>Parquet/Avro/ORC internals, compression algorithms, encoding strategies, partitioning patterns</p><p><strong>Batch vs Stream Processing</strong><br>Lambda/Kappa architectures, micro-batching, hybrid processing models</p><p><strong>Distributed Data Processing</strong><br>Spark execution model, Catalyst optimizer, distributed joins, shuffle optimization, memory tuning</p><p><strong>Stream Processing Architectures</strong><br>Kafka Streams, Flink state management, windowing, exactly-once semantics, watermarking</p><p><strong>Data Lakes &amp; Lakehouses</strong><br>Delta Lake/Iceberg/Hudi internals, ACID transactions, metadata catalogs, table formats</p><p><strong>Change Data Capture (CDC)</strong><br>Log-based CDC (binlog, WAL), consistency guarantees, performance at scale</p><p><strong>Real-time Analytics &amp; OLAP</strong><br>Druid/ClickHouse architecture, pre-aggregation patterns, approximate query processing</p><p><strong>Data Quality &amp; Validation</strong><br>Schema validation, data contracts, anomaly detection, reconciliation techniques</p><p><strong>ETL/ELT Patterns</strong><br>Incremental processing, transformation layers (bronze/silver/gold), dbt workflows, deduplication</p><p><strong>Data Governance &amp; Lineage</strong><br>Lineage tracking, access control, data masking, GDPR compliance, catalog systems</p><div><hr></div><h2>How It Works</h2><p>Every topic includes:</p><p>&#9989; <strong>Expert-curated content</strong> with depth that matters in real interviews<br>&#9989; <strong>Trade-off analysis</strong> for making informed design decisions<br>&#9989; <strong>Practical scenarios</strong> from actual production systems<br>&#9989; <strong>Progressive difficulty</strong> with time estimates<br>&#9989; <strong>Implementation patterns</strong> that work at scale</p><p>This isn&#8217;t just theory. It&#8217;s the mental models you need to design data systems that handle billions of events per day.</p><div><hr></div><h2>Who This Is For</h2><p>&#128204; <strong>Senior/Staff/Principal Engineers</strong> preparing for data infrastructure roles<br>&#128204; <strong>Backend Engineers</strong> moving into data platform teams<br>&#128204; <strong>Data Engineers</strong> leveling up their system design skills<br>&#128204; <strong>Anyone building</strong> pipelines, warehouses, or real-time analytics at scale</p><div><hr></div><h2>Get Started Today</h2><p>&#128073; <strong><a href="https://www.systemoverflow.com">www.systemoverflow.com</a></strong></p><p>Join engineers from <strong>FAANG+</strong> companies using System Overflow to level up their design skills.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.systemoverflow.com/pricing&quot;,&quot;text&quot;:&quot;10% OFF - Buy Pro&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.systemoverflow.com/pricing"><span>10% OFF - Buy Pro</span></a></p><div><hr></div><p><strong>Already crushing System Design or ML Design on the platform?</strong> The Data Engineering track is waiting for you.</p><p><strong>New to System Overflow?</strong> Start with any track. All three are designed to work together as you build end-to-end expertise.</p><p>Let&#8217;s design better Systems. &#128640;</p>]]></content:encoded></item><item><title><![CDATA[TPUs: The Chip That Trades Flexibility for Raw ML Performance]]></title><description><![CDATA[The $100 Million Question Nobody Asked]]></description><link>https://blog.systemoverflow.com/p/tpus-the-chip-that-trades-flexibility</link><guid isPermaLink="false">https://blog.systemoverflow.com/p/tpus-the-chip-that-trades-flexibility</guid><dc:creator><![CDATA[System Overflow]]></dc:creator><pubDate>Fri, 26 Dec 2025 16:55:22 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!5BDm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ecc57c1-5f49-42cb-b9fd-dafa80de49b9_2816x1536.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Most engineers think of TPUs as &#8220;Google&#8217;s GPUs.&#8221; They&#8217;re not. TPUs represent a fundamentally different design philosophy: instead of building flexible hardware that handles many workloads adequately, Google built specialized hardware that handles one workload exceptionally.</p><p>To understand TPUs, we need to start with a question: what do neural networks actually do at the hardware level?</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5BDm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ecc57c1-5f49-42cb-b9fd-dafa80de49b9_2816x1536.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5BDm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ecc57c1-5f49-42cb-b9fd-dafa80de49b9_2816x1536.png 424w, https://substackcdn.com/image/fetch/$s_!5BDm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ecc57c1-5f49-42cb-b9fd-dafa80de49b9_2816x1536.png 848w, https://substackcdn.com/image/fetch/$s_!5BDm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ecc57c1-5f49-42cb-b9fd-dafa80de49b9_2816x1536.png 1272w, https://substackcdn.com/image/fetch/$s_!5BDm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ecc57c1-5f49-42cb-b9fd-dafa80de49b9_2816x1536.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5BDm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ecc57c1-5f49-42cb-b9fd-dafa80de49b9_2816x1536.png" width="1456" height="794" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0ecc57c1-5f49-42cb-b9fd-dafa80de49b9_2816x1536.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:794,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:5977561,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://blog.systemoverflow.com/i/182632419?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ecc57c1-5f49-42cb-b9fd-dafa80de49b9_2816x1536.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!5BDm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ecc57c1-5f49-42cb-b9fd-dafa80de49b9_2816x1536.png 424w, https://substackcdn.com/image/fetch/$s_!5BDm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ecc57c1-5f49-42cb-b9fd-dafa80de49b9_2816x1536.png 848w, https://substackcdn.com/image/fetch/$s_!5BDm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ecc57c1-5f49-42cb-b9fd-dafa80de49b9_2816x1536.png 1272w, https://substackcdn.com/image/fetch/$s_!5BDm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ecc57c1-5f49-42cb-b9fd-dafa80de49b9_2816x1536.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.systemoverflow.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.systemoverflow.com/subscribe?"><span>Subscribe now</span></a></p><h2>The Problem TPUs Solve</h2><p>Neural network training and inference are dominated by one operation: matrix multiplication. Forward pass? Multiply weight matrices by activation vectors. Backpropagation? More matrix multiplies to compute gradients. Attention mechanisms? Matrix multiplies between queries, keys, and values.</p><p>GPUs handle this reasonably well because they&#8217;re designed for parallel computation. But GPUs are also designed to run graphics, physics simulations, cryptocurrency mining, and general-purpose computing. All that flexibility comes with overhead: complex instruction decoding, cache hierarchies for unpredictable memory access, branch prediction for conditional code.</p><p>Google asked: what if we threw all that away and built hardware that only does matrix multiplication?</p><h2>The Systolic Array: TPU&#8217;s Core Innovation</h2><p>The answer is the <strong>systolic array</strong>, a computing architecture from the 1980s that fell out of favor for general computing but turns out to be perfect for matrix math.</p><p>Picture a two-dimensional grid of simple processing elements. Each cell does exactly one thing: multiply two numbers and add the result to a running total. No conditionals, no branching, no complex logic.</p><blockquote><p><em><strong>How data flows:</strong> Weights load into the array and stay stationary. Activations flow in from the left, moving one cell right each clock cycle. Partial sums flow downward. By the time data exits the bottom of the array, you have your matrix multiplication result.</em></p></blockquote><p>The term &#8220;systolic&#8221; comes from the heart. Just as blood pulses through your circulatory system in waves, data pulses through the array in a regular, predictable rhythm.</p><p>This predictability is the key insight. Because data flow is fixed, the hardware never waits for memory, never mispredicts a branch, never stalls on a cache miss. Every cycle, every cell is doing useful work.</p><p>Even better, each value gets reused multiple times. A weight sitting in a cell multiplies against every activation that flows past it. An activation moving across a row multiplies against every weight in that row. This <strong>data reuse</strong> dramatically reduces memory bandwidth requirements.</p><h2>What TPUs Give Up</h2><p>This efficiency comes from extreme specialization. Understanding what TPUs <em>can&#8217;t</em> do is just as important as understanding what they excel at.</p><p><strong>No general-purpose computing.</strong> TPUs can&#8217;t run arbitrary code. They only execute tensor operations. Anything else, from data preprocessing to custom logic, runs on a host CPU and communicates with the TPU over PCIe.</p><p><strong>No CUDA, no direct programming.</strong> You don&#8217;t write TPU kernels. Instead, you write TensorFlow or JAX code, and the XLA (Accelerated Linear Algebra) compiler transforms it into TPU instructions. This means automatic optimization, but also less control when things don&#8217;t compile efficiently.</p><p><strong>No flexibility on precision.</strong> TPUs are designed around bfloat16, a 16-bit format optimized for ML. This works well for neural networks, but if your workload needs higher precision, you&#8217;re fighting the hardware.</p><p><strong>No purchasing or on-prem deployment.</strong> TPUs are cloud-only, rented from Google Cloud. You can&#8217;t buy them for your own datacenter.</p><h2>How This Compares to GPUs</h2><p>Now that we understand how TPUs work, the comparison to GPUs becomes clearer. These aren&#8217;t just different products; they&#8217;re different philosophies.</p><ol><li><p><strong>Parallelism model</strong> &#8212; GPUs use SIMT (Single Instruction, Multiple Threads): thousands of threads executing the same instruction on different data. TPUs use systolic data flow: values streaming through a fixed grid. SIMT handles irregular workloads gracefully; systolic arrays maximize efficiency for regular workloads.</p></li><li><p><strong>Memory architecture</strong> &#8212; GPUs use complex cache hierarchies to hide unpredictable memory latency. TPUs use large on-chip buffers with predictable access patterns, eliminating caching overhead entirely.</p></li><li><p><strong>Programmability</strong> &#8212; GPUs let you write custom CUDA kernels with fine-grained control. TPUs require compilation through XLA, which optimizes automatically but limits what you can express.</p></li><li><p><strong>Ecosystem</strong> &#8212; CUDA has 15+ years of libraries, tools, and community knowledge. TPU tooling is younger and entirely controlled by Google.</p></li></ol><p>Neither approach is universally better. They optimize for different assumptions about your workload.</p><h2>Programming TPUs: The XLA Model</h2><p>Since you can&#8217;t program TPUs directly, understanding XLA is essential.</p><p>XLA captures your computation as a graph of operations: matrix multiplies, convolutions, activations, and so on. It then optimizes this graph by fusing operations together, eliminating redundant computation, and arranging memory layout for efficient access. Finally, it generates TPU instructions that map onto the systolic array.</p><blockquote><p><em><strong>The trade-off:</strong> XLA handles optimization automatically, but you lose the ability to hand-tune performance. If an operation compiles poorly, your options are limited compared to CUDA, where you can always write a custom kernel.</em></p></blockquote><p>This is why TPUs work best with standard architectures. Transformers, CNNs, and common layer types compile efficiently. Custom operations or unusual control flow can hit XLA limitations.</p><h2>Practical Considerations: Batch Size and Memory</h2><p>TPUs have a simpler memory hierarchy than GPUs: High Bandwidth Memory (HBM) connects to on-chip buffers, which feed the systolic array. The key constraint is keeping the array fed with data.</p><p>This is why <strong>batch size matters enormously on TPUs</strong>. Larger batches mean more data reuse in the systolic array, better amortization of memory transfer overhead, and higher utilization of compute units. If your batch size is too small, the array spends cycles waiting for data instead of computing.</p><p>This differs from GPUs, where the flexible threading model handles small batches more gracefully. On TPUs, you often need to redesign your training pipeline around larger batches to achieve good performance.</p><h2>When TPUs Struggle</h2><p>The systolic array&#8217;s efficiency comes from predictable, dense, regular computation. When workloads deviate from this pattern, performance degrades.</p><p><strong>Sparse operations</strong> are the clearest example. If your matrices are mostly zeros, the systolic array still processes every zero. There&#8217;s no sparse matrix acceleration. Sparse attention mechanisms, mixture-of-experts with dynamic routing, or sparse activations can significantly underutilize TPU hardware.</p><p><strong>Dynamic shapes</strong> cause problems because XLA compiles for specific tensor dimensions. Variable sequence lengths or dynamic batching require either padding (wasting compute) or recompilation (adding latency).</p><p><strong>Complex control flow</strong> maps poorly to the systolic array&#8217;s fixed data flow. Most neural networks are straight-line computation, but models with significant branching can struggle.</p><h2>Scaling: TPU Pods</h2><p>Individual TPUs connect into pods through high-speed custom interconnects. Unlike GPU clusters that use standard InfiniBand or Ethernet, TPU pods use a 2D or 3D torus topology where each chip communicates directly with its neighbors.</p><p>This topology is optimized for the communication patterns of distributed ML training, particularly the all-reduce operations used in gradient synchronization. The interconnect is tightly coupled with the TPU architecture, rather than being a separate networking layer you configure independently.</p><p>This tight coupling means TPU pods can be extremely efficient for workloads that fit their communication patterns, but less flexible if your distributed training approach differs from Google&#8217;s assumptions.</p><h2>Making the Choice</h2><p>Given everything above, here&#8217;s when each option makes sense:</p><p><strong>Choose GPUs when:</strong></p><ul><li><p>You need framework flexibility, especially PyTorch-first workflows</p></li><li><p>Your workloads include sparse operations or dynamic shapes</p></li><li><p>You want multi-cloud or on-premises deployment</p></li><li><p>You need fine-grained control over kernel implementations</p></li><li><p>You&#8217;re prototyping and need fast iteration</p></li></ul><p><strong>Choose TPUs when:</strong></p><ul><li><p>You&#8217;re running large-scale training or inference on dense, regular models</p></li><li><p>You&#8217;re using TensorFlow or JAX and standard architectures</p></li><li><p>You can use large batch sizes that saturate the systolic array</p></li><li><p>Latency predictability matters (TPUs don&#8217;t thermal throttle like GPUs)</p></li><li><p>You&#8217;re committed to Google Cloud infrastructure</p></li></ul><h2>The Broader Lesson</h2><p>TPUs embody a bet: that ML workloads are important and stable enough to justify specialized silicon. General-purpose hardware can run anything but excels at nothing. Specialized hardware excels at specific workloads but becomes useless when requirements change.</p><p>So far, Google&#8217;s bet has paid off. The workloads that matter most, transformers and large language models, are exactly the dense matrix operations that systolic arrays handle best.</p><p>The lesson for engineers isn&#8217;t that TPUs are better or worse than GPUs. It&#8217;s that hardware architecture embodies assumptions about workloads. When you understand those assumptions, you can match your problem to the right hardware. When you don&#8217;t, you end up fighting the architecture instead of leveraging it.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.systemoverflow.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.systemoverflow.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><p>Dive deeper into ML System Design @ <a href="https://www.systemoverflow.com">System Overflow</a></p>]]></content:encoded></item><item><title><![CDATA[Performance Optimization: Lessons from Google’s Legends]]></title><description><![CDATA[Reading the performance optimization playbook from two of the most influential engineers in computing.]]></description><link>https://blog.systemoverflow.com/p/performance-optimization-lessons</link><guid isPermaLink="false">https://blog.systemoverflow.com/p/performance-optimization-lessons</guid><dc:creator><![CDATA[System Overflow]]></dc:creator><pubDate>Sun, 21 Dec 2025 08:52:10 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!NXNP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F523d6493-89c1-411d-bf13-75f603225659_1190x1390.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NXNP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F523d6493-89c1-411d-bf13-75f603225659_1190x1390.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NXNP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F523d6493-89c1-411d-bf13-75f603225659_1190x1390.png 424w, https://substackcdn.com/image/fetch/$s_!NXNP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F523d6493-89c1-411d-bf13-75f603225659_1190x1390.png 848w, https://substackcdn.com/image/fetch/$s_!NXNP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F523d6493-89c1-411d-bf13-75f603225659_1190x1390.png 1272w, https://substackcdn.com/image/fetch/$s_!NXNP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F523d6493-89c1-411d-bf13-75f603225659_1190x1390.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NXNP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F523d6493-89c1-411d-bf13-75f603225659_1190x1390.png" width="1190" height="1390" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/523d6493-89c1-411d-bf13-75f603225659_1190x1390.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1390,&quot;width&quot;:1190,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:737669,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://blog.systemoverflow.com/i/182223023?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F523d6493-89c1-411d-bf13-75f603225659_1190x1390.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!NXNP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F523d6493-89c1-411d-bf13-75f603225659_1190x1390.png 424w, https://substackcdn.com/image/fetch/$s_!NXNP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F523d6493-89c1-411d-bf13-75f603225659_1190x1390.png 848w, https://substackcdn.com/image/fetch/$s_!NXNP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F523d6493-89c1-411d-bf13-75f603225659_1190x1390.png 1272w, https://substackcdn.com/image/fetch/$s_!NXNP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F523d6493-89c1-411d-bf13-75f603225659_1190x1390.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>If you&#8217;ve worked in distributed systems or backend infrastructure, you&#8217;ve almost certainly come across Jeff Dean and Sanjay Ghemawat. Together, they co-created MapReduce and Bigtable, two foundational systems that shaped modern large-scale data processing. Jeff Dean later went on to co-author Spanner and lead major efforts behind TensorFlow, extending that lineage into globally consistent databases and large-scale machine learning. </p><p>Recently, they published a comprehensive guide on performance optimization, and it&#8217;s a goldmine. Let us extract the core principles that can transform how you think about performance.</p><h2>The 3% That Matters</h2><p>Knuth famously said &#8220;premature optimization is the root of all evil.&#8221; But here&#8217;s the full quote most people miss:</p><blockquote><p>&#8220;We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. <strong>Yet we should not pass up our opportunities in that critical 3%.</strong>&#8220;</p></blockquote><p>The key insight? If you ignore performance entirely during development, you&#8217;ll end up with a <strong>flat profile</strong>&#8212;performance lost everywhere, no obvious hotspots. Much harder to fix later.</p><h3>Why &#8220;Fix It Later&#8221; Fails</h3><ol><li><p><strong>Flat profiles are hell to optimize</strong> - No clear starting point when slowness is distributed everywhere</p></li><li><p><strong>Library users can&#8217;t fix your mess</strong> - They don&#8217;t understand your internals well enough</p></li><li><p><strong>Heavy-use systems resist change</strong> - Hard to refactor production code serving millions of requests</p></li><li><p><strong>Overprovisioning masks problems</strong> - You throw hardware at issues that could&#8217;ve been prevented with better code</p></li></ol><p><strong>The golden rule</strong>: When writing code, choose the faster alternative if it doesn&#8217;t significantly hurt readability.</p><h2>The Art of Estimation</h2><p>Before diving into optimization, develop intuition for <em>what matters</em>. Ask yourself:</p><ul><li><p><strong>Is it test code?</strong> &#8594; Focus on asymptotic complexity only</p></li><li><p><strong>Is it application-specific?</strong> &#8594; Identify hot paths vs. initialization code</p></li><li><p><strong>Is it library code?</strong> &#8594; Assume it&#8217;ll be used in performance-critical contexts</p></li></ul><h3>Back-of-the-Envelope Math Still Works</h3><p>Here&#8217;s the latency table every engineer should memorize (updated for 2025):</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hjlF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d26cc62-cf41-4cc5-b843-aed4f9b3ae67_2816x1536.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hjlF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d26cc62-cf41-4cc5-b843-aed4f9b3ae67_2816x1536.png 424w, https://substackcdn.com/image/fetch/$s_!hjlF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d26cc62-cf41-4cc5-b843-aed4f9b3ae67_2816x1536.png 848w, https://substackcdn.com/image/fetch/$s_!hjlF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d26cc62-cf41-4cc5-b843-aed4f9b3ae67_2816x1536.png 1272w, https://substackcdn.com/image/fetch/$s_!hjlF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d26cc62-cf41-4cc5-b843-aed4f9b3ae67_2816x1536.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hjlF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d26cc62-cf41-4cc5-b843-aed4f9b3ae67_2816x1536.png" width="1456" height="794" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2d26cc62-cf41-4cc5-b843-aed4f9b3ae67_2816x1536.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:794,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:5003006,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.systemoverflow.com/i/182223023?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d26cc62-cf41-4cc5-b843-aed4f9b3ae67_2816x1536.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!hjlF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d26cc62-cf41-4cc5-b843-aed4f9b3ae67_2816x1536.png 424w, https://substackcdn.com/image/fetch/$s_!hjlF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d26cc62-cf41-4cc5-b843-aed4f9b3ae67_2816x1536.png 848w, https://substackcdn.com/image/fetch/$s_!hjlF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d26cc62-cf41-4cc5-b843-aed4f9b3ae67_2816x1536.png 1272w, https://substackcdn.com/image/fetch/$s_!hjlF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d26cc62-cf41-4cc5-b843-aed4f9b3ae67_2816x1536.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.systemoverflow.com/p/performance-optimization-lessons?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.systemoverflow.com/p/performance-optimization-lessons?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><h4>Example: Quicksort a Billion Numbers</h4><p>Let&#8217;s estimate sorting 1 billion 4-byte integers:</p><ol><li><p><strong>Memory bandwidth</strong>: 4GB &#215; 30 passes &#247; 16GB/s = <strong>7.5 seconds</strong></p></li><li><p><strong>Branch mispredictions</strong>: 30B comparisons &#215; 50% mispredicted &#215; 5ns = <strong>75 seconds</strong></p></li><li><p><strong>Total</strong>: ~82.5 seconds (branch mispredictions dominate!)</p></li></ol><h4>Example: Generate Web Page with 30 Thumbnails</h4><p><strong>Serial reads from disk</strong>:</p><ul><li><p>30 images &#215; (5ms seek + 10ms transfer) = <strong>450ms</strong></p></li></ul><p><strong>Parallel reads across K disks</strong>:</p><ul><li><p>Same work, latency drops by factor of K = <strong>~15ms</strong> (with hundreds of disks)</p></li></ul><p><strong>Serial reads from SSD</strong>:</p><ul><li><p>30 images &#215; (20&#181;s + 1ms) = <strong>~30ms</strong></p></li></ul><p>This math takes 30 seconds but saves hours of implementation time.</p><h2>Measurement: Your #1 Tool</h2><h3>Profiling Strategies</h3><p><strong>Start with <a href="https://github.com/google/pprof">pprof</a></strong> for high-level CPU profiling. Move to <code>perf</code> for hardware counter details.</p><p>Critical practices:</p><ul><li><p>Build with optimizations + debug symbols</p></li><li><p>Write microbenchmarks for iteration speed</p></li><li><p>Emit performance counter readings for precision</p></li><li><p>Profile lock contention separately (can hide CPU bottlenecks)</p></li></ul><h3>When Profiles Are Flat</h3><p>No obvious hotspot? Try this:</p><ol><li><p><strong>Many small wins compound</strong> - Twenty 1% improvements = 20% total gain</p></li><li><p><strong>Look at loop call stacks</strong> - Restructure from the top down</p></li><li><p><strong>Replace generality with specialization</strong> - Custom code beats generic libraries</p></li><li><p><strong>Reduce allocations</strong> - Get heap profiles, target allocation count</p></li><li><p><strong>Use hardware counters</strong> - Cache miss rates reveal hidden costs</p></li></ol><h2>API Design for Performance</h2><h3>Bulk Operations</h3><p>Single-item APIs force expensive boundary crossings. Add bulk variants:</p><pre><code><code>// Before
util::StatusOr&lt;LiveTensor&gt; Lookup(const TensorIdProto&amp; id);

// After - 1000x less overhead
struct LookupKey {
  ClientHandle client;
  uint64 local_id;
};
bool LookupMany(absl::Span&lt;const LookupKey&gt; keys,
                absl::Span&lt;tensorflow::Tensor&gt; tensors);</code></code></pre><p>Real impact: Reduced per-call overhead from milliseconds to microseconds.</p><h3>View Types Over Copies</h3><pre><code><code>// Slow - forces copies
void ProcessData(const std::vector&lt;int&gt;&amp; data);

// Fast - caller chooses container
void ProcessData(absl::Span&lt;const int&gt; data);</code></code></pre><p>This lets callers use <code>std::vector</code>, <code>absl::InlinedVector</code>, arrays, or anything contiguous.</p><h3>Thread-Compatible &gt; Thread-Safe</h3><p>Default to external synchronization. Internal locks are wasted overhead when callers already synchronize:</p><pre><code><code>// Before - internal lock
TransferPhase HitlessTransferPhase::get() const {
  MonitoredMutexLock l(&amp;mutex_);
  return phase_;
}

// After - caller synchronizes
TransferPhase HitlessTransferPhase::get() const { 
  return phase_; 
}</code></code></pre><p>Result: <strong>43 seconds &#8594; 2 seconds</strong> in production workload.</p><h2>Algorithmic Wins</h2><p>These are rare but devastating when found.</p><h3>Example: O(N&#178;) &#8594; O(N)</h3><p><strong>Before</strong>: Adding graph nodes/edges one at a time to cycle detector </p><p><strong>After</strong>: Add entire graph in reverse post-order</p><p>Result: Cycle detection becomes trivial.</p><h3>Example: Replace Sorted Intersection with Hash Table</h3><pre><code><code>// Before: O(N log N)
std::set_intersection(sources1.begin(), sources1.end(),
                      sources2.begin(), sources2.end());

// After: O(N)
absl::flat_hash_set&lt;Node*&gt; sources_set(sources1.begin(), sources1.end());
for (Node* src : sources2) {
  if (sources_set.contains(src)) { /* found common source */ }
}</code></code></pre><p>Impact: <strong>28.5s &#8594; 22.4s</strong> (21% improvement) on large compilations.</p><h2>Memory Optimization</h2><h3>Compact Representations</h3><p>Every byte matters at scale. Consider:</p><pre><code><code>// Bad - 64 bits wasted per pointer on modern machines
std::vector&lt;Node*&gt; graph;

// Better - 32-bit indices if &lt;4B nodes
std::vector&lt;uint32_t&gt; node_indices;
Node nodes[];  // Contiguous allocation</code></code></pre><p>Benefits:</p><ul><li><p>Smaller memory footprint</p></li><li><p>Better cache locality</p></li><li><p>Less allocator overhead</p></li></ul><h3>Inlined Storage for Small Collections</h3><pre><code><code>// Before - always heap allocates
std::vector&lt;int&gt; small_list;

// After - stack allocation for &#8804;N elements
absl::InlinedVector&lt;int, 8&gt; small_list;</code></code></pre><p>No allocation overhead when size &#8804; 8.</p><h3>Arrays Instead of Maps</h3><pre><code><code>// Before
gtl::flat_map&lt;int, int&gt; payload_type_to_frequency;

// After - payload types are 0-127
struct PayloadTypeMap {
  int map[128];
};</code></code></pre><p><strong>Benchmark improvement</strong>: 26-31% faster access.</p><h3>Bit Vectors for Dense Integer Sets</h3><pre><code><code>// Before
dense_hash_set&lt;ZoneId&gt; zones;  // Heavy allocation

// After
util::bitmap::InlinedBitVector&lt;256&gt; zones;  // Single allocation

bool ContainsZone(ZoneId zone) const {
  return zone &lt; zones.size() &amp;&amp; zones.get_bit(zone);
}</code></code></pre><p>Results: <strong>26-31% faster</strong> in real workloads.</p><h2>Reducing Allocations</h2><p>Every allocation has three costs:</p><ol><li><p>Allocator CPU time</p></li><li><p>Initialization overhead</p></li><li><p>Cache line fragmentation</p></li></ol><h3>Avoid Needless Allocations</h3><pre><code><code>// Before - allocates every time
std::shared_ptr&lt;DeviceInfo&gt; dinfo = 
    std::make_shared&lt;DeviceInfo&gt;();

// After - reuse static instance
static const std::shared_ptr&lt;DeviceInfo&gt;&amp; empty_device_info() {
  static auto* result = new std::shared_ptr&lt;DeviceInfo&gt;(
      std::make_shared&lt;DeviceInfo&gt;());
  return *result;
}</code></code></pre><p><strong>21% throughput increase</strong> in production.</p><h3>Reuse Temporaries</h3><pre><code><code>// Before - reallocates every iteration
for (const auto&amp; item : items) {
  ResourceRecord record;  // &#8592; Expensive!
  ProcessRecord(record);
}

// After - reuse allocation
ResourceRecord record;
for (const auto&amp; item : items) {
  record.Clear();
  ProcessRecord(record);
}</code></code></pre><p>Caveat: Reset periodically to prevent unbounded growth.</p><h3>Reserve Container Capacity</h3><pre><code><code>// Before - multiple reallocations
std::vector&lt;int&gt; results;
for (int i = 0; i &lt; n; ++i) {
  results.push_back(compute(i));
}

// After - single allocation
std::vector&lt;int&gt; results;
results.reserve(n);
for (int i = 0; i &lt; n; ++i) {
  results.push_back(compute(i));
}</code></code></pre><h2>Avoiding Unnecessary Work</h2><h3>Fast Paths for Common Cases</h3><p><strong>Handle ASCII in UTF-8 parsing</strong>:</p><pre><code><code>// Fast path - process 8 ASCII bytes at once
while ((src_limit - src &gt;= 8) &amp;&amp;
       (((UNALIGNED_LOAD32(src) | UNALIGNED_LOAD32(src+4)) 
         &amp; 0x80808080) == 0)) {
  src += 8;
}

// Handle trailing ASCII bytes
while (src &lt; src_limit &amp;&amp; Is7BitAscii(*src)) {
  src++;
}

// Fall back to state machine for non-ASCII
if (src &lt; src_limit) {
  UTF8GenericScan(/*...*/);
}</code></code></pre><h3>Precompute Expensive Values</h3><pre><code><code>// Before - computed in every hot loop iteration
bool kernel_is_expensive = kernel-&gt;IsExpensive();
bool is_merge = IsMerge(node);
bool is_enter = IsEnter(node);

// After - computed once during initialization
struct NodeItem {
  bool kernel_is_expensive : 1;
  bool is_merge : 1;
  bool is_enter : 1;
  bool is_enter_exit_or_next_iter : 1;
};

// Hot path check
if (!item-&gt;is_enter_exit_or_next_iter) {
  // Fast path - no special handling needed
}</code></code></pre><h3>Defer Until Needed</h3><pre><code><code>// Before - always compute
HloSharding alt = user.sharding().GetSubSharding(/*...*/);
if (condition) { use(alt); }

// After - compute only when needed
if (condition) {
  HloSharding alt = user.sharding().GetSubSharding(/*...*/);
  use(alt);
}</code></code></pre><p>Saved <strong>43 seconds &#8594; 2 seconds</strong> by deferring expensive call.</p><h3>Specialize Generic Code</h3><p>Replace regex with simple operations when possible:</p><pre><code><code>// Before
if (RE2::FullMatch(token, "prefix.*")) { /*...*/ }

// After
if (absl::StartsWith(token, "prefix")) { /*...*/ }</code></code></pre><p>Or custom implementations for critical paths:</p><pre><code><code>// Before - sprintf for IP address
StringPrintf("[%s]:%d", ip.ToString().c_str(), port);

// After - direct formatting
StrCat(a1, ".", a2, ".", a3, ".", a4, ":", port);</code></code></pre><p><strong>4x faster</strong> in monitoring hot paths.</p><h3>Caching</h3><pre><code><code>// Cache based on fingerprint
uint64 fp = Fingerprint(proto);
{
  absl::MutexLock l(&amp;cache_mu);
  auto it = cache.find(fp);
  if (it != cache.end()) {
    return it-&gt;second;  // Cache hit
  }
  // Parse and cache
  auto result = ParseProto(proto);
  cache[fp] = result;
  return result;
}</code></code></pre><h2>Help the Compiler</h2><p>Compilers are smart but conservative. You can help:</p><h3>Use Raw Pointers in Hot Loops</h3><pre><code><code>// Before - absl::Span has overhead
ForEachState(const Shape&amp; s, 
             absl::Span&lt;const int64_t&gt; base,
             absl::Span&lt;const int64_t&gt; count);

// After - raw pointers are faster
ForEachState(const Shape&amp; s,
             const int64_t* const base,
             const int64_t* const count);</code></code></pre><h3>Hand-Unroll Critical Loops</h3><pre><code><code>// Before
while ((p + 4) &lt;= e) {
  STEP;
}

// After - 16 bytes at a time
while ((e - p) &gt;= 16) {
  STEP; STEP; STEP; STEP;
}
while ((p + 4) &lt;= e) {
  STEP;
}</code></code></pre><h3>Replace FATAL with DCHECK</h3><pre><code><code>// Before - forces frame setup
default:
  ABSL_LOG(FATAL) &lt;&lt; "Invalid tag";
  return sizeof(DynamicNode);

// After - compiles away in optimized builds
default:
  ABSL_DCHECK(false) &lt;&lt; "Invalid tag";
  return sizeof(DynamicNode);</code></code></pre><p>Eliminates frame setup costs in release builds.</p><h2>Reduce Stats Collection</h2><p>Balance utility vs. cost:</p><h3>Sample, Don&#8217;t Measure Everything</h3><pre><code><code>// Before - update 39 histograms per request
UpdateHistograms(request);

// After - sample 1 in 32 requests
if (request_count % 32 == 0) {
  UpdateHistograms(request);
}</code></code></pre><p><strong>Google Meet used this</strong> during COVID surge to handle traffic spikes.</p><h3>Drop Unused Stats</h3><pre><code><code>// Removed expensive alarm/closure counting
// that nobody looked at
// Result: 771ns &#8594; 271ns per alarm</code></code></pre><h3>Precompute Logging Decisions</h3><pre><code><code>// Before - checked every iteration
for (int i = 0; i &lt; 1000000; ++i) {
  if (VLOG_IS_ON(3)) {
    VLOG(3) &lt;&lt; "Processing " &lt;&lt; i;
  }
}

// After - check once
const bool vlog_3 = VLOG_IS_ON(3);
for (int i = 0; i &lt; 1000000; ++i) {
  if (vlog_3) {
    VLOG(3) &lt;&lt; "Processing " &lt;&lt; i;
  }
}</code></code></pre><p>Results: <strong>8-10% improvement</strong> on compute-heavy loops.</p><h2>When to Optimize</h2><p>Not all code deserves the same scrutiny:</p><ul><li><p><strong>Test code</strong>: Optimize asymptotic complexity only</p></li><li><p><strong>Application code</strong>: Focus on request handling, not initialization</p></li><li><p><strong>Library code</strong>: Assume worst case&#8212;it&#8217;ll end up on hot paths</p></li><li><p><strong>Infrastructure code</strong>: Every nanosecond multiplies across thousands of servers</p></li></ul><h2>Code Size Matters Too</h2><p>Large binaries mean:</p><ul><li><p>Longer compile/link times</p></li><li><p>More memory pressure</p></li><li><p>Worse instruction cache behavior</p></li><li><p>Harder deployment</p></li></ul><p>Sometimes <strong>smaller, simpler code is faster</strong> despite being &#8220;less optimized.&#8221;</p><div><hr></div><h2>The Meta-Lesson</h2><p>Jeff and Sanjay&#8217;s guide isn&#8217;t about premature optimization. It&#8217;s about <strong>informed decision-making</strong>:</p><ol><li><p>Understand the cost model of your system</p></li><li><p>Make the fast choice when it&#8217;s equally simple</p></li><li><p>Measure before complex optimizations</p></li><li><p>Think in orders of magnitude, not percentages</p></li><li><p>Compound small wins into big gains</p></li></ol><p>Most importantly: <strong>Don&#8217;t wait for performance problems to think about performance.</strong> Build it right from the start, and save yourself from the architectural debt that&#8217;s nearly impossible to pay off later.</p><div><hr></div><p><em>Want more deep dives on systems engineering? Follow System Overflow for weekly breakdowns of distributed systems, databases, and infrastructure engineering.</em></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.systemoverflow.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading System Overflow - Master System Design! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p><strong>Further Reading:</strong></p><ul><li><p><a href="https://abseil.io/fast/hints.html">Original Abseil Performance Guide</a></p></li><li><p><a href="https://static.googleusercontent.com/media/research.google.com/en//people/jeff/stanford-295-talk.pdf">Jeff Dean&#8217;s Numbers Everyone Should Know</a></p></li><li><p><a href="https://github.com/google/pprof">Google pprof Profiler</a></p></li></ul>]]></content:encoded></item><item><title><![CDATA[From Batch to Real-Time: How LinkedIn Serves Recommendations]]></title><description><![CDATA[LinkedIn: Four-Phase Recommendation System Evolution (90% Cost Reduction)]]></description><link>https://blog.systemoverflow.com/p/from-batch-to-real-time-how-linkedin</link><guid isPermaLink="false">https://blog.systemoverflow.com/p/from-batch-to-real-time-how-linkedin</guid><dc:creator><![CDATA[System Overflow]]></dc:creator><pubDate>Fri, 19 Dec 2025 16:06:11 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Ss7f!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63e8be95-b832-4fd8-9b92-6685c0a9aa2a_1789x594.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When you open LinkedIn and instantly see personalized jobs or profile suggestions, you&#8217;re seeing the outcome of <strong>four distinct architectural eras</strong>. Each era reflects a deliberate trade-off between <strong>freshness, latency, cost, and model power</strong>.</p><p>This evolution is less about optimization, and more about <strong>knowing when an architecture has hit its ceiling</strong>.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.systemoverflow.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading System Overflow - Master System Design! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>The Core Problem (That Never Changes)</p><blockquote><p><strong>Given millions of items, how do you return the most relevant ones for a user in ~100ms at global scale?</strong></p></blockquote><p>Key constraints:</p><ul><li><p><strong>Freshness</strong>: React to recent user behavior</p></li><li><p><strong>Latency</strong>: Stay within tight p99 budgets</p></li><li><p><strong>Cost</strong>: Avoid computing and storing things no one sees</p></li><li><p><strong>Model complexity</strong>: Support increasingly powerful ML models</p></li></ul><p>Every architecture answers these constraints differently.</p><div><hr></div><h2>The Four Phases of Recommendation Architecture</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Ss7f!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63e8be95-b832-4fd8-9b92-6685c0a9aa2a_1789x594.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Ss7f!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63e8be95-b832-4fd8-9b92-6685c0a9aa2a_1789x594.png 424w, https://substackcdn.com/image/fetch/$s_!Ss7f!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63e8be95-b832-4fd8-9b92-6685c0a9aa2a_1789x594.png 848w, https://substackcdn.com/image/fetch/$s_!Ss7f!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63e8be95-b832-4fd8-9b92-6685c0a9aa2a_1789x594.png 1272w, https://substackcdn.com/image/fetch/$s_!Ss7f!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63e8be95-b832-4fd8-9b92-6685c0a9aa2a_1789x594.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Ss7f!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63e8be95-b832-4fd8-9b92-6685c0a9aa2a_1789x594.png" width="1456" height="483" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/63e8be95-b832-4fd8-9b92-6685c0a9aa2a_1789x594.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:483,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:134232,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.systemoverflow.com/i/182093371?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63e8be95-b832-4fd8-9b92-6685c0a9aa2a_1789x594.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Ss7f!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63e8be95-b832-4fd8-9b92-6685c0a9aa2a_1789x594.png 424w, https://substackcdn.com/image/fetch/$s_!Ss7f!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63e8be95-b832-4fd8-9b92-6685c0a9aa2a_1789x594.png 848w, https://substackcdn.com/image/fetch/$s_!Ss7f!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63e8be95-b832-4fd8-9b92-6685c0a9aa2a_1789x594.png 1272w, https://substackcdn.com/image/fetch/$s_!Ss7f!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63e8be95-b832-4fd8-9b92-6685c0a9aa2a_1789x594.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Phase 1: Offline Batch Scoring (2008&#8211;2012)</h2><p>In the earliest phase, LinkedIn relied on offline batch jobs that precomputed recommendation scores and stored them for lookup.</p><p>This approach failed quietly. Storage requirements exploded as users and items grew, and recommendations became stale almost immediately. Profile updates or job changes took hours or days to appear.</p><blockquote><p><strong>Why this matters?</strong></p><p>Offline systems don&#8217;t usually break. They decay. Relevance fades slowly, and by the time metrics move, the architecture is already holding you back.</p></blockquote><div><hr></div><h2>Phase 2: Nearline Scoring (2012&#8211;2015)</h2><p>To reduce staleness, LinkedIn introduced nearline recomputation triggered by user actions.</p><p>Freshness improved, but consistency didn&#8217;t. Some recommendations were updated quickly while others lagged behind. Distributed triggers introduced coordination complexity and partial failures that were hard to observe.</p><blockquote><p><strong>Why this matters?</strong></p><p>Hybrid systems often look like progress, but they introduce uneven behavior that&#8217;s harder to debug than full batch or full real-time systems.</p></blockquote><div><hr></div><h2>Phase 3: Online Scoring on CPUs (2015&#8211;2020)</h2><p>The next shift moved scoring into the request path. Recommendations were generated and scored in real time when a user loaded a page.</p><p>Freshness was solved, but latency became the dominant constraint. With a strict end-to-end budget, models had to be simple enough to run on CPUs. Feature richness and model depth were limited, and cold-start problems persisted.</p><blockquote><p><strong>Why this matters?</strong></p><p>Online scoring fixes staleness, but it puts a ceiling on intelligence. Latency budgets become product constraints.</p></blockquote><div><hr></div><h2>Phase 4: Decoupled Architecture with Remote GPU Scoring (2020&#8211;Present)</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ITcZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fee1b34-27a9-4060-a603-2408c4a64b27_1141x1398.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ITcZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fee1b34-27a9-4060-a603-2408c4a64b27_1141x1398.png 424w, https://substackcdn.com/image/fetch/$s_!ITcZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fee1b34-27a9-4060-a603-2408c4a64b27_1141x1398.png 848w, https://substackcdn.com/image/fetch/$s_!ITcZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fee1b34-27a9-4060-a603-2408c4a64b27_1141x1398.png 1272w, https://substackcdn.com/image/fetch/$s_!ITcZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fee1b34-27a9-4060-a603-2408c4a64b27_1141x1398.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ITcZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fee1b34-27a9-4060-a603-2408c4a64b27_1141x1398.png" width="1141" height="1398" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8fee1b34-27a9-4060-a603-2408c4a64b27_1141x1398.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1398,&quot;width&quot;:1141,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:146454,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.systemoverflow.com/i/182093371?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fee1b34-27a9-4060-a603-2408c4a64b27_1141x1398.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ITcZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fee1b34-27a9-4060-a603-2408c4a64b27_1141x1398.png 424w, https://substackcdn.com/image/fetch/$s_!ITcZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fee1b34-27a9-4060-a603-2408c4a64b27_1141x1398.png 848w, https://substackcdn.com/image/fetch/$s_!ITcZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fee1b34-27a9-4060-a603-2408c4a64b27_1141x1398.png 1272w, https://substackcdn.com/image/fetch/$s_!ITcZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fee1b34-27a9-4060-a603-2408c4a64b27_1141x1398.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The current system separates candidate generation from scoring and offloads inference to remote GPU services.</p><p>This architectural split changed what was possible. Candidate generation focused on recall, while scoring models could grow far more sophisticated. Embedding-based retrieval enabled semantic matching, reducing cold-start issues.</p><blockquote><p><strong>Why this matters?</strong></p><p>GPUs didn&#8217;t just make models faster&#8212;they made entirely new classes of models possible.</p></blockquote><div><hr></div><h2>What Happens in a Single Request</h2><p>When a user opens LinkedIn Jobs, the system generates candidates from multiple sources, narrows them using embedding similarity, and ranks them using GPU-powered models. Hundreds of features and real-time context are evaluated, all within roughly 100 milliseconds at the 99th percentile.</p><p>Decoupling recall from ranking allows each stage to evolve independently without blowing the latency budget.</p><div><hr></div><h2>Cost and Failure Modes</h2><p>Despite GPU infrastructure being expensive, overall system cost dropped dramatically. The system stopped precomputing and storing scores that were never viewed and shifted to on-demand inference.</p><p>Failure modes shifted as well. Offline systems fail slowly through staleness. Online systems fail instantly through latency. GPU-based systems fail operationally through serving and orchestration complexity.</p><p>Every architectural upgrade trades one kind of risk for another. Maturity isn&#8217;t eliminating failures, it&#8217;s choosing the ones you can handle.</p><div><hr></div><h2>Choosing the Right Architecture</h2><p>This evolution isn&#8217;t linear progress where the final stage is always best.</p><p>Offline batch systems still make sense at small scale. Nearline or online scoring becomes necessary when staleness hurts engagement. GPU-based inference only pays off when traffic, latency pressure, and business value align.</p><p>Premature architectural ambition is just another form of technical debt.</p><div><hr></div><h2>The Real Takeaway</h2><p>LinkedIn&#8217;s biggest gains didn&#8217;t come from tuning models, but they came from recognizing architectural limits and crossing them decisively.</p><p>If your system feels stuck despite constant optimization, the problem is probably architectural, not algorithmic.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.systemoverflow.com/p/from-batch-to-real-time-how-linkedin?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.systemoverflow.com/p/from-batch-to-real-time-how-linkedin?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><div><hr></div><p><em>Learn more about ML design concepts on <a href="https://www.systemoverflow.com/">System Overflow</a>.</em></p>]]></content:encoded></item><item><title><![CDATA[Design Pastebin - Text Sharing Service]]></title><description><![CDATA[FAANG Interview System Design Problem]]></description><link>https://blog.systemoverflow.com/p/design-pastebin-text-sharing-service</link><guid isPermaLink="false">https://blog.systemoverflow.com/p/design-pastebin-text-sharing-service</guid><dc:creator><![CDATA[System Overflow]]></dc:creator><pubDate>Wed, 17 Dec 2025 07:22:08 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/198ce716-75c0-4d6e-9faa-6b4b5e09840e_2560x1440.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1><strong>Interview Question:</strong></h1><p>Design a web service that allows users to store and share text snippets through unique URLs. Users can paste text content, receive a shareable link, and optionally set expiration times. The system should handle basic text storage, retrieval, and URL generation similar to Pastebin or GitHub Gist.</p><div id="youtube2-BAwUuEdNgy8" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;BAwUuEdNgy8&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/BAwUuEdNgy8?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.systemoverflow.com/p/design-pastebin-text-sharing-service?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.systemoverflow.com/p/design-pastebin-text-sharing-service?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p>]]></content:encoded></item><item><title><![CDATA[How Airbnb Built Adaptive Traffic Management for a Multi-tenant Key-value Store]]></title><description><![CDATA[Designing layered, adaptive QoS and rate limiting for multi-tenant backend services using resource-aware controls and local feedback loops.]]></description><link>https://blog.systemoverflow.com/p/how-airbnb-built-adaptive-traffic</link><guid isPermaLink="false">https://blog.systemoverflow.com/p/how-airbnb-built-adaptive-traffic</guid><dc:creator><![CDATA[System Overflow]]></dc:creator><pubDate>Sat, 13 Dec 2025 06:00:49 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!BomW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e1a9e67-230f-4779-a443-09d914f8c09e_860x1057.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introduction</h2><p>Every request you make at Airbnb - from searching for a stay to loading support data - eventually hits <strong>Mussel</strong>, Airbnb&#8217;s multi-tenant key-value store. At normal load it serves millions of reads smoothly, but during spikes, bulk uploads, or bot traffic, it has to stay fast without taking the rest of the platform down.</p><p>Airbnb&#8217;s first solution used simple per-client QPS limits. That was enough to prevent total meltdowns, but not enough to <strong>maximize useful work</strong> while staying within capacity. The real challenge was building <strong>adaptive traffic management</strong> that reacts to changing workloads in real time.</p><p>In this article, you will see how Airbnb evolved Mussel from static rate limiting to a layered QoS system, and how you can apply the same patterns - resource-aware limits, local feedback control, and hot-key protection - in your own systems.</p><h2>The Challenge</h2><p>Mussel sits in front of a storage engine as a fleet of stateless dispatcher pods running on Kubernetes. Every online product area at Airbnb sends traffic to it: point lookups, range scans, bulk writes, and internal tools. On top of normal diurnal cycles, Mussel also sees:</p><p>- Sudden user spikes, for example when a listing goes viral<br>- Large analytical or backfill jobs that scan huge ranges<br>- Misbehaving crawlers or outright DDoS-like bursts</p><p>The original design used a <strong>Redis-backed rate limiter</strong>: each caller had a static per-minute quota, and dispatchers incremented a counter per request. If you exceeded your quota, Mussel returned HTTP 429. This was simple and gave <strong>caller-level isolation</strong>: one bad client could not take the entire system down.</p><p>Over time, two deeper problems appeared.</p><p><strong>1. Cost variance between requests</strong></p><p>A one-row read and a 100,000-row range scan both counted as &#8220;1 request&#8221;. In reality they could differ by orders of magnitude in:</p><p>- CPU and memory usage<br>- Network bytes<br>- Disk I/O and cache pressure</p><p>This meant you could stay within your QPS but still quietly crush the backend with a few very expensive queries. The system had no concept of <strong>real resource cost per request</strong>.</p><p><strong>2. Traffic skew and hot spots</strong></p><p>Rate limits were per caller, not per data item. Imagine a popular listing that appears on a front page. Thousands of different callers all read the same key. Each caller respects its quota, but all these reads pound a single shard. That shard slows down, and now even unrelated keys hosted there get slow. Isolation at the caller level did not give isolation at the <strong>data or shard</strong> level.</p><p>A useful analogy is a supermarket with a &#8220;10 items per customer&#8221; rule but no control on how many people swarm one shelf. You avoid one person hogging the checkout, but if 500 people all grab from the same shelf at once, that aisle still collapses.</p><p>Common solutions like global QPS caps or static per-service quotas fail here because they:</p><p>- Do not distinguish cheap from expensive work<br>- Do not respond quickly enough to micro-bursts and hot keys<br>- Do not express <strong>priority</strong> across different types of traffic</p><p>This is a common challenge whenever you run a <strong>multi-tenant backend</strong> that serves heterogeneous workloads: databases, search clusters, caches, or shared internal platforms. You are not just limiting <em>how many</em> calls arrive; you are managing <strong>which work gets done under constrained resources</strong>.</p><h2>Airbnb&#8217;s Solution Architecture</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!BomW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e1a9e67-230f-4779-a443-09d914f8c09e_860x1057.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!BomW!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e1a9e67-230f-4779-a443-09d914f8c09e_860x1057.png 424w, https://substackcdn.com/image/fetch/$s_!BomW!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e1a9e67-230f-4779-a443-09d914f8c09e_860x1057.png 848w, https://substackcdn.com/image/fetch/$s_!BomW!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e1a9e67-230f-4779-a443-09d914f8c09e_860x1057.png 1272w, https://substackcdn.com/image/fetch/$s_!BomW!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e1a9e67-230f-4779-a443-09d914f8c09e_860x1057.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!BomW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e1a9e67-230f-4779-a443-09d914f8c09e_860x1057.png" width="860" height="1057" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4e1a9e67-230f-4779-a443-09d914f8c09e_860x1057.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1057,&quot;width&quot;:860,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:50291,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://systemoverflow.substack.com/i/181491738?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e1a9e67-230f-4779-a443-09d914f8c09e_860x1057.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!BomW!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e1a9e67-230f-4779-a443-09d914f8c09e_860x1057.png 424w, https://substackcdn.com/image/fetch/$s_!BomW!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e1a9e67-230f-4779-a443-09d914f8c09e_860x1057.png 848w, https://substackcdn.com/image/fetch/$s_!BomW!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e1a9e67-230f-4779-a443-09d914f8c09e_860x1057.png 1272w, https://substackcdn.com/image/fetch/$s_!BomW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e1a9e67-230f-4779-a443-09d914f8c09e_860x1057.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>Airbnb&#8217;s engineers redesigned Mussel&#8217;s QoS as a <strong>layered control system</strong> rather than a single global rate limit. The layers are:</p><p>1. <strong>Resource-aware rate control (RARC)</strong> using request units<br>2. <strong>Load shedding</strong> based on latency feedback and request criticality<br>3. <strong>Hot-key detection and mitigation</strong> to protect shards from skewed access</p><p>You can read this as: &#8220;price requests correctly, then adapt to stress, then neutralize amplification patterns.&#8221; Here is how each layer works and how it generalizes.</p><h3>1. Resource-aware rate control with request units</h3><p>Instead of counting raw QPS, Mussel now charges each operation in <strong>request units (RU)</strong>. An RU is a synthetic cost metric that reflects:</p><p>- A base cost per call<br>- Data volume (rows or bytes)<br>- Observed latency for that call</p><p>You can think of this as a linear pricing model:</p><p>&gt; RU = base_cost + weight_bytes <em>bytes + weight_latency </em>latency_ms</p><p>Weights are calibrated from load tests that roughly balance CPU, network, and disk cost. The exact coefficients are not the important part. The important idea is that <strong>expensive operations consume more of a client&#8217;s quota</strong> than cheap ones, using metrics you can easily observe at the proxy.</p><p>Each caller now has a static <strong>RU quota per time window</strong>, not a raw QPS quota. Each dispatcher maintains a local token bucket: on each request, it computes the RU cost and decrements tokens. When tokens are gone, Mussel rejects the request with a throttling code.</p><p>Airbnb chose this model because it preserved a simple, static contract to clients (you get N RU per minute), while internally allowing much better fairness across workloads. This pattern - &#8220;convert requests into resource units, then rate limit on units&#8221; - is useful any time you have:</p><p>- A shared backend with variable-cost operations<br>- The ability to measure simple per-request features</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.systemoverflow.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.systemoverflow.com/subscribe?"><span>Subscribe now</span></a></p><h3>2. Load shedding with local latency feedback</h3><p>RU-based quotas smooth average behavior, but they do not react instantly to rapid changes. Airbnb added a <strong>load-shedding layer</strong> that uses two local signals inside each dispatcher:</p><p>- A <strong>latency ratio</strong>: short-term p95 latency divided by long-term p95 latency<br>- A <strong>queue delay threshold</strong>: based on how long requests spend waiting in the dispatcher thread pool</p><p>The latency ratio is a compact way to detect when the system is getting slower. A ratio near 1 means &#8220;steady.&#8221; If the short-term p95 grows sharply, the ratio drops toward 0.3 or lower. When it crosses a threshold, the dispatcher concludes &#8220;we are entering overload&#8221; and starts to <strong>penalize</strong> less critical traffic classes by artificially inflating their RU cost or dropping queued requests earlier.</p><p>The queue control is inspired by CoDel-style algorithms that do not just look at queue length, but at <strong>sojourn time</strong> (how long each request sat in the queue). If that wait time exceeds a target for long enough, the dispatcher starts failing new arrivals quickly instead of letting them pile up and time out.</p><p>Airbnb also tags traffic with <strong>criticality tiers</strong> (for example, user-facing vs batch). Under stress, lower tiers back off first, preserving headroom for critical paths like customer support or trust and safety.</p><p>This pattern of <strong>local, feedback-based load shedding</strong> is powerful when you need to:</p><p>- React within milliseconds to backend slowdowns<br>- Protect high-priority workloads without human intervention<br>- Keep the control logic independent per proxy instance</p><h3>3. Hot-key detection and DDoS mitigation</h3><p>Even with good rate limits, a &#8220;stampede&#8221; of reads for one record can overload its shard. Airbnb addressed this with a three-part <strong>hot-key defence</strong> at each dispatcher:</p><p>1. <strong>Real-time top-k tracking</strong> of keys using a constant-space streaming algorithm<br>2. <strong>Short-lived local caching</strong> of hot keys<br>3. <strong>Request coalescing</strong> for in-flight reads of the same hot key</p><p>Every incoming key updates a compact data structure that approximates the most frequent keys. When a key crosses a hotness threshold, the dispatcher starts serving it from a small <strong>process-local LRU cache</strong> with a very short TTL (on the order of seconds). This is enough to ride out a news spike or a bot burst without requiring a global cache.</p><p>If multiple requests for a hot key arrive while a cache miss is in progress, the dispatcher records that there is an <strong>in-flight request</strong> and attaches new callers to the same future. When the backend response arrives, it fans out to all waiters. In practice this means that for each dispatcher pod, at most one in-flight backend request per hot key is active at a time.</p><p>This general pattern - &#8220;detect hot keys, cache locally with tiny TTLs, coalesce in-flight requests&#8221; - is broadly applicable to any key-based storage or cache. It converts N identical expensive reads into 1 read plus N cheap local responses.</p><h2>Trade-offs &amp; Considerations</h2><p>Airbnb&#8217;s approach trades <strong>simplicity</strong> for <strong>control and resilience</strong>.</p><p>On the positive side, you get:</p><p>- Finer-grained fairness: heavy range scans cannot starve cheap point reads<br>- Better protection of critical paths during overloads<br>- Robustness to traffic skew and DDoS-style patterns</p><p>On the cost side, you accept:</p><p>- More moving parts: RU accounting, latency feedback, queue control, top-k tracking, local caches<br>- Tuning complexity: choosing RU weights, latency thresholds, and hot thresholds<br>- Some approximation error: RU formulas and streaming algorithms are not perfect</p><p>This architecture works best when:</p><p>- You own a clear proxy or gateway where all traffic passes<br>- You can cheaply measure basic per-request metrics (bytes, latency)<br>- You have heterogeneous workloads and multi-tenant usage</p><p>It may be overkill for a small service with uniform traffic where simple per-client QPS limits suffice, or for systems where you cannot easily change client quotas or introduce admission control.</p><p>You also need to think about failure modes: what happens if the central quota store (like Redis) is down, or if latency metrics get corrupted, or if hot-key detection misfires. Airbnb&#8217;s design keeps most control loops <strong>local to each dispatcher</strong>, which reduces blast radius: if one node&#8217;s control logic behaves badly, it does not directly affect others.</p><h2>Conclusion</h2><p>Airbnb&#8217;s evolution of Mussel from static QPS limits to adaptive traffic management illustrates a powerful system design pattern for multi-tenant backends.</p><p>You start by <strong>measuring work in resource units</strong>, not requests. You then <strong>layer fast, local feedback loops</strong> to shed load based on latency and queue health. Finally, you <strong>neutralize amplification patterns</strong> like hot keys with detection, caching, and request coalescing.</p><p>If you run a shared data service, cache, or API that different teams depend on, these ideas map directly to classic system design concepts: token buckets and RU-based rate limiting, admission control, backpressure, prioritized QoS, and hotspot mitigation. As your traffic and tenants grow, this style of architecture can be the difference between &#8220;we stayed up&#8221; and &#8220;everything was technically within quota but still fell over.&#8221;</p>]]></content:encoded></item><item><title><![CDATA[How Message Queues Enable Scalable Distributed Systems]]></title><description><![CDATA[Every time you place an order on Amazon, upload a photo to Instagram, or send a message in Slack, message queues are working behind the scenes to ensure your action completes instantly while complex processing happens later.]]></description><link>https://blog.systemoverflow.com/p/how-message-queues-enable-scalable</link><guid isPermaLink="false">https://blog.systemoverflow.com/p/how-message-queues-enable-scalable</guid><dc:creator><![CDATA[System Overflow]]></dc:creator><pubDate>Mon, 08 Dec 2025 15:40:36 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!JGdu!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e1ac73a-22e8-4297-9692-962a010b649a_512x512.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Every time you place an order on Amazon, upload a photo to Instagram, or send a message in Slack, message queues are working behind the scenes to ensure your action completes instantly while complex processing happens later. Without this pattern, you&#8217;d wait seconds or minutes for every action while systems process payments, resize images, or trigger notifications.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ojmI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5a987f2-81bb-4fbb-8d9b-afd6b4129204_1108x1286.svg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ojmI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5a987f2-81bb-4fbb-8d9b-afd6b4129204_1108x1286.svg 424w, https://substackcdn.com/image/fetch/$s_!ojmI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5a987f2-81bb-4fbb-8d9b-afd6b4129204_1108x1286.svg 848w, https://substackcdn.com/image/fetch/$s_!ojmI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5a987f2-81bb-4fbb-8d9b-afd6b4129204_1108x1286.svg 1272w, https://substackcdn.com/image/fetch/$s_!ojmI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5a987f2-81bb-4fbb-8d9b-afd6b4129204_1108x1286.svg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ojmI!,w_2400,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5a987f2-81bb-4fbb-8d9b-afd6b4129204_1108x1286.svg" width="1200" height="1395.3488372093022" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a5a987f2-81bb-4fbb-8d9b-afd6b4129204_1108x1286.svg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;large&quot;,&quot;height&quot;:150,&quot;width&quot;:129,&quot;resizeWidth&quot;:1200,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Message Queue Fundamentals - Overview&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-large" alt="Message Queue Fundamentals - Overview" title="Message Queue Fundamentals - Overview" srcset="https://substackcdn.com/image/fetch/$s_!ojmI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5a987f2-81bb-4fbb-8d9b-afd6b4129204_1108x1286.svg 424w, https://substackcdn.com/image/fetch/$s_!ojmI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5a987f2-81bb-4fbb-8d9b-afd6b4129204_1108x1286.svg 848w, https://substackcdn.com/image/fetch/$s_!ojmI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5a987f2-81bb-4fbb-8d9b-afd6b4129204_1108x1286.svg 1272w, https://substackcdn.com/image/fetch/$s_!ojmI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5a987f2-81bb-4fbb-8d9b-afd6b4129204_1108x1286.svg 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a><figcaption class="image-caption">Message Queue Fundamentals - Overview</figcaption></figure></div><h2>The Core Concept</h2><p>A message queue is a durable buffer that sits between services, letting them communicate asynchronously instead of waiting for each other. When your application needs to do work, it writes a message to the queue and immediately continues. Separate consumer services read messages from the queue and process them at their own pace.</p><p>Think of a message queue like a restaurant&#8217;s order ticket system. When you place an order, the waiter writes it down and immediately returns to serve other customers. The kitchen processes orders as fast as they can, but diners aren&#8217;t standing at the counter waiting. If the kitchen gets slammed with orders, tickets stack up, but no customer is told &#8220;we&#8217;re too busy right now, come back later.&#8221;</p><p>This architectural shift changes everything about how systems handle load. Imagine your e-commerce API receives 10,000 order requests per second during a flash sale, but your payment processor can only handle 2,000 per second. Without a queue, 8,000 requests would fail or timeout. With a queue, all 10,000 requests succeed immediately (the message is queued), and the payment processor works through the backlog over the next few minutes.</p><p>The trade-off is clear: you give up instant confirmation in exchange for resilience. Users don&#8217;t know immediately if their payment succeeded, they get a &#8220;we&#8217;re processing your order&#8221; message instead. This works perfectly for orders, background jobs, and notifications, but poorly for interactive requests like search where users need immediate results.</p><h2>How This Works in Production</h2><p>Let&#8217;s continue with the e-commerce example and see how Amazon SQS (a popular message queue service) handles this in production. When a customer clicks &#8220;Place Order,&#8221; your API writes the order details to an SQS queue in under 100 milliseconds and returns a confirmation page. The customer sees &#8220;Order received&#8221; and can continue shopping.</p><p>Behind the scenes, multiple consumer instances are continuously polling the queue for work. When a consumer receives a message, SQS marks it invisible to other consumers for 30 seconds (the visibility timeout). This prevents two consumers from processing the same order simultaneously. The consumer validates the order, charges the payment method, updates inventory, and sends a confirmation email. Once complete, it acknowledges the message, and SQS permanently deletes it.</p><p>Here&#8217;s the counterintuitive part: most production queues use &#8220;at least once&#8221; delivery, meaning the same order might be processed twice if a consumer crashes before acknowledging. This seems like a bug, but it&#8217;s actually the practical choice. True &#8220;exactly once&#8221; processing requires complex distributed transactions that add significant latency. Instead, systems make their processing idempotent: they store processed order IDs in a cache for 24 to 72 hours. If a duplicate arrives, they check the cache and skip reprocessing. This achieves the same correctness with much simpler infrastructure.</p><p>During normal load, messages wait in the queue for only seconds. During that flash sale spike, the queue might accumulate thousands of messages, and end-to-end processing time stretches to minutes. But no orders are lost, and the system never tells customers it&#8217;s overloaded. You simply add more consumer instances to work through the backlog faster.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.systemoverflow.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.systemoverflow.com/subscribe?"><span>Subscribe now</span></a></p><p></p><h2>Key Takeaway</h2><p>Message queues transform how distributed systems handle load by decoupling services and absorbing traffic spikes, trading immediate feedback for resilience and independent scaling. Understanding Message Queue Fundamentals is foundational for building scalable systems. Learn more in-depth about Message Queue Fundamentals on System Overflow, with detailed cards covering advanced patterns, edge cases, and production scenarios.</p><div><hr></div><p><em>Learn more in-depth about Message Queue Fundamentals on <a href="https://www.systemoverflow.com/">System Overflow</a></em></p>]]></content:encoded></item><item><title><![CDATA[How Netflix Maintains Reliability Using Service-Level Prioritized Load Shedding]]></title><description><![CDATA[How Netflix Keeps Streaming During Traffic Spikes using Load Shedding]]></description><link>https://blog.systemoverflow.com/p/how-netflix-maintains-reliability</link><guid isPermaLink="false">https://blog.systemoverflow.com/p/how-netflix-maintains-reliability</guid><dc:creator><![CDATA[System Overflow]]></dc:creator><pubDate>Sat, 06 Dec 2025 12:38:42 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!cfad!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6143ec2-faca-4b1c-acda-d91e681bc006_4494x2254.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When millions of viewers simultaneously click play on a new season of a hit show, Netflix&#8217;s infrastructure faces a sudden surge that can easily overwhelm its servers. Unlike gradual increases that autoscaling can handle, these massive spikes happen faster than new servers can spin up. This is where sophisticated load shedding transforms potential catastrophic failure into graceful degradation, ensuring most viewers can keep watching even when the system is pushed beyond its limits.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cfad!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6143ec2-faca-4b1c-acda-d91e681bc006_4494x2254.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cfad!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6143ec2-faca-4b1c-acda-d91e681bc006_4494x2254.png 424w, https://substackcdn.com/image/fetch/$s_!cfad!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6143ec2-faca-4b1c-acda-d91e681bc006_4494x2254.png 848w, https://substackcdn.com/image/fetch/$s_!cfad!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6143ec2-faca-4b1c-acda-d91e681bc006_4494x2254.png 1272w, https://substackcdn.com/image/fetch/$s_!cfad!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6143ec2-faca-4b1c-acda-d91e681bc006_4494x2254.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cfad!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6143ec2-faca-4b1c-acda-d91e681bc006_4494x2254.png" width="1456" height="730" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a6143ec2-faca-4b1c-acda-d91e681bc006_4494x2254.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:730,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Enhancing Reliability Using Service-Level Prioritized Load Shedding: Netflix at QCon SF 2025 - Overview&quot;,&quot;title&quot;:&quot;Enhancing Reliability Using Service-Level Prioritized Load Shedding: Netflix at QCon SF 2025 - Overview&quot;,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Enhancing Reliability Using Service-Level Prioritized Load Shedding: Netflix at QCon SF 2025 - Overview" title="Enhancing Reliability Using Service-Level Prioritized Load Shedding: Netflix at QCon SF 2025 - Overview" srcset="https://substackcdn.com/image/fetch/$s_!cfad!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6143ec2-faca-4b1c-acda-d91e681bc006_4494x2254.png 424w, https://substackcdn.com/image/fetch/$s_!cfad!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6143ec2-faca-4b1c-acda-d91e681bc006_4494x2254.png 848w, https://substackcdn.com/image/fetch/$s_!cfad!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6143ec2-faca-4b1c-acda-d91e681bc006_4494x2254.png 1272w, https://substackcdn.com/image/fetch/$s_!cfad!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6143ec2-faca-4b1c-acda-d91e681bc006_4494x2254.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Enhancing Reliability Using Service-Level Prioritized Load Shedding: Netflix at QCon SF 2025 - Overview</figcaption></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.systemoverflow.com/pricing&quot;,&quot;text&quot;:&quot;Last Day: Cyber Monday Sale - 15% OFF&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.systemoverflow.com/pricing"><span>Last Day: Cyber Monday Sale - 15% OFF</span></a></p><p>Load shedding is the practice of intentionally rejecting some requests when a system approaches capacity limits, protecting it from complete collapse. Think of it like a nightclub with a maximum occupancy: instead of letting everyone in and creating a dangerous, unpleasant experience for all, the bouncer controls entry to maintain a good experience for those inside.</p><p>The fundamental challenge Netflix engineers identified is that traditional autoscaling assumes you have time to respond. When a popular show drops at midnight and millions of users flood the service within minutes, spinning up new server capacity takes too long. The alternative, provisioning enough capacity for theoretical maximum peaks, would mean running servers at perhaps 20% utilization most of the time, wasting millions of dollars annually.</p><p>This is where Netflix&#8217;s conceptual resilience model becomes critical. They quantify system health using two buffers. The Success Buffer represents how much traffic above baseline a service can handle without performance degradation. If your service normally runs at 1,000 requests per second and can handle up to 1,500 requests per second before latency increases, you have a 500 request per second Success Buffer.</p><p>The Failure Buffer is equally important but often overlooked. This represents the system&#8217;s capacity to gracefully reject excess requests without cascading failures. When traffic hits 1,600 requests per second, the system needs enough headroom to evaluate incoming requests, make rejection decisions, and send proper error responses. Without this buffer, the service simply freezes or crashes, taking everything down.</p><p>The breakthrough Netflix achieved was recognizing that not all requests deserve equal treatment during overload. Traditional load shedding dropped requests randomly, like closing your eyes and randomly turning away people at the nightclub entrance. This means a paying customer trying to enter might get rejected while someone just looking for the bathroom gets in.</p><p>Service-Level-Prioritized Load Shedding assigns priorities to different request types based on their business value. When you click play on a show, that&#8217;s a high-priority, user-initiated playback request. But Netflix also makes prefetch requests in the background, preloading content you might watch next. During normal operation, prefetching improves experience. During overload, these low-priority requests get shed first, preserving capacity for actual playback.</p><h2>How Netflix Implements Prioritized Load Shedding</h2><p>The implementation involves moving load shedding decisions from Netflix&#8217;s centralized API Gateway down to individual microservices. This architectural choice creates a surprising advantage: it allows critical requests to dynamically steal capacity from non-critical operations within the same application instance.</p><p>Consider a specific scenario during a major content launch. A backend service handling both user playback requests and background analytics processing normally allocates resources equally. Under traditional load shedding at the gateway, if the gateway drops 30% of traffic randomly, both critical playback and non-critical analytics get reduced proportionally. The service itself still wastes precious CPU cycles on analytics while users can&#8217;t watch their shows.</p><p>With service-level prioritization, the picture changes dramatically. As CPU utilization climbs to 60%, the service automatically begins shedding background analytics requests while continuing to process all playback requests. At 70% utilization, it might shed prefetch operations. Only when utilization reaches 80% does it start rejecting even some user-initiated requests, and even then, it prioritizes based on factors like whether this is a new session versus an ongoing stream.</p><p>The counterintuitive insight here is that optimal load shedding actually increases total request rejection rates compared to waiting until the last moment. By proactively shedding low-priority traffic at 60% utilization, the system maintains its Success Buffer for high-value requests. Services that wait until 95% utilization to start shedding often experience cascading failures because they&#8217;ve exhausted both their Success and Failure Buffers simultaneously.</p><p>Netflix automated this across hundreds of microservices through three integrated pillars. Priority assignment happens early in the request lifecycle through headers that propagate downstream. Critically, services can only maintain or decrease priority, never escalate it, preventing gaming of the system. A prefetch request tagged as low-priority stays low-priority throughout its journey.</p><p>Central configuration generates unique load-shedding functions for each service cluster based on its specific utilization metrics. One service might use CPU as its primary signal, starting non-critical shedding at 60% CPU. Another might use request queue depth, beginning shedding when 200 requests are queued. These thresholds map utilization levels and request priorities to specific rejection probabilities. At 65% CPU, the system might reject 50% of low-priority requests but 0% of high-priority ones. At 75% CPU, it might reject 100% of low-priority and 20% of high-priority requests.</p><p>Automated validation through Netflix&#8217;s Chaos Automation Platform ensures every cluster has adequate buffers before major launches. Engineers inject artificial load spikes weeks in advance, measuring whether services maintain stability and shed appropriately. This validation caught cases where services would have failed during actual launches, allowing teams to adjust configurations proactively.</p><p>The retry strategy prevents the thundering herd problem where shed requests immediately retry, amplifying the overload. When server-side shedding activates, clients scale back all retries. Under heavy load, only high-priority requests retry, and even those use exponential backoff. This coordination between client and server behavior is crucial. Without it, shedding 30% of requests at the server just triggers 30% more retries from clients, creating a feedback loop that makes overload worse.</p><h2>Trade-offs and Architectural Decisions</h2><p>Implementing service-level prioritized load shedding introduces significant complexity compared to simple gateway-based approaches. Each service team must instrument their code to understand and propagate priorities, instrument utilization metrics, and test shedding behavior. For organizations with dozens rather than hundreds of services, centralized gateway shedding might provide 80% of the benefit with 20% of the complexity.</p><p>The decision of when to start shedding involves balancing user experience against resource efficiency. Starting shedding too early (say, at 40% utilization) wastes capacity and unnecessarily degrades service for low-priority but still valuable requests. Starting too late (at 90% utilization) risks exhausting your Failure Buffer and experiencing cascading failures. Netflix found the sweet spot typically falls between 60-70% utilization for non-critical shedding.</p><p>Different companies make different architectural choices based on their traffic patterns. Services with gradual, predictable load increases might rely primarily on autoscaling with minimal load shedding. Services with sudden spikes (ticket sales, limited product drops) need aggressive load shedding. Companies like Ticketmaster implement virtual waiting rooms rather than shedding, queuing excess users transparently. The right approach depends on whether maintaining queue position has business value.</p><p>Cost implications are substantial but nuanced. Load shedding allows running closer to capacity limits, potentially reducing infrastructure costs by 30-40%. However, the engineering investment in building, testing, and maintaining the shedding infrastructure is significant. Organizations must weigh these ongoing engineering costs against infrastructure savings and improved reliability during peak events.</p><h2>Key Takeaway</h2><p>Service-level prioritized load shedding transforms graceful degradation from a blunt instrument into a precision tool, ensuring systems protect their most valuable traffic when overwhelmed. By treating requests differently based on business impact, maintaining separate Success and Failure buffers, and automating configuration across distributed systems, services can survive traffic spikes that would otherwise cause complete outages. Learn more about Enhancing Reliability Using Service-Level Prioritized Load Shedding: Netflix at QCon SF 2025 and other system design concepts on System Overflow.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.systemoverflow.com/pricing&quot;,&quot;text&quot;:&quot;Last Day: Cyber Monday Sale - 15% OFF&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.systemoverflow.com/pricing"><span>Last Day: Cyber Monday Sale - 15% OFF</span></a></p><div><hr></div><p><em>Learn more about rate limiting and other system design concepts on <a href="https://www.systemoverflow.com/">System Overflow.</a></em></p>]]></content:encoded></item><item><title><![CDATA[Understanding Cache Patterns: Aside, Through, and Back]]></title><description><![CDATA[Cache patterns are fundamental architectural decisions that shape your system&#8217;s performance characteristics and operational complexity.]]></description><link>https://blog.systemoverflow.com/p/understanding-cache-patterns-aside</link><guid isPermaLink="false">https://blog.systemoverflow.com/p/understanding-cache-patterns-aside</guid><dc:creator><![CDATA[System Overflow]]></dc:creator><pubDate>Sat, 29 Nov 2025 07:28:11 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!6Cuk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c250d2e-acad-4eed-aa37-84f1f0992ad6_1892x1204.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Every time you scroll through Instagram and instantly see photos load, or refresh Twitter to see new tweets appear immediately, caching patterns are working behind the scenes. These patterns determine how data flows between blazingly fast in-memory caches and slower persistent databases. Getting this right means the difference between sub-millisecond response times and multi-second page loads.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6Cuk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c250d2e-acad-4eed-aa37-84f1f0992ad6_1892x1204.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6Cuk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c250d2e-acad-4eed-aa37-84f1f0992ad6_1892x1204.png 424w, https://substackcdn.com/image/fetch/$s_!6Cuk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c250d2e-acad-4eed-aa37-84f1f0992ad6_1892x1204.png 848w, https://substackcdn.com/image/fetch/$s_!6Cuk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c250d2e-acad-4eed-aa37-84f1f0992ad6_1892x1204.png 1272w, https://substackcdn.com/image/fetch/$s_!6Cuk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c250d2e-acad-4eed-aa37-84f1f0992ad6_1892x1204.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6Cuk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c250d2e-acad-4eed-aa37-84f1f0992ad6_1892x1204.png" width="1456" height="927" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3c250d2e-acad-4eed-aa37-84f1f0992ad6_1892x1204.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:927,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Cache Patterns (Aside, Through, Back) - Overview&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Cache Patterns (Aside, Through, Back) - Overview" title="Cache Patterns (Aside, Through, Back) - Overview" srcset="https://substackcdn.com/image/fetch/$s_!6Cuk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c250d2e-acad-4eed-aa37-84f1f0992ad6_1892x1204.png 424w, https://substackcdn.com/image/fetch/$s_!6Cuk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c250d2e-acad-4eed-aa37-84f1f0992ad6_1892x1204.png 848w, https://substackcdn.com/image/fetch/$s_!6Cuk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c250d2e-acad-4eed-aa37-84f1f0992ad6_1892x1204.png 1272w, https://substackcdn.com/image/fetch/$s_!6Cuk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c250d2e-acad-4eed-aa37-84f1f0992ad6_1892x1204.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Cache Patterns (Aside, Through, Back) - Overview</figcaption></figure></div><h2>What Are Cache Patterns?</h2><p>Cache patterns define who controls cache population and when data gets written to your source of truth (your database). Think of caching like a restaurant kitchen: Cache Aside is when the waiter (your application) checks if a dish is ready on the counter, and if not, goes to the kitchen to get it. Read Through is when the waiter always asks the expeditor (cache layer), who handles fetching from the kitchen automatically. Write Back is when orders go on a ticket board first, then get batched to the kitchen later.</p><p><strong>Cache Aside</strong> puts your application in full control. On reads, your app checks the cache first. On a miss, it loads from the database, stores the result in cache with an expiration time, and returns the data. On writes, you update the database first, then delete the cached entry to prevent serving stale data. This pattern excels for read-heavy workloads where you want fine-grained control over what gets cached.</p><p><strong>Read Through</strong> moves responsibility to the cache layer itself. Your application always reads through the cache, which automatically fetches from the database on misses. This centralizes logic and enables smart features like request coalescing (combining multiple requests for the same key into one database fetch).</p><p><strong>Write Back</strong> optimizes for write speed by acknowledging writes immediately to the cache, then persisting to the database asynchronously in batches. This delivers the fastest write latency but risks data loss if the cache fails before flushing.</p><h2>How This Works in Production</h2><p>Let&#8217;s see how Meta uses Cache Aside with Memcache at massive scale for their social graph data. When you load a friend&#8217;s profile, the application first checks Memcache for that user&#8217;s data. On a cache hit (which happens over 90% of the time), Memcache returns the data in under a millisecond. This is why profile pages feel instant.</p><p>On a cache miss, the application queries MySQL, which takes a few milliseconds for an intra-datacenter round trip. It then stores the result in Memcache with a Time To Live before returning it to you. Here&#8217;s the surprising part: Meta deletes cache entries on writes rather than updating them. This prevents a subtle race condition where one server might cache stale data while another is writing new data.</p><p>To prevent cache stampedes (where thousands of servers simultaneously miss a hot celebrity&#8217;s profile and overwhelm MySQL), Meta uses lease tokens. Only one server gets permission to fetch from the database, while others wait briefly for that result. They also add jitter to expiration times, randomizing TTLs by 10-20%. Without this, synchronized expiry would cause massive synchronized misses.</p><p>The trade-off with Cache Aside is application complexity. Your code must handle miss logic, concurrency controls, and invalidation carefully. But this complexity buys you flexibility: you can cache denormalized views, implement different strategies per entity type, and optimize based on specific access patterns.</p><h2>Key Takeaway</h2><p>Cache patterns are fundamental architectural decisions that shape your system&#8217;s performance characteristics and operational complexity. Cache Aside gives maximum control for read-heavy workloads, Read Through simplifies application code with smart cache infrastructure, and Write Back optimizes write latency with durability trade-offs. Understanding Cache Patterns (Aside, Through, Back) is foundational for building scalable systems. Learn more in-depth about Cache Patterns (Aside, Through, Back) on System Overflow, with 3 detailed cards covering advanced patterns, edge cases, and production scenarios.</p><div><hr></div><p><em>Learn more in-depth about Cache Patterns (Aside, Through, Back) on <a href="https://www.systemoverflow.com/learn/caching/cache-patterns">System Overflow</a></em></p>]]></content:encoded></item><item><title><![CDATA[We're now System Overflow (+ Black Friday EXTRA 20% off)]]></title><description><![CDATA[We&#8217;re Now System Overflow]]></description><link>https://blog.systemoverflow.com/p/were-now-system-overflow-black-friday</link><guid isPermaLink="false">https://blog.systemoverflow.com/p/were-now-system-overflow-black-friday</guid><dc:creator><![CDATA[System Overflow]]></dc:creator><pubDate>Fri, 28 Nov 2025 17:25:35 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!JGdu!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e1ac73a-22e8-4297-9692-962a010b649a_512x512.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1><strong>We&#8217;re Now System Overflow</strong></h1><p>If you have been following along, you know us as Preploop. Today, we&#8217;re excited to announce our rebrand to <strong><a href="http://www.systemoverflow.com">System Overflow</a></strong>.</p><h2><strong>Why the Change?</strong></h2><p>The old name suggested we were just another interview prep tool. But that&#8217;s never been what we&#8217;re about.</p><p>We build tools for engineers who want to actually understand system design - not just memorize templates for interviews. Engineers who want depth over breadth. Trade-offs over talking points.</p><p>System Overflow better reflects what the platform does: help you systematically master the fundamentals and advanced concepts that make distributed systems work.</p><p>Same platform. Same 3000+ cards curated by FAANG+ staff-level experts. Your account, progress, streaks, and entire learning journey remain exactly as they were. Just a better name.</p><h2><strong>Black Friday: EXTRA 20% Off All Plans</strong></h2><p>To celebrate the rebrand (and because it&#8217;s Black Friday), we&#8217;re offering <strong>20% off all pro plans</strong> through the end of the week.</p><h4><strong>Early Adopter Pricing + Black Friday Discount:</strong></h4><ul><li><p>6 Months Pro: $59 &#8594; <strong>$47</strong> (20% off)</p></li><li><p>1 Year Pro: $99 &#8594; <strong>$79</strong> (20% off)</p></li></ul><p>The discount applies automatically at checkout using code <strong>BLACKFRIDAY20</strong>.</p><p>This stacks with our early adopter pricing, which won&#8217;t last forever. Once we hit our growth targets, prices go back to regular rates.</p><h4><strong>What You Get with Pro</strong></h4><ul><li><p>Unlimited learning cards (3000+ cards across System Design aspects ML Systems, and Software Engineering)</p></li><li><p>Unlimited design practice problems with AI evaluation</p></li><li><p>Company-specific tagging (Google, Meta, Amazon, Netflix, etc.)</p></li><li><p>Full access to trade-offs, edge cases, and failure modes</p></li></ul><p>Free tier stays at 6 cards per day if you want to try it first.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.systemoverflow.com/pricing&quot;,&quot;text&quot;:&quot;Upgrade to Pro - BLACK FRIDAY OFFER&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.systemoverflow.com/pricing"><span>Upgrade to Pro - BLACK FRIDAY OFFER</span></a></p><h2><strong>What&#8217;s Next</strong></h2><p>The rebrand is just the beginning. We&#8217;re shipping:</p><ul><li><p>Audio explanations for every card (already live for 100+ concepts)</p></li><li><p>YouTube videos breaking down complex system design problems</p></li><li><p>AI Mock Interviews (not just another AI gimmick - substantive practice that tests your understanding)</p></li><li><p>Company-specific learning paths</p></li></ul><p>If you&#8217;ve bookmarked preploop.io, update your links to <a href="http://www.systemoverflow.com">http://www.systemoverflow.com</a>. All old links redirect automatically, so nothing breaks.</p><p>Thanks for being part of this journey.</p><p><em>P.S. Black Friday discount ends November 30th at midnight UTC. Honestly, this is our biggest sale.</em></p>]]></content:encoded></item><item><title><![CDATA[How ChatGPT Actually Generates Your Response in Real Time]]></title><description><![CDATA[Every time you ask ChatGPT a question and watch the response stream back word by word, a sophisticated inference pipeline is orchestrating dozens of operations across multiple systems.]]></description><link>https://blog.systemoverflow.com/p/how-chatgpt-actually-generates-your</link><guid isPermaLink="false">https://blog.systemoverflow.com/p/how-chatgpt-actually-generates-your</guid><dc:creator><![CDATA[System Overflow]]></dc:creator><pubDate>Sat, 08 Nov 2025 16:14:20 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!9JHV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13e50b76-7d09-4473-a411-16ff46c68313_4533x1568.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Every time you ask ChatGPT a question and watch the response stream back word by word, a sophisticated inference pipeline is orchestrating dozens of operations across multiple systems. Understanding this pipeline reveals why some responses appear instantly while others take several seconds, and why certain prompts occasionally fail or produce unexpected results.</p><h2>The Journey From Send to Response</h2><p>When you press Send, your message triggers a complex multi-stage process that transforms simple text into contextually aware responses. The system doesn&#8217;t just pass your question to a model and return an answer. Instead, it assembles context, validates safety constraints, manages computational resources, and carefully orchestrates the generation process across specialized hardware.</p><h4>Understanding Context Windows</h4><p>The core challenge is that language models cannot simply &#8220;think&#8221; about your question. They process text as sequences of tokens (roughly word fragments), and they have strict limits on how much text they can consider at once. This boundary is called the context window. Modern production models range from 8,000 to over 1 million tokens, but regardless of size, this is a hard constraint. The model literally cannot see beyond it.</p><p>Think of context assembly like packing a suitcase with a strict weight limit for a trip. You have system instructions (the essentials you must bring), conversation history (items from previous trips you want to reference), tool definitions (specialized equipment you might need), and your new message (today&#8217;s additions). If everything doesn&#8217;t fit, the system must decide what to trim or compress. This is why very long conversations eventually &#8220;forget&#8221; earlier details. The platform summarizes or drops old turns to make room for new ones.</p><h4>The Two Inference Phases</h4><p>Once context is assembled and validated through safety checks, the actual inference begins in two distinct phases:</p><p><strong>Prefill:</strong> The model reads every input token and computes its initial internal state. This is computationally expensive because the model must process the entire context in one pass. For a 2,500 token prompt, this typically takes 400 milliseconds under normal load.</p><p><strong>Decode:</strong> The model generates output one token at a time, feeding each new token back into its state to produce the next one. This happens at roughly 25 tokens per second, depending on server load and model size.</p><p>This is why you see responses stream word by word rather than appearing all at once. The system starts sending tokens as soon as the first one is ready, hiding the remaining computation time behind progressive delivery. For users, this creates the perception of low latency even when generating a full response takes many seconds. Without streaming, you would wait in silence for the complete answer, making the system feel sluggish and unresponsive.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9JHV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13e50b76-7d09-4473-a411-16ff46c68313_4533x1568.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9JHV!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13e50b76-7d09-4473-a411-16ff46c68313_4533x1568.png 424w, https://substackcdn.com/image/fetch/$s_!9JHV!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13e50b76-7d09-4473-a411-16ff46c68313_4533x1568.png 848w, https://substackcdn.com/image/fetch/$s_!9JHV!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13e50b76-7d09-4473-a411-16ff46c68313_4533x1568.png 1272w, https://substackcdn.com/image/fetch/$s_!9JHV!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13e50b76-7d09-4473-a411-16ff46c68313_4533x1568.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9JHV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13e50b76-7d09-4473-a411-16ff46c68313_4533x1568.png" width="1456" height="504" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/13e50b76-7d09-4473-a411-16ff46c68313_4533x1568.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:504,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;What Actually Happens When You Press &#8216;Send&#8217; to ChatGPT - Overview&quot;,&quot;title&quot;:&quot;What Actually Happens When You Press &#8216;Send&#8217; to ChatGPT - Overview&quot;,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="What Actually Happens When You Press &#8216;Send&#8217; to ChatGPT - Overview" title="What Actually Happens When You Press &#8216;Send&#8217; to ChatGPT - Overview" srcset="https://substackcdn.com/image/fetch/$s_!9JHV!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13e50b76-7d09-4473-a411-16ff46c68313_4533x1568.png 424w, https://substackcdn.com/image/fetch/$s_!9JHV!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13e50b76-7d09-4473-a411-16ff46c68313_4533x1568.png 848w, https://substackcdn.com/image/fetch/$s_!9JHV!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13e50b76-7d09-4473-a411-16ff46c68313_4533x1568.png 1272w, https://substackcdn.com/image/fetch/$s_!9JHV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13e50b76-7d09-4473-a411-16ff46c68313_4533x1568.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">What Actually Happens When You Press &#8216;Send&#8217; to ChatGPT - Overview</figcaption></figure></div><h2>Inside a Production Serving Stack</h2><p>Let&#8217;s walk through a realistic scenario. You open ChatGPT and ask: &#8220;What are three unique gift ideas for a software engineer who loves coffee?&#8221; with about 2,000 tokens of prior conversation history. The platform assembles roughly 2,500 tokens total including system instructions and tool schemas.</p><h4>Request Routing and Priority Queuing</h4><p>The request hits the API gateway, which enforces rate limits and routes based on your subscription tier. As a paid user, your request enters a priority queue that protects you from free-tier traffic spikes. The scheduler groups your request with others targeting the same model version and similar characteristics into a dynamic batch.</p><p>Here&#8217;s the counterintuitive part: batching actually increases your individual latency slightly (often 50 to 200 milliseconds at the median, sometimes a full second or more at p99 during peak load) but improves overall system efficiency by 2 to 8 times. The platform accepts this trade-off because it dramatically reduces the GPU hours needed to serve millions of requests.</p><h4>GPU Processing and Inference</h4><p>Your batched request lands on an NVIDIA H100 GPU, which costs providers roughly to per hour in cloud environments. The prefill phase processes your 2,500 input tokens, taking approximately 400 milliseconds under normal load. This first-token latency dominates your perceived wait time for short prompts. The model then begins decode, generating tokens at roughly 25 per second given current server load and model size.</p><h4>Caching Optimizations</h4><p>But the system isn&#8217;t just generating text blindly. It&#8217;s using two critical optimizations:</p><p><strong>KV Caching:</strong> Stores intermediate attention computations so the model doesn&#8217;t recompute from scratch for every new token. Without this optimization, decode would be prohibitively expensive.</p><p><strong>Prompt Caching:</strong> Leverages the immutable parts of your context (system instructions and tool schemas), skipping their recomputation entirely across requests. This can reduce prefill time by 60-80% for subsequent requests.</p><h4>Tool Calls and External Services</h4><p>After generating about 15 tokens, the model decides it needs current information about coffee accessories. It emits a structured tool call to perform a search. The platform executes this external service call, which adds 800 milliseconds (internal tool latency varies from 100 milliseconds for cached data services to 2-3 seconds for web searches). The results get appended to your context, and the model continues decoding with fresh information. This is why responses sometimes pause briefly mid-generation before continuing with specific details.</p><h4>Output Safety and Streaming</h4><p>Throughout decode, output safety checks run in parallel. These add minimal latency (typically 30-80 milliseconds) for most requests but can block content after generation completes if policy violations are detected. The streaming transport uses server-sent events to deliver each token chunk with metadata like token position and status flags, allowing your browser to render progressively.</p><p>The full response of roughly 180 tokens completes in about 8 seconds total: 400ms prefill, 800ms tool call, plus decode time. Your browser showed the first word after just 400 milliseconds, making the experience feel nearly instantaneous despite significant backend work.</p><h2>Trade-offs and Design Decisions</h2><h4>Throughput vs Tail Latency</h4><p>Production systems face constant tension between throughput and tail latency. Larger batch sizes maximize GPU utilization and reduce cost per request but increase head-of-line blocking. Background workloads like content moderation or summarization can tolerate batches of 64 or 128 requests. Interactive chat with strict latency SLOs (service level objectives, like p95 under 4 seconds to first token) requires smaller batches of 8 to 16 requests or dedicated capacity.</p><h4>Long Context vs Retrieval Augmented Generation</h4><p>The choice between long context windows and retrieval augmented generation presents another fundamental trade-off. Google&#8217;s Gemini 1.5 advertises a 1 million token window, which eliminates complex retrieval orchestration and reduces tool call latency. However, this increases prefill time proportionally and creates memory pressure. At these scales, providers gate access and prioritize paid tiers to maintain p50 latency under 2 seconds for premium users. Retrieval keeps prompts short and costs low but depends entirely on retrieval quality and introduces external dependencies.</p><h4>Common Failure Modes</h4><p>Several failure patterns reveal system boundaries:</p><p><strong>Context overflow</strong> can truncate critical system instructions, causing the model to ignore constraints or forget available tools.</p><p><strong>Tool call loops</strong> happen when schemas are ambiguous, with the model repeatedly calling the same function.</p><p><strong>Cold starts</strong> occur when GPU memory pressure forces worker eviction, adding 15 to 45 seconds of delay while weights reload.</p><p><strong>Moderation races</strong> waste compute by generating many tokens before output filters block the entire response.</p><p>Robust systems cap tool depth, maintain hot GPU pools sized for p95 load, and use early classification to avoid generating content likely to be blocked.</p><h2>The Big Picture</h2><p>The architecture of modern LLM serving reveals a critical insight: perceived latency and actual computational cost often point in opposite directions. Streaming, batching, and caching optimize for user experience and infrastructure efficiency simultaneously, but they introduce complexity in error handling, cost attribution, and capacity planning. Systems that master these trade-offs deliver both responsive user experiences and sustainable unit economics. As models grow larger and context windows expand, the engineering challenge shifts from making inference possible to making it economical at scale while maintaining strict latency guarantees for interactive workloads.</p><div><hr></div><p><em>Learn more Machine Learning System Design concepts on <a href="https://preploop.io/">PrepLoop.io</a></em></p>]]></content:encoded></item><item><title><![CDATA[Leader-Follower Replication: How Distributed Data Stays in Sync]]></title><description><![CDATA[Every time you update your profile on LinkedIn or post a tweet, that change needs to propagate across multiple servers to ensure your data survives hardware failures.]]></description><link>https://blog.systemoverflow.com/p/leader-follower-replication-how-distributed</link><guid isPermaLink="false">https://blog.systemoverflow.com/p/leader-follower-replication-how-distributed</guid><dc:creator><![CDATA[System Overflow]]></dc:creator><pubDate>Wed, 05 Nov 2025 04:21:32 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Pdkg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F461ee550-ddfe-441a-9017-d2742306ed2b_1942x1233.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Every time you update your profile on LinkedIn or post a tweet, that change needs to propagate across multiple servers to ensure your data survives hardware failures. Leader-follower replication is the architecture that makes this possible, powering systems like MySQL, PostgreSQL, MongoDB, and Kafka that handle billions of operations daily.</p><h2>What Is Leader-Follower Replication?</h2><p>Leader-follower replication is a distributed data architecture where one node (the leader) coordinates all write operations, while multiple follower nodes copy those changes to provide redundancy and serve read traffic. This design solves a fundamental problem in distributed systems: how do you keep multiple copies of data consistent while handling failures?</p><p>The architecture works through a simple but powerful pattern. When a client wants to write data (say, updating a user&#8217;s email address), that write goes exclusively to the leader. The leader appends this operation to a replication log with a sequence number, saves it to disk, and then ships this log entry to all followers. Each follower applies these entries in the exact order they were created, ensuring they eventually converge to match the leader&#8217;s state.</p><p>This single-writer design eliminates write conflicts by construction. Since only one node accepts writes, there&#8217;s no ambiguity about which update happened first. Imagine a social media post: the leader decides it&#8217;s post number 12,345 in the system, and every follower applies that exact same post with that exact same number in their local copy.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Pdkg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F461ee550-ddfe-441a-9017-d2742306ed2b_1942x1233.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Pdkg!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F461ee550-ddfe-441a-9017-d2742306ed2b_1942x1233.png 424w, https://substackcdn.com/image/fetch/$s_!Pdkg!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F461ee550-ddfe-441a-9017-d2742306ed2b_1942x1233.png 848w, https://substackcdn.com/image/fetch/$s_!Pdkg!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F461ee550-ddfe-441a-9017-d2742306ed2b_1942x1233.png 1272w, https://substackcdn.com/image/fetch/$s_!Pdkg!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F461ee550-ddfe-441a-9017-d2742306ed2b_1942x1233.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Pdkg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F461ee550-ddfe-441a-9017-d2742306ed2b_1942x1233.png" width="1456" height="924" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/461ee550-ddfe-441a-9017-d2742306ed2b_1942x1233.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:924,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Leader-Follower Replication - Overview&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Leader-Follower Replication - Overview" title="Leader-Follower Replication - Overview" srcset="https://substackcdn.com/image/fetch/$s_!Pdkg!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F461ee550-ddfe-441a-9017-d2742306ed2b_1942x1233.png 424w, https://substackcdn.com/image/fetch/$s_!Pdkg!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F461ee550-ddfe-441a-9017-d2742306ed2b_1942x1233.png 848w, https://substackcdn.com/image/fetch/$s_!Pdkg!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F461ee550-ddfe-441a-9017-d2742306ed2b_1942x1233.png 1272w, https://substackcdn.com/image/fetch/$s_!Pdkg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F461ee550-ddfe-441a-9017-d2742306ed2b_1942x1233.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Leader-Follower Replication - Overview</figcaption></figure></div><h2>How This Works in Production</h2><p>Let&#8217;s walk through what happens when you update your email address in a system using leader-follower replication with three nodes: one leader and two followers.</p><p>Your application sends the update request to the leader. The leader writes &#8220;Change user_id=789 email to new@example.com&#8221; into its replication log as entry 12,345, saves it to local disk (typically taking under 1 millisecond), and immediately sends this log entry to both followers over the network. Each follower receives the entry, applies it to their local database in order, and sends back an acknowledgment.</p><p>Here&#8217;s where the crucial trade-off appears: does the leader confirm your update immediately after saving locally (asynchronous replication), or does it wait for at least one follower to acknowledge (synchronous replication)? Asynchronous mode gives you sub-millisecond response times but risks losing recent writes if the leader crashes before followers replicate them. Synchronous mode adds one network round trip (typically 1 to 5 milliseconds within a data center) but guarantees your data exists on multiple machines before you get confirmation.</p><p>Most production systems use semi-synchronous replication: they wait for one follower to acknowledge for durability, while keeping additional followers asynchronous for read scaling. MySQL and PostgreSQL commonly run this way, achieving under 10 millisecond write latency while protecting against data loss. The followers can then serve read queries, distributing load across the cluster. If the leader fails, the system promotes one of the up-to-date followers to become the new leader, typically completing this failover in 10 to 30 seconds.</p><h2>Key Takeaway</h2><p>Leader-follower replication provides a clean separation of concerns: one node coordinates writes while others replicate for durability and scale reads. Understanding Leader-Follower Replication is foundational for building scalable systems. Learn more in-depth about Leader-Follower Replication on PrepLoop.io, with 3 detailed cards covering advanced patterns, edge cases, and production scenarios.</p><div><hr></div><p><em>Learn more in-depth about Leader-Follower Replication on <a href="https://preploop.io/">PrepLoop.io</a></em></p>]]></content:encoded></item><item><title><![CDATA[Consensus Algorithms (Raft, Paxos)]]></title><description><![CDATA[Understanding Consensus Algorithms: How Raft and Paxos Work]]></description><link>https://blog.systemoverflow.com/p/consensus-algorithms-raft-paxos</link><guid isPermaLink="false">https://blog.systemoverflow.com/p/consensus-algorithms-raft-paxos</guid><dc:creator><![CDATA[System Overflow]]></dc:creator><pubDate>Sun, 02 Nov 2025 14:04:53 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!sVnm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1e8efa2-520b-4913-a3a6-c9cc17477165_1779x1146.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1>Understanding Consensus Algorithms: How Raft and Paxos Work</h1><p>Every time you book an Uber, update a Google Doc with teammates, or post a message in Slack that instantly appears for everyone, consensus algorithms are quietly ensuring all servers agree on the exact order of events. Without these algorithms, distributed systems would be chaos; servers would disagree about which ride request came first, whose edit won, or what messages were sent. Consensus algorithms like Raft and Paxos are the invisible foundation that makes modern distributed applications reliable and consistent.</p><h2>What Are Consensus Algorithms?</h2><p>Consensus algorithms solve a deceptively simple problem: getting multiple unreliable computers to agree on a single sequence of decisions, even when some servers crash or networks fail. This agreement is called &#8220;quorum consensus,&#8221; and it requires maintaining at least 2f+1 replicas to tolerate f failures.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.systemoverflow.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption"></p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!sVnm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1e8efa2-520b-4913-a3a6-c9cc17477165_1779x1146.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!sVnm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1e8efa2-520b-4913-a3a6-c9cc17477165_1779x1146.png 424w, https://substackcdn.com/image/fetch/$s_!sVnm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1e8efa2-520b-4913-a3a6-c9cc17477165_1779x1146.png 848w, https://substackcdn.com/image/fetch/$s_!sVnm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1e8efa2-520b-4913-a3a6-c9cc17477165_1779x1146.png 1272w, https://substackcdn.com/image/fetch/$s_!sVnm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1e8efa2-520b-4913-a3a6-c9cc17477165_1779x1146.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!sVnm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1e8efa2-520b-4913-a3a6-c9cc17477165_1779x1146.png" width="1456" height="938" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f1e8efa2-520b-4913-a3a6-c9cc17477165_1779x1146.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:938,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Consensus Algorithms (Raft, Paxos) - Basic Concept&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Consensus Algorithms (Raft, Paxos) - Basic Concept" title="Consensus Algorithms (Raft, Paxos) - Basic Concept" srcset="https://substackcdn.com/image/fetch/$s_!sVnm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1e8efa2-520b-4913-a3a6-c9cc17477165_1779x1146.png 424w, https://substackcdn.com/image/fetch/$s_!sVnm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1e8efa2-520b-4913-a3a6-c9cc17477165_1779x1146.png 848w, https://substackcdn.com/image/fetch/$s_!sVnm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1e8efa2-520b-4913-a3a6-c9cc17477165_1779x1146.png 1272w, https://substackcdn.com/image/fetch/$s_!sVnm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1e8efa2-520b-4913-a3a6-c9cc17477165_1779x1146.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Here&#8217;s why this math matters: with 3 servers, you need 2 to agree (tolerating 1 failure). With 5 servers, you need 3 to agree (tolerating 2 failures). The magic is that any two majorities must overlap in at least one server that &#8220;remembers&#8221; prior decisions, preventing conflicting choices from being committed.</p><p>Consensus systems prioritize two critical properties. <strong>Safety</strong> ensures the system never commits conflicting decisions&#8212;this is absolute and never violated. <strong>Liveness</strong> ensures the system eventually makes progress when a majority is available&#8212;this can be temporarily suspended during network partitions.</p><p>Both Raft and Multi-Paxos maintain a replicated, ordered log across servers, but they differ in approach. Multi-Paxos evolved as an optimization of basic Paxos, where a stable leader handles proposals after an initial election. However, the original literature leaves many implementation details unspecified, making it notoriously difficult to implement correctly.</p><p>Raft explicitly breaks the problem into three clear components: leader election using randomized timeouts, log replication where the leader manages indexed entries, and membership changes. When followers don&#8217;t receive heartbeats within 150-300 milliseconds (in wide-area networks), they start a new election. This clarity is why systems like etcd, Consul, and CockroachDB chose Raft over Paxos.</p><h2>Real-World Implementation</h2><p>Google Spanner uses Paxos groups with 5 replicas spread across 3+ regions, accepting 50-200 milliseconds of commit latency for exceptional durability. Each Paxos group manages a shard of data, and Spanner runs thousands of these groups to scale horizontally rather than trying to scale a single consensus group.</p><p>The performance characteristics are predictable: a 3-node cluster in a single availability zone with NVMe storage achieves 2-6 milliseconds p50 latency. This breaks down to roughly 0.2-2ms for the leader&#8217;s fsync (durably writing to disk), 0.5-1ms for network transmission, and 0.2-2ms for follower fsync, plus protocol overhead.</p><p>Cross-region deployments face stark trade-offs. Multi-zone configurations within one region add only 1-2ms round-trip time while protecting against zone failures&#8212;an excellent balance for most applications. Cross-region setups sacrifice latency (70-100ms coast-to-coast, 150-250ms transoceanic) but provide resilience against entire region outages.</p><p>Production systems scale throughput by sharding data across independent consensus groups, each with its own leader. Within a group, batching small entries amortizes fsync costs, but batches must complete within 10-50ms to keep tail latencies acceptable.</p><h2>Key Takeaways</h2><p>Consensus algorithms enable distributed systems to maintain consistency despite failures. The choice between 3 and 5 replicas directly impacts both availability (how many failures you tolerate) and performance (how many acknowledgments you wait for).</p><p>The fundamental trade-off is geographic: single-region deployments offer low latency but regional vulnerability, while multi-region setups provide disaster resilience at the cost of write latency. Most systems start with multi-zone single-region deployments for the best balance.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!G1Z0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a82626b-c950-4fbb-9304-2b95d70d75ae_1946x972.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!G1Z0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a82626b-c950-4fbb-9304-2b95d70d75ae_1946x972.png 424w, https://substackcdn.com/image/fetch/$s_!G1Z0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a82626b-c950-4fbb-9304-2b95d70d75ae_1946x972.png 848w, https://substackcdn.com/image/fetch/$s_!G1Z0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a82626b-c950-4fbb-9304-2b95d70d75ae_1946x972.png 1272w, https://substackcdn.com/image/fetch/$s_!G1Z0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a82626b-c950-4fbb-9304-2b95d70d75ae_1946x972.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!G1Z0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a82626b-c950-4fbb-9304-2b95d70d75ae_1946x972.png" width="1456" height="727" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9a82626b-c950-4fbb-9304-2b95d70d75ae_1946x972.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:727,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Consensus Algorithms (Raft, Paxos) - Complete System&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Consensus Algorithms (Raft, Paxos) - Complete System" title="Consensus Algorithms (Raft, Paxos) - Complete System" srcset="https://substackcdn.com/image/fetch/$s_!G1Z0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a82626b-c950-4fbb-9304-2b95d70d75ae_1946x972.png 424w, https://substackcdn.com/image/fetch/$s_!G1Z0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a82626b-c950-4fbb-9304-2b95d70d75ae_1946x972.png 848w, https://substackcdn.com/image/fetch/$s_!G1Z0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a82626b-c950-4fbb-9304-2b95d70d75ae_1946x972.png 1272w, https://substackcdn.com/image/fetch/$s_!G1Z0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a82626b-c950-4fbb-9304-2b95d70d75ae_1946x972.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Understanding Consensus Algorithms (Raft, Paxos) is foundational for building scalable systems. Learn more in-depth about Consensus Algorithms (Raft, Paxos) on PrepLoop.io, with 3 detailed cards covering advanced patterns, edge cases, and production scenarios.</p><div><hr></div><p><em>Learn more in-depth about Consensus Algorithms (Raft, Paxos) on <a href="https://preploop.io/">PrepLoop.io</a></em></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.systemoverflow.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading PrepLoop - System Design Letters! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[OLTP vs OLAP: Understanding Transactional vs Analytical Systems]]></title><description><![CDATA[Every time you check your bank balance online and then immediately use that card to buy coffee, you&#8217;re experiencing the seamless coordination between two fundamentally different data processing systems.]]></description><link>https://blog.systemoverflow.com/p/oltp-vs-olap-understanding-transactional</link><guid isPermaLink="false">https://blog.systemoverflow.com/p/oltp-vs-olap-understanding-transactional</guid><dc:creator><![CDATA[System Overflow]]></dc:creator><pubDate>Sun, 02 Nov 2025 07:16:01 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!EVNo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd103087-aa0f-43ea-b4cb-9b511c7cf4e5_3017x748.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Every time you check your bank balance online and then immediately use that card to buy coffee, you&#8217;re experiencing the seamless coordination between two fundamentally different data processing systems. Behind the scenes, OLTP systems handle your transaction in milliseconds while OLAP systems prepare that data for monthly spending reports and fraud detection algorithms. Understanding this split is crucial for any engineer building applications that need both real-time user interactions and analytical insights.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.systemoverflow.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading PrepLoop - System Design Letters! Subscribe for free.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Core Concept: Two Different Worlds of Data Processing</h2><p>Online Transaction Processing (OLTP) and Online Analytical Processing (OLAP) represent two fundamentally different approaches to handling data, each optimized for completely different workload shapes and business requirements.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!EVNo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd103087-aa0f-43ea-b4cb-9b511c7cf4e5_3017x748.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EVNo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd103087-aa0f-43ea-b4cb-9b511c7cf4e5_3017x748.png 424w, https://substackcdn.com/image/fetch/$s_!EVNo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd103087-aa0f-43ea-b4cb-9b511c7cf4e5_3017x748.png 848w, https://substackcdn.com/image/fetch/$s_!EVNo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd103087-aa0f-43ea-b4cb-9b511c7cf4e5_3017x748.png 1272w, https://substackcdn.com/image/fetch/$s_!EVNo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd103087-aa0f-43ea-b4cb-9b511c7cf4e5_3017x748.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EVNo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd103087-aa0f-43ea-b4cb-9b511c7cf4e5_3017x748.png" width="1456" height="361" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bd103087-aa0f-43ea-b4cb-9b511c7cf4e5_3017x748.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:361,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;OLTP vs OLAP - Basic Concept&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="OLTP vs OLAP - Basic Concept" title="OLTP vs OLAP - Basic Concept" srcset="https://substackcdn.com/image/fetch/$s_!EVNo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd103087-aa0f-43ea-b4cb-9b511c7cf4e5_3017x748.png 424w, https://substackcdn.com/image/fetch/$s_!EVNo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd103087-aa0f-43ea-b4cb-9b511c7cf4e5_3017x748.png 848w, https://substackcdn.com/image/fetch/$s_!EVNo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd103087-aa0f-43ea-b4cb-9b511c7cf4e5_3017x748.png 1272w, https://substackcdn.com/image/fetch/$s_!EVNo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd103087-aa0f-43ea-b4cb-9b511c7cf4e5_3017x748.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p><strong>OLTP systems power the operational heart of applications</strong>&#8212;the features users interact with directly. When you post a photo on Instagram, update your Slack status, or place an order on Amazon, you&#8217;re triggering OLTP transactions. These systems are designed for small, fast operations that read or write just a handful of records. The key characteristics are speed and consistency: OLTP transactions typically complete in single-digit milliseconds and must maintain strict correctness guarantees because they affect real-world state that users can immediately see.</p><p>The data modeling in OLTP systems heavily favors normalization. Customer information lives in one table, orders in another, and they&#8217;re connected through foreign key relationships. This approach minimizes write amplification&#8212;when a customer updates their address, you only change one record instead of updating potentially millions of order records. Every piece of data has a single source of truth, and the system maintains referential integrity through constraints and transactions.</p><p><strong>OLAP systems serve an entirely different purpose</strong>&#8212;they&#8217;re built for analysis and decision-making. Instead of handling millions of tiny transactions, OLAP queries might scan billions of rows to calculate revenue trends, identify customer segments, or detect fraud patterns. These queries often take seconds or minutes to complete, but they process vastly more data than any single OLTP transaction ever would.</p><p>Where OLTP prioritizes normalization, OLAP embraces denormalization. Data gets flattened into star or snowflake schemas where dimension information is often duplicated directly into fact tables. This redundancy eliminates the need for expensive joins during query time. When analyzing sales by region, you don&#8217;t want to join orders to customers to addresses&#8212;you want the region information readily available in the sales fact table for immediate aggregation.</p><p>The storage architectures reflect these different priorities. OLTP uses row-oriented storage where entire records are stored together, making it fast to retrieve all information about a specific order or user. OLAP uses columnar storage where each attribute is stored separately, allowing queries to read only the columns they need. This dramatically reduces I/O when calculating something like total revenue&#8212;you only read the revenue column, ignoring the dozens of other attributes in each record.</p><p><strong>The critical insight is workload isolation</strong>. Running analytical queries directly against your production OLTP database is a recipe for disaster. A single analyst query scanning millions of rows can exhaust memory, spike CPU usage, and increase transaction latencies from 20 milliseconds to 500 milliseconds, potentially triggering cascading failures that impact user-facing features.</p><p>This is why successful architectures maintain a clear separation: OLTP systems own the source of truth and handle user-facing operations, while separate OLAP systems receive data through change streams or batch exports. The OLTP system remains focused on serving users quickly and consistently, while the OLAP system can optimize for different access patterns without interfering with production workloads.</p><h2>When to Use This Pattern: Choosing the Right Architecture</h2><p>The OLTP/OLAP split becomes essential when you&#8217;re serving both user-facing transactions and analytical workloads that could interfere with each other. If your application only handles operational data with minimal reporting needs, you might run everything on a well-tuned OLTP database with occasional read replicas for lighter analytical queries.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!eH9-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2473a2b8-a3ca-449d-b976-6d76735e4b2d_5232x1737.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!eH9-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2473a2b8-a3ca-449d-b976-6d76735e4b2d_5232x1737.png 424w, https://substackcdn.com/image/fetch/$s_!eH9-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2473a2b8-a3ca-449d-b976-6d76735e4b2d_5232x1737.png 848w, https://substackcdn.com/image/fetch/$s_!eH9-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2473a2b8-a3ca-449d-b976-6d76735e4b2d_5232x1737.png 1272w, https://substackcdn.com/image/fetch/$s_!eH9-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2473a2b8-a3ca-449d-b976-6d76735e4b2d_5232x1737.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!eH9-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2473a2b8-a3ca-449d-b976-6d76735e4b2d_5232x1737.png" width="1456" height="483" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2473a2b8-a3ca-449d-b976-6d76735e4b2d_5232x1737.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:483,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;OLTP vs OLAP - Complete System&quot;,&quot;title&quot;:&quot;OLTP vs OLAP - Complete System&quot;,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="OLTP vs OLAP - Complete System" title="OLTP vs OLAP - Complete System" srcset="https://substackcdn.com/image/fetch/$s_!eH9-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2473a2b8-a3ca-449d-b976-6d76735e4b2d_5232x1737.png 424w, https://substackcdn.com/image/fetch/$s_!eH9-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2473a2b8-a3ca-449d-b976-6d76735e4b2d_5232x1737.png 848w, https://substackcdn.com/image/fetch/$s_!eH9-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2473a2b8-a3ca-449d-b976-6d76735e4b2d_5232x1737.png 1272w, https://substackcdn.com/image/fetch/$s_!eH9-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2473a2b8-a3ca-449d-b976-6d76735e4b2d_5232x1737.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><strong>Scale indicators</strong> help determine when separation becomes necessary. If your analytical queries regularly scan more than millions of rows, take longer than a few seconds to complete, or run frequently enough to impact transactional performance, it&#8217;s time to consider dedicated OLAP infrastructure. When your business users request historical reporting, trend analysis, or complex aggregations across large time ranges, columnar analytical databases will significantly outperform transactional systems.</p><p><strong>Data freshness requirements</strong> drive architectural decisions. Real-time operational dashboards, fraud detection, and supply-demand matching need streaming CDC pipelines that move data in seconds. Financial reporting, marketing analysis, and strategic planning often work perfectly well with nightly batch exports that reduce system complexity while meeting business needs.</p><p><strong>Team and organizational factors</strong> matter significantly. Maintaining separate OLTP and OLAP systems requires expertise in different technologies, monitoring approaches, and operational practices. Smaller teams might prefer unified platforms that handle both workloads reasonably well, accepting some performance compromises for operational simplicity.</p><p><strong>Cost considerations</strong> vary dramatically between approaches. OLTP systems scale with write amplification and provisioned IOPS, while OLAP systems often charge based on data scanned and compute resources consumed. Understanding your query patterns helps optimize costs&#8212;heavily aggregated data with predictable access patterns works well with pre-computed materialized views, while ad-hoc exploration benefits from flexible columnar scanning.</p><p>The decision often comes down to whether your analytical workloads are predictable enough to isolate through time-based scheduling, resource limits, and read replicas, or whether they&#8217;re diverse and intensive enough to warrant separate infrastructure. Most growing applications eventually hit the point where this separation becomes necessary for both performance and operational reasons.</p><h2>Key Takeaways &amp; Next Steps</h2><p>Understanding OLTP versus OLAP is fundamental to designing systems that serve both users and business intelligence effectively. Remember that OLTP optimizes for fast, consistent transactions while OLAP optimizes for analytical throughput across large datasets. Workload isolation prevents analytical queries from impacting user-facing performance, typically achieved through CDC pipelines that move data from transactional to analytical systems. The architecture choice depends on your scale, freshness requirements, and team capabilities&#8212;start simple but plan for the eventual separation as your system grows.</p><p>Ready to dive deeper into database architectures and distributed systems patterns? <strong>Explore the complete OLTP vs OLAP learning path on PrepLoop.io</strong>, featuring detailed technical cards covering advanced implementation patterns, failure scenarios, and production optimization strategies used by top tech companies.</p><div><hr></div><p><em>Learn more in-depth about OLTP vs OLAP on <a href="https://preploop.io/">PrepLoop.io</a></em></p>]]></content:encoded></item></channel></rss>