<?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[Hands On System Design - Distributed Systems Implementation : Hands On Production-grade distributed log platform  —  Build LogStream (Java/Spring boot)]]></title><description><![CDATA[The gap between "I can code" and "I can build the systems behind Cloudflare, Datadog, and Stripe" is closed by one thing: building it yourself.
Each week you'll ship working code on a real distributed log processing platform — the same architecture pattern that powers companies you've heard of. By the end of the journey: a deployable, observable, fault-tolerant system you can put on GitHub and walk a senior interviewer through.
Not theory. Not whiteboard. Not copy-paste from someone else's repo. You write every line.
Java + Spring Boot + Python · Kafka · Docker · Kubernetes · AWS/GCP]]></description><link>https://sdcourse.substack.com/s/system-design-course-with-java-and</link><image><url>https://substackcdn.com/image/fetch/$s_!zDvF!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7c554ddc-369a-4da8-bd75-54cd71f9a6e9_1024x1024.png</url><title>Hands On System Design - Distributed Systems Implementation : Hands On Production-grade distributed log platform  —  Build LogStream (Java/Spring boot)</title><link>https://sdcourse.substack.com/s/system-design-course-with-java-and</link></image><generator>Substack</generator><lastBuildDate>Thu, 09 Jul 2026 17:09:44 GMT</lastBuildDate><atom:link href="https://sdcourse.substack.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Systemdr, Inc.]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[sdcourse@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[sdcourse@substack.com]]></itunes:email><itunes:name><![CDATA[System Design Course]]></itunes:name></itunes:owner><itunes:author><![CDATA[System Design Course]]></itunes:author><googleplay:owner><![CDATA[sdcourse@substack.com]]></googleplay:owner><googleplay:email><![CDATA[sdcourse@substack.com]]></googleplay:email><googleplay:author><![CDATA[System Design Course]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Day 66: Implement Log Redaction for Compliance]]></title><description><![CDATA[What We&#8217;re Building Today]]></description><link>https://sdcourse.substack.com/p/day-66-implement-log-redaction-for</link><guid isPermaLink="false">https://sdcourse.substack.com/p/day-66-implement-log-redaction-for</guid><dc:creator><![CDATA[System Design Course]]></dc:creator><pubDate>Tue, 07 Jul 2026 08:31:06 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!6DTV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f732e9a-d613-416e-b176-ec634a1cdbfc_6000x4500.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>What We&#8217;re Building Today</h2><p>Today we implement a production-grade log redaction system that automatically sanitizes sensitive data before storage and transmission:</p><ul><li><p><strong>Pattern-based redaction engine</strong> detecting PII, credentials, and regulated data types</p></li><li><p><strong>Streaming redaction pipeline</strong> processing logs at ingestion with zero storage of raw sensitive data</p></li><li><p><strong>Configurable redaction policies</strong> supporting GDPR, HIPAA, PCI-DSS compliance frameworks</p></li><li><p><strong>Audit-preserving redaction</strong> maintaining investigative capability while protecting privacy</p></li></ul><h2>Why This Matters: The Compliance-Performance Paradox</h2><p>When Uber expanded to Europe, they faced a critical challenge: their centralized logging infrastructure inadvertently stored millions of user phone numbers, email addresses, and location data across multiple regions. Under GDPR, each instance represented potential &#8364;20M fines. Their solution? Real-time redaction at ingestion, processing 2M events/second while guaranteeing zero sensitive data persistence.</p><p>The core tension in compliance-focused systems is this: regulations demand you never store sensitive data, yet debugging production incidents requires detailed logs. Traditional approaches&#8212;post-hoc scrubbing or field-level encryption&#8212;either fail audits (data existed, even temporarily) or make logs unusable for troubleshooting. Production systems need redaction that&#8217;s both immediate and intelligent, removing genuine risks while preserving investigative context.</p><p>At scale, this becomes a distributed systems problem. Netflix&#8217;s approach processes logs through three independent redaction layers before storage, accepting 15% performance overhead to guarantee compliance. Each layer uses different detection strategies (regex, ML-based entity recognition, schema validation) to catch what others miss. The architectural insight: <strong>compliance isn&#8217;t a feature you add&#8212;it&#8217;s a constraint that shapes your entire data flow.</strong></p><h2>System Design Deep Dive</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6DTV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f732e9a-d613-416e-b176-ec634a1cdbfc_6000x4500.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6DTV!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f732e9a-d613-416e-b176-ec634a1cdbfc_6000x4500.png 424w, https://substackcdn.com/image/fetch/$s_!6DTV!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f732e9a-d613-416e-b176-ec634a1cdbfc_6000x4500.png 848w, https://substackcdn.com/image/fetch/$s_!6DTV!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f732e9a-d613-416e-b176-ec634a1cdbfc_6000x4500.png 1272w, https://substackcdn.com/image/fetch/$s_!6DTV!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f732e9a-d613-416e-b176-ec634a1cdbfc_6000x4500.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6DTV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f732e9a-d613-416e-b176-ec634a1cdbfc_6000x4500.png" width="546" height="409.5" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7f732e9a-d613-416e-b176-ec634a1cdbfc_6000x4500.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1092,&quot;width&quot;:1456,&quot;resizeWidth&quot;:546,&quot;bytes&quot;:2456060,&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://sdcourse.substack.com/i/201102434?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f732e9a-d613-416e-b176-ec634a1cdbfc_6000x4500.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_!6DTV!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f732e9a-d613-416e-b176-ec634a1cdbfc_6000x4500.png 424w, https://substackcdn.com/image/fetch/$s_!6DTV!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f732e9a-d613-416e-b176-ec634a1cdbfc_6000x4500.png 848w, https://substackcdn.com/image/fetch/$s_!6DTV!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f732e9a-d613-416e-b176-ec634a1cdbfc_6000x4500.png 1272w, https://substackcdn.com/image/fetch/$s_!6DTV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f732e9a-d613-416e-b176-ec634a1cdbfc_6000x4500.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 class="callout-block" data-callout="true"><p>Preparing for a distributed systems interview?</p><p>&#8594;<a href="https://systemdrd.com/ebooks/sdcourse-distributed-systems-interview">Download the free Interview Pack</a></p><p>&#8594; <a href="https://sdcourse.substack.com/subscribe">Subscribe</a> now to access source code repository - 200 + coding lessons</p></div>
      <p>
          <a href="https://sdcourse.substack.com/p/day-66-implement-log-redaction-for">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 65: Field-Level Encryption for Sensitive Log Data]]></title><description><![CDATA[What We&#8217;re Building Today]]></description><link>https://sdcourse.substack.com/p/day-65-field-level-encryption-for-cca</link><guid isPermaLink="false">https://sdcourse.substack.com/p/day-65-field-level-encryption-for-cca</guid><dc:creator><![CDATA[System Design Course]]></dc:creator><pubDate>Mon, 29 Jun 2026 05:26:06 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Gmb7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf8e6207-4a08-4647-adf5-07998c4d4d8e_12000x6600.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>What We&#8217;re Building Today</h2><ul><li><p><strong>AES-256-GCM encryption service</strong> for PII fields (email, SSN, credit cards) in log events</p></li><li><p><strong>Key rotation system</strong> with versioned encryption keys stored in distributed cache</p></li><li><p><strong>Transparent decryption layer</strong> with role-based access to encrypted fields</p></li><li><p><strong>Performance-optimized encryption pipeline</strong> handling 50,000+ events/second</p></li></ul><h2>Why This Matters</h2><p>When logs contain personally identifiable information (PII), compliance frameworks like GDPR, HIPAA, and PCI-DSS mandate encryption at rest and in transit. However, encrypting entire log streams creates operational nightmares: debugging becomes impossible, pattern analysis breaks, and search performance tanks. Field-level encryption solves this by selectively protecting sensitive fields while keeping the rest of the log searchable and analyzable.</p><p>Netflix processes billions of log events daily, many containing user IDs, IP addresses, and session tokens. Their approach: encrypt only the 5-10% of fields containing PII, keeping 90% of log data in plaintext for operational visibility. This hybrid strategy reduces encryption overhead by 85% while maintaining compliance. The challenge isn&#8217;t just encryption&#8212;it&#8217;s building a system that remains performant, debuggable, and operationally practical at scale.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://sdcourse.substack.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">LogStream &#8212; Build Distributed Systems is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</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>System Design Deep Dive</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Gmb7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf8e6207-4a08-4647-adf5-07998c4d4d8e_12000x6600.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Gmb7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf8e6207-4a08-4647-adf5-07998c4d4d8e_12000x6600.png 424w, https://substackcdn.com/image/fetch/$s_!Gmb7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf8e6207-4a08-4647-adf5-07998c4d4d8e_12000x6600.png 848w, https://substackcdn.com/image/fetch/$s_!Gmb7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf8e6207-4a08-4647-adf5-07998c4d4d8e_12000x6600.png 1272w, https://substackcdn.com/image/fetch/$s_!Gmb7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf8e6207-4a08-4647-adf5-07998c4d4d8e_12000x6600.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Gmb7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf8e6207-4a08-4647-adf5-07998c4d4d8e_12000x6600.png" width="12000" height="6600" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/af8e6207-4a08-4647-adf5-07998c4d4d8e_12000x6600.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:6600,&quot;width&quot;:12000,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2832659,&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://sdcourse.substack.com/i/201102430?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2d437b3-46f0-4c2b-afdd-3f91606df8f8_12000x9000.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_!Gmb7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf8e6207-4a08-4647-adf5-07998c4d4d8e_12000x6600.png 424w, https://substackcdn.com/image/fetch/$s_!Gmb7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf8e6207-4a08-4647-adf5-07998c4d4d8e_12000x6600.png 848w, https://substackcdn.com/image/fetch/$s_!Gmb7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf8e6207-4a08-4647-adf5-07998c4d4d8e_12000x6600.png 1272w, https://substackcdn.com/image/fetch/$s_!Gmb7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf8e6207-4a08-4647-adf5-07998c4d4d8e_12000x6600.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 class="callout-block" data-callout="true"><p>Preparing for a distributed systems interview?</p><p>&#8594;A free welcome gift: <a href="https://systemdrd.com/ebooks/sdcourse-distributed-systems-interview">Download the free Interview Pack</a></p><p>&#8594;52 FAANG Questions Drill cards Cheatsheets Vault -  Get it <a href="https://systemdrd.com/ebooks/52-faang-questions-drillcards-cheatsheets/">here</a></p><p>&#8594; <a href="https://sdcourse.substack.com/subscribe">Subscribe</a> now to access source code repository - 200 + coding lessons</p></div><h3>1. Encryption Strategy: Field-Level vs Full Payload</h3><p><strong>The Trade-off</strong>: Encrypting entire log events is simple but operationally devastating. Field-level encryption adds complexity but preserves observability.</p><p><strong>Full Payload Encryption</strong> (the naive approach):</p><ul><li><p>Pros: Simple implementation, guaranteed protection</p></li><li><p>Cons: Logs become opaque binary blobs, regex/grep fails, storage increases 40%, search requires full decryption</p></li></ul><p><strong>Field-Level Encryption</strong> (production approach):</p><ul><li><p>Pros: Selective protection, searchable metadata, 10x faster queries</p></li><li><p>Cons: Complex key management, schema awareness required, potential for data leakage in related fields</p></li></ul><p><strong>Production Pattern</strong>: Use a <strong>field classification system</strong>. Tag fields as <code>PUBLIC</code>, <code>INTERNAL</code>, or <code>PII</code> during schema definition. Only <code>PII</code> fields get encrypted. This requires schema evolution support&#8212;when you add a new PII field, historical logs remain unencrypted for that field, so the decryption layer must handle missing encrypted data gracefully.</p><h3>2. Key Management: Rotation Without Downtime</h3><p><strong>The CAP Theorem Reality</strong>: You cannot have consistent key distribution, always-available encryption, and partition-tolerant key storage simultaneously.</p><p>Most systems choose <strong>AP (Available + Partition-Tolerant)</strong> for encryption keys:</p><ul><li><p>Keys cached in Redis with 5-minute TTL</p></li><li><p>Key rotation happens asynchronously</p></li><li><p>Old keys remain valid for 24 hours during rotation</p></li><li><p>Accept eventual consistency: 0.01% of events might use stale keys during rotation windows</p></li></ul><p><strong>Anti-pattern</strong>: Storing keys in a central database and fetching on every encryption. This creates a single point of failure and bottlenecks throughput at ~5,000 ops/sec. Instead, use <strong>versioned key caching</strong>:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;180498c3-4c7d-49f9-a3cf-44f4f3290ef2&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">Key Structure: 
{
  "keyId": "encryption-key-v47",
  "algorithm": "AES-256-GCM",
  "key": "base64-encoded-key",
  "validFrom": "2025-02-01T00:00:00Z",
  "validUntil": "2025-03-01T00:00:00Z"
}
</code></pre></div><p>Each encrypted field stores its <code>keyId</code> version. Decryption services fetch the appropriate key from cache, falling back to the key management service (AWS KMS, HashiCorp Vault) only on cache miss.</p><h3>3. Encryption Performance: Batching and Async Processing</h3><p><strong>The Bottleneck</strong>: AES-256-GCM encryption on a single core processes ~200MB/sec. For a system handling 50,000 events/sec with 5 PII fields each (250,000 encryption ops/sec), naive synchronous encryption saturates at 12,000 events/sec on a 16-core machine.</p><p><strong>Solution</strong>: <strong>Async encryption pipeline with batching</strong>:</p><ol><li><p><strong>Kafka consumer</strong> reads log events at 50K/sec</p></li><li><p><strong>Classification stage</strong> identifies PII fields (CPU-bound, parallelizable)</p></li><li><p><strong>Batch accumulator</strong> groups 100 events (reduces per-event overhead)</p></li><li><p><strong>Parallel encryption workers</strong> (16 threads) encrypt batches</p></li><li><p><strong>Kafka producer</strong> publishes encrypted events</p></li></ol><p>This architecture achieves <strong>50,000 events/sec</strong> because:</p><ul><li><p>Batching reduces context switching overhead by 60%</p></li><li><p>Parallel workers saturate all CPU cores</p></li><li><p>Async processing prevents backpressure to upstream services</p></li></ul><p><strong>Trade-off</strong>: Batching adds 50-100ms latency. For real-time alerting on PII exposure, maintain a separate <strong>fast-path pipeline</strong> that processes high-priority events synchronously.</p><h3>4. Decryption Access Control: Role-Based Field Visibility</h3><p><strong>The Problem</strong>: Not all engineers should decrypt all PII. Support engineers need email addresses for customer lookup but shouldn&#8217;t see SSNs. Compliance teams need audit trails of who decrypted what.</p><p><strong>Pattern</strong>: <strong>Attribute-Based Access Control (ABAC)</strong> at the field level:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;3574631a-99ae-483e-8860-c2c9b98069fc&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">Access Policy:
{
  "role": "support-engineer",
  "allowedFields": ["user.email", "user.name"],
  "deniedFields": ["user.ssn", "payment.cardNumber"],
  "auditRequired": true
}
</code></pre></div><p>When a user queries logs:</p><ol><li><p>Parse query for requested fields</p></li><li><p>Check user role against field-level policies</p></li><li><p>Decrypt only <strong>allowed</strong> encrypted fields</p></li><li><p>Redact <strong>denied</strong> fields (replace with <code>[REDACTED-SSN]</code>)</p></li><li><p>Log decryption event to audit trail</p></li></ol><p><strong>Failure Mode</strong>: Policy changes don&#8217;t propagate instantly. Use a <strong>policy versioning system</strong> where each decryption request includes a <code>policyVersion</code> timestamp. Services cache policies for 60 seconds, then check for updates. During policy updates, some requests may use stale policies&#8212;accept this as a trade-off for availability.</p><h3>5. Storage Optimization: Encrypted Field Indexing</h3><p><strong>The Problem</strong>: Encrypted fields can&#8217;t be indexed or searched. How do you find &#8220;all logs with email=user@example.com&#8221; when emails are encrypted?</p><p><strong>Solution</strong>: <strong>Deterministic encryption for indexable fields</strong>:</p><ul><li><p>Use <strong>HMAC-SHA256</strong> to generate a searchable hash: <code>hmac(email) = "abc123"</code></p></li><li><p>Store both the hash and AES-encrypted value</p></li><li><p>Queries search by hash, retrieve encrypted value, decrypt for display</p></li></ul><p><strong>Trade-off</strong>: Deterministic encryption is vulnerable to rainbow table attacks if the keyspace is small (e.g., email domains). Mitigate with <strong>domain-specific salts</strong>: use different HMAC keys for different email domains.</p><h2>Implementation Walkthrough</h2><h3><strong>GitHub Link:</strong></h3><pre><code><a href="https://github.com/sysdr/sdc-java-p/tree/main/day65/log-encryption-system">https://github.com/sysdr/sdc-java-p/tree/main/day65/log-encryption-system</a></code></pre><h3>Step 1: Encryption Service with Key Versioning</h3><p>The <code>EncryptionService</code> handles field-level encryption with automatic key rotation:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;55dc40aa-47be-48d6-b357-34f8fcb30bee&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">@Service
public class EncryptionService {
    private final RedisTemplate&lt;String, EncryptionKey&gt; keyCache;
    private final KeyManagementClient kmsClient;
    
    public EncryptedField encrypt(String fieldName, String value) {
        EncryptionKey key = getCurrentKey(fieldName);
        
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        byte[] iv = generateIV(); // 12 bytes for GCM
        cipher.init(Cipher.ENCRYPT_MODE, key.getSecretKey(), new GCMParameterSpec(128, iv));
        
        byte[] encrypted = cipher.doFinal(value.getBytes(UTF_8));
        
        return new EncryptedField(
            fieldName,
            Base64.encode(encrypted),
            key.getKeyId(),
            Base64.encode(iv)
        );
    }
}
</code></pre></div><p><strong>Architectural Decision</strong>: Store the initialization vector (IV) with each encrypted field. GCM mode requires unique IVs per encryption to maintain security. This increases storage by 16 bytes per field but prevents IV reuse attacks.</p><h3>Step 2: Kafka Consumer with Async Encryption</h3><p>The consumer processes logs in batches, encrypting PII fields asynchronously:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;4cc9d73f-1a2e-4e0a-ba93-3606bca5cd7b&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">@Service
public class LogEncryptionConsumer {
    private final ExecutorService encryptionPool = Executors.newFixedThreadPool(16);
    
    @KafkaListener(topics = "raw-logs")
    public void processLogs(List&lt;LogEvent&gt; events) {
        List&lt;CompletableFuture&lt;LogEvent&gt;&gt; futures = events.stream()
            .map(event -&gt; CompletableFuture.supplyAsync(
                () -&gt; encryptSensitiveFields(event), 
                encryptionPool
            ))
            .toList();
        
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
            .thenAccept(v -&gt; publishEncryptedLogs(
                futures.stream().map(CompletableFuture::join).toList()
            ));
    }
}
</code></pre></div><p><strong>Why Async?</strong> Blocking encryption on 16 threads would cap throughput at 12K events/sec. Async processing with <code>CompletableFuture</code> allows the consumer thread to batch-fetch the next 100 events while encryption workers process the current batch, achieving 50K+ events/sec.</p><h3>Step 3: Role-Based Decryption Layer</h3><p>The query service decrypts fields based on user roles:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;02f9d8ef-9fd2-42cc-aa0c-54a29f130220&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">@Service
public class LogQueryService {
    public List&lt;LogEvent&gt; queryLogs(LogQuery query, UserContext user) {
        List&lt;LogEvent&gt; results = logRepository.findByQuery(query);
        
        return results.stream()
            .map(event -&gt; decryptAllowedFields(event, user))
            .toList();
    }
    
    private LogEvent decryptAllowedFields(LogEvent event, UserContext user) {
        Set&lt;String&gt; allowedFields = policyService.getAllowedFields(user.getRole());
        
        event.getEncryptedFields().forEach((fieldName, encryptedValue) -&gt; {
            if (allowedFields.contains(fieldName)) {
                String decrypted = encryptionService.decrypt(encryptedValue);
                event.setField(fieldName, decrypted);
                auditService.logDecryption(user, fieldName, event.getId());
            } else {
                event.setField(fieldName, "[REDACTED]");
            }
        });
        
        return event;
    }
}
</code></pre></div><p><strong>Key Insight</strong>: Decryption happens <strong>lazily at query time</strong>, not during storage. This allows policy changes to take effect immediately&#8212;revoking SSN access from a role instantly prevents future decryptions without re-encrypting stored data.</p><h2>Production Considerations</h2><p><strong>Performance</strong>: Encryption adds 2-5ms per event. Under load, batch 100 events and parallelize encryption across 16 workers to maintain 50K events/sec throughput. Monitor <code>encryption_latency_p99</code> metric&#8212;if it exceeds 10ms, scale worker pools horizontally.</p><p><strong>Monitoring</strong>: Track key rotation failures with <code>key_rotation_error_rate</code>. A spike indicates KMS availability issues. Set up alerts for <code>decryption_access_denied_rate</code>&#8212;sudden increases suggest policy misconfigurations or potential security incidents.</p><p><strong>Failure Scenarios</strong>:</p><ul><li><p><strong>KMS unavailable</strong>: Encryption falls back to last-known cached keys (valid for 24h). Logs continue flowing; alert ops team.</p></li><li><p><strong>Key rotation mid-flight</strong>: Events encrypted with old keys remain decryptable. Decryption service tries current key first, falls back to previous 3 versions.</p></li><li><p><strong>Corrupted encrypted data</strong>: Add HMAC signatures to detect tampering. Reject events with invalid signatures; alert security team.</p></li></ul><h2>Working Demo Link </h2><div id="youtube2-K-mZZ844Idc" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;K-mZZ844Idc&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/K-mZZ844Idc?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><h2>Scale Connection</h2><p><strong>Uber&#8217;s approach</strong>: Encrypt rider/driver PII in trip logs but keep geolocation data plaintext. This enables fraud detection (pattern analysis on routes) while protecting identities. They use <strong>field-level encryption with geographic key sharding</strong>&#8212;US data uses US KMS keys, EU data uses EU KMS keys, ensuring GDPR compliance.</p><p><strong>Amazon&#8217;s pattern</strong>: Encrypt customer PII in CloudWatch logs but maintain separate <strong>encrypted search indexes</strong> using deterministic encryption. Queries search the index by hashed email, retrieve encrypted log IDs, then batch-decrypt full logs. This hybrid approach achieves sub-second search on billions of encrypted logs.</p><h2>Next Steps</h2><p>Tomorrow: <strong>Implement log redaction for compliance</strong>&#8212;automatically detect and redact SSNs, credit cards, and API keys in unstructured log text using regex patterns and ML-based PII detection.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://sdcourse.substack.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">LogStream &#8212; Build Distributed Systems is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</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[Day 64: Implement Role-Based Access Control for Log Data]]></title><description><![CDATA[What We&#8217;re Building Today]]></description><link>https://sdcourse.substack.com/p/day-64-implement-role-based-access</link><guid isPermaLink="false">https://sdcourse.substack.com/p/day-64-implement-role-based-access</guid><dc:creator><![CDATA[System Design Course]]></dc:creator><pubDate>Tue, 23 Jun 2026 08:30:30 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!IUDy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97eef978-21ba-45bb-9f60-50d2e47aaffc_6000x5500.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>What We&#8217;re Building Today</h2><ul><li><p><strong>JWT-based authentication service</strong> with refresh token rotation</p></li><li><p><strong>Fine-grained authorization middleware</strong> controlling log access by team/service</p></li><li><p><strong>Audit logging system</strong> tracking all data access attempts</p></li><li><p><strong>Multi-tenant isolation</strong> ensuring teams only see their logs</p></li></ul><h2>Why This Matters</h2><p>In production log processing systems at scale, access control isn&#8217;t optional&#8212;it&#8217;s a regulatory requirement. When your system ingests millions of events per second from hundreds of microservices, you&#8217;re inevitably capturing sensitive data: user IDs, payment details, health information, internal API keys. A single unauthorized query could expose customer PII, violate GDPR/HIPAA compliance, or leak competitive intelligence.</p><p>Netflix processes 500+ billion events daily across 1,000+ microservices. Without RBAC, any engineer could query any service&#8217;s logs&#8212;a security nightmare. Uber&#8217;s data breach in 2016 partially stemmed from inadequate access controls. Modern distributed systems require defense-in-depth: authentication proves identity, authorization enforces least-privilege access, and audit trails ensure accountability.</p><p>The challenge: implementing security without sacrificing the millisecond-latency queries that make logs useful for incident response. Today&#8217;s RBAC system must scale horizontally, cache authorization decisions, and fail closed (deny access on errors) while maintaining the sub-100ms query performance engineers expect.</p><h2>System Design Deep Dive</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!IUDy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97eef978-21ba-45bb-9f60-50d2e47aaffc_6000x5500.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!IUDy!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97eef978-21ba-45bb-9f60-50d2e47aaffc_6000x5500.png 424w, https://substackcdn.com/image/fetch/$s_!IUDy!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97eef978-21ba-45bb-9f60-50d2e47aaffc_6000x5500.png 848w, https://substackcdn.com/image/fetch/$s_!IUDy!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97eef978-21ba-45bb-9f60-50d2e47aaffc_6000x5500.png 1272w, https://substackcdn.com/image/fetch/$s_!IUDy!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97eef978-21ba-45bb-9f60-50d2e47aaffc_6000x5500.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!IUDy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97eef978-21ba-45bb-9f60-50d2e47aaffc_6000x5500.png" width="458" height="419.9381868131868" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/97eef978-21ba-45bb-9f60-50d2e47aaffc_6000x5500.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1335,&quot;width&quot;:1456,&quot;resizeWidth&quot;:458,&quot;bytes&quot;:2035635,&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://sdcourse.substack.com/i/201102419?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97eef978-21ba-45bb-9f60-50d2e47aaffc_6000x5500.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_!IUDy!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97eef978-21ba-45bb-9f60-50d2e47aaffc_6000x5500.png 424w, https://substackcdn.com/image/fetch/$s_!IUDy!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97eef978-21ba-45bb-9f60-50d2e47aaffc_6000x5500.png 848w, https://substackcdn.com/image/fetch/$s_!IUDy!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97eef978-21ba-45bb-9f60-50d2e47aaffc_6000x5500.png 1272w, https://substackcdn.com/image/fetch/$s_!IUDy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97eef978-21ba-45bb-9f60-50d2e47aaffc_6000x5500.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 class="callout-block" data-callout="true"><p>Preparing for a distributed systems interview?</p><p>&#8594;<a href="https://systemdrd.com/ebooks/sdcourse-distributed-systems-interview">Download the free Interview Pack</a></p><p>&#8594; <a href="https://sdcourse.substack.com/subscribe">Subscribe</a> now to access source code repository - 200 + coding lessons</p></div>
      <p>
          <a href="https://sdcourse.substack.com/p/day-64-implement-role-based-access">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Week 2 : Network-Based Log Collection: From TCP Ingestion to Throughput Measurement]]></title><description><![CDATA[1.]]></description><link>https://sdcourse.substack.com/p/network-based-log-collection-from</link><guid isPermaLink="false">https://sdcourse.substack.com/p/network-based-log-collection-from</guid><dc:creator><![CDATA[sysdai]]></dc:creator><pubDate>Sat, 20 Jun 2026 08:31:01 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!tEm4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffbf82711-66e4-45fd-9c25-a3fec8465898_6000x4100.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>1. Introduction</h2><blockquote><p>Most production systems do not keep logs on the machine that generated them. Applications emit events continuously; operators need those events centralized, searchable, and durable. That requirement pushes you toward <strong>network-based log collection</strong>: agents and receivers that accept log streams over TCP or UDP, buffer them when downstream systems lag, batch and compress them to save bandwidth, encrypt them in transit, and finally land them in storage or a message bus like Kafka.</p><p>This integrated Week 2 project (<code>week_2_integrated_project</code>) walks that arc in seven incremental layers&#8212;Days 8 through 14&#8212;inside a <strong>single Spring Boot application</strong> (<code>com.example.week2.Week2IntegratedApplication</code>). Each day remains a distinct package (<code>com.example.week2.day8</code> &#8230; <code>day14</code>), while shared persistence, configuration, and observability live under <code>com.example.week2.common</code>. You can run the full stack locally on one JVM (HTTP on 8080, Day 8 Netty TCP on 9080, Day 9 TCP receiver on 9091, Day 10 UDP on 9876) and optionally attach Prometheus and Grafana for dashboards.</p><p>This article is written for a mid-level engineer who knows Spring Boot and wants to treat log shipping as an infrastructure problem, not a one-off socket demo. You will see how transport choice, buffering, batching, compression, TLS readiness, and load testing interact&#8212;and how to keep each concern in a module that can be understood and tested on its own.</p></blockquote><div><hr></div><h2>2. From Fundamentals to a Unified System</h2><h3>Day 8 &#8212; TCP Server and Bounded In-Memory Buffering</h3><p>Day 8 implements a <strong>Netty-based TCP log server</strong> (<code>Day8TcpLogServer</code>) that listens on port 9080 (configured via <code>week2.day8.tcp.port</code> in <code>application.yml</code>). Incoming lines are framed as newline-delimited JSON and handled by <code>Day8LogMessageHandler</code>, which validates <code>timestamp</code>, <code>level</code>, and <code>message</code> before handing events to <code>Day8LogBufferService</code>. The buffer is a bounded <code>LinkedBlockingQueue</code>; when it fills, events are dropped and counted in <code>Day8LogMetrics</code>.</p><p>The engineering concern is <strong>backpressure at the edge</strong>: a naive server that writes synchronously to a database will collapse under burst traffic. Day 8 decouples network I/O from persistence with a scheduled flush (<code>@Scheduled(fixedDelay = 5000)</code>) and batch writes through <code>LogPersistenceService</code>, guarded by a Resilience4j circuit breaker named <code>database</code>. REST queries are exposed at <code>/api/week2/day8/logs/*</code> via <code>Day8LogQueryController</code>.</p><h3>Day 9 &#8212; Log Shipping Client and Kafka Handoff</h3><p>Day 9 adds a <strong>TCP shipping pipeline</strong>: HTTP clients post to <code>Day9LogIngestionController</code> (<code>POST /api/week2/day9/logs</code>), <code>Day9TcpLogShipperService</code> buffers JSON lines and flushes them every 100ms to <code>Day9TcpServerService</code> on port 9091, and the receiver publishes each line to the Kafka topic <code>logs</code> (<code>Day9KafkaLogConsumer</code> persists via <code>LogPersistenceService</code> and caches ERROR logs in Redis through <code>RedisLogCacheService</code>).</p><p>The concern is <strong>reliable forwarding</strong> across process boundaries. The shipper uses a circuit breaker (<code>logShipper</code>) and reconnect logic; when <code>app.kafka.enabled</code> is false (default <code>local</code> profile), logs are stored directly so the API remains testable without Kafka.</p><h3>Day 10 &#8212; UDP for High-Throughput, Loss-Tolerant Paths</h3><p>Day 10 introduces <strong>UDP transport</strong> via <code>Day10UdpLogShipperService</code> and <code>Day10UdpServerService</code> (port 9876). Datagrams carry an 8-byte sequence number prefix plus JSON payload. The shipper tracks in-flight messages, retries on timeout, and exposes <code>POST /api/week2/day10/logs/ship</code>. The UDP server uses a NIO <code>Selector</code> loop and forwards to Kafka topic <code>logs.udp.ingress</code>; <code>Day10KafkaConsumerService</code> deduplicates and persists.</p><p>The concern is <strong>throughput versus delivery guarantees</strong>: UDP avoids connection overhead but requires application-level sequencing and dedupe&#8212;patterns you see in statsd-style agents and some observability collectors.</p><h3>Day 11 &#8212; Batching to Optimize Network and Broker Usage</h3><p>Day 11 centralizes <strong>batching</strong> in <code>Day11LogBatchingService</code>: events land in an <code>ArrayBlockingQueue</code>, flush when the batch reaches <code>week2.day11.batching.max-batch-size</code> (1000) or on a time trigger (<code>@Scheduled</code> every 5000ms). A single Kafka message carries a JSON array on topic <code>log-events-batched</code>. <code>Day11KafkaConsumerService</code> deserializes the array and calls <code>saveAllFromEvents</code>. Optional synthetic traffic comes from <code>Day11LogGeneratorService</code> when <code>week2.day11.generator.enabled=true</code>.</p><p>The concern is <strong>amortizing fixed costs</strong>&#8212;fewer TCP segments, fewer Kafka produce requests, better broker compression ratios&#8212;at the cost of latency until the batch fills or the timer fires.</p><h3>Day 12 &#8212; Application-Level Compression</h3><p>Day 12 compresses payloads <strong>before</strong> Kafka in <code>Day12CompressionService</code> (NONE, GZIP, SNAPPY, LZ4) with algorithm selection based on payload size. <code>Day12KafkaProducerService</code> attaches Kafka headers <code>compression-algorithm</code> and <code>original-size</code>; <code>Day12KafkaConsumerService</code> decompresses inside a Resilience4j <code>decompression</code> circuit breaker. Ingest is via <code>POST /api/week2/day12/logs</code> (<code>Day12LogController</code>).</p><p>The concern is <strong>bandwidth and broker load</strong> when JSON log lines are repetitive or large. Note that broker-level compression (<code>compression.type</code>) and application-level compression solve different problems; this project demonstrates the latter explicitly.</p><h3>Day 13 &#8212; TLS Readiness and Production Resilience</h3><p>Day 13 hardens the <strong>Kafka produce path</strong> with <code>Day13KafkaProducerService</code> (<code>@CircuitBreaker(name = "kafka-producer")</code>) and <code>Day13GatewayController</code> (<code>@CircuitBreaker(name = "producer-service")</code>) on <code>POST /api/week2/day13/logs</code>. <code>Day13CertificateHealthIndicator</code> (bean name <code>day13CertificateHealth</code>) reports Actuator health based on JKS certificate expiry when <code>week2.day13.ssl.keystore-path</code> is set; locally it reports UP with <code>certificateCheck: skipped</code>. WARN/ERROR logs are cached in Redis in <code>Day13KafkaConsumerService</code>.</p><p>The concern is <strong>secure, observable pipelines</strong>: encryption in transit (TLS scaffolding), failure isolation (circuit breakers), and operator visibility (health indicators)&#8212;without conflating &#8220;TLS configured&#8221; with &#8220;TLS required in dev.&#8221;</p><h3>Day 14 &#8212; Load Generation and Throughput Measurement</h3><p>Day 14 adds <strong>sustained and burst load</strong> through <code>Day14LoadGeneratorService</code> (<code>@Scheduled</code> steady rate when <code>week2.day14.load-generator.enabled=true</code>) and <code>POST /api/week2/day14/load/burst</code>. <code>Day14KafkaProducerService</code> records Micrometer timers; <code>Day14KafkaConsumerService</code> runs with concurrency 3 and publishes <code>day14.log.processing.time</code> percentiles. Operators inspect throughput via <code>Day14MetricsController</code> (<code>/api/week2/day14/metrics/summary</code>) and Grafana panels fed from <code>/actuator/prometheus</code>.</p><p>The concern is <strong>capacity planning</strong>: you cannot claim a pipeline handles 10k logs/sec without a generator, metrics, and a dashboard that prove it under your hardware and configuration.</p><div><hr></div><h2>3. Architecture Overview</h2><p>At runtime, the system is one Spring Boot process whose context is rooted at <code>Week2IntegratedApplication</code> with <code>@EnableScheduling</code> and <code>@EnableAsync</code> for periodic flushes and load generation.</p><p><strong>Configuration layer</strong> (<code>com.example.week2.common.config</code>):</p><ul><li><p><code>AppConfig</code> &#8212; <code>ObjectMapper</code>, <code>CircuitBreakerRegistry</code>, <code>RestTemplate</code>, <code>WebClient.Builder</code></p></li><li><p><code>KafkaConfig</code> &#8212; conditional on <code>app.kafka.enabled</code>; provides <code>KafkaTemplate&lt;String, String&gt;</code> and byte-array templates for Day 12</p></li><li><p><code>SchedulingConfig</code> &#8212; enables Spring&#8217;s scheduler for <code>@Scheduled</code> methods across day modules</p></li><li><p><code>application.yml</code> &#8212; ports, topics, batch sizes, and profile-specific datasource (H2 for <code>local</code>, PostgreSQL for <code>docker</code>)</p></li></ul><p><strong>Shared domain layer</strong> (<code>com.example.week2.common</code>):</p><ul><li><p><code>LogEvent</code> &#8212; canonical DTO</p></li><li><p><code>LogEntryEntity</code> / <code>LogEntryRepository</code> &#8212; JPA persistence with <code>module</code> column distinguishing day pipelines</p></li><li><p><code>LogPersistenceService</code> &#8212; single write path for map, event, and batch inserts</p></li><li><p><code>RedisLogCacheService</code> &#8212; optional dedupe and error caching</p></li><li><p><code>HomeController</code> / <code>Week2HealthController</code> &#8212; discovery and aggregate health</p></li></ul><p><strong>Per-day transport and pipeline modules</strong> sit beside common code: Netty (day8), blocking TCP + Kafka (day9), UDP + Kafka (day10), batching (day11), compression (day12), resilient gateway (day13), load + metrics (day14).</p><p><strong>External boundaries</strong>:</p><ul><li><p>Log producers (curl, <code>nc</code>, agents) on HTTP 8080 and network ports 9080/9091/9876</p></li><li><p>Kafka cluster (when enabled) on <code>spring.kafka.bootstrap-servers</code></p></li><li><p>Redis (optional) for cache and dedupe</p></li><li><p>Prometheus/Grafana (Docker Compose) scraping <code>/actuator/prometheus</code> on the host</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tEm4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffbf82711-66e4-45fd-9c25-a3fec8465898_6000x4100.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tEm4!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffbf82711-66e4-45fd-9c25-a3fec8465898_6000x4100.png 424w, https://substackcdn.com/image/fetch/$s_!tEm4!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffbf82711-66e4-45fd-9c25-a3fec8465898_6000x4100.png 848w, https://substackcdn.com/image/fetch/$s_!tEm4!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffbf82711-66e4-45fd-9c25-a3fec8465898_6000x4100.png 1272w, https://substackcdn.com/image/fetch/$s_!tEm4!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffbf82711-66e4-45fd-9c25-a3fec8465898_6000x4100.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!tEm4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffbf82711-66e4-45fd-9c25-a3fec8465898_6000x4100.png" width="1456" height="995" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fbf82711-66e4-45fd-9c25-a3fec8465898_6000x4100.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:995,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1180516,&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://sdcourse.substack.com/i/202810265?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffbf82711-66e4-45fd-9c25-a3fec8465898_6000x4100.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_!tEm4!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffbf82711-66e4-45fd-9c25-a3fec8465898_6000x4100.png 424w, https://substackcdn.com/image/fetch/$s_!tEm4!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffbf82711-66e4-45fd-9c25-a3fec8465898_6000x4100.png 848w, https://substackcdn.com/image/fetch/$s_!tEm4!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffbf82711-66e4-45fd-9c25-a3fec8465898_6000x4100.png 1272w, https://substackcdn.com/image/fetch/$s_!tEm4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffbf82711-66e4-45fd-9c25-a3fec8465898_6000x4100.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>
          <a href="https://sdcourse.substack.com/p/network-based-log-collection-from">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 63: Chaos Engineering - Building Resilience Through Controlled Failure]]></title><description><![CDATA[What We&#8217;re Building Today]]></description><link>https://sdcourse.substack.com/p/day-63-chaos-engineering-building</link><guid isPermaLink="false">https://sdcourse.substack.com/p/day-63-chaos-engineering-building</guid><dc:creator><![CDATA[System Design Course]]></dc:creator><pubDate>Tue, 16 Jun 2026 09:01:03 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!4eXq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f384ee0-e3aa-4e28-9ce5-bfbec41b8004_7000x6000.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>What We&#8217;re Building Today</h2><ul><li><p><strong>Chaos testing framework</strong> that randomly introduces network failures, service crashes, and resource exhaustion</p></li><li><p><strong>Automated failure injection</strong> across Kafka, Redis, PostgreSQL, and API services</p></li><li><p><strong>Resilience verification suite</strong> that validates circuit breakers, retry logic, and graceful degradation</p></li><li><p><strong>Production-grade monitoring</strong> to observe system behavior under failure conditions</p></li></ul><h2>Why This Matters</h2><blockquote><p>After implementing backpressure mechanisms on Day 62, your log processing system can handle traffic spikes. But real production failures aren&#8217;t predictable&#8212;they&#8217;re messy, cascading, and often occur at the worst possible moment. Netflix&#8217;s Chaos Monkey famously shuts down production instances randomly, not because they want outages, but because controlled chaos builds antifragile systems.</p><p>In distributed systems, failure is not an edge case&#8212;it&#8217;s the default state. Network partitions, disk failures, OOM kills, and cascade failures happen constantly at scale. The difference between a robust system and a brittle one is whether you&#8217;ve tested these scenarios before your users experience them. Chaos engineering shifts failure discovery from 3 AM production incidents to controlled daytime experiments.</p><p>Your log processing system processes thousands of events per second across multiple services. When Kafka becomes unavailable, does your producer gracefully degrade or crash the entire pipeline? When PostgreSQL experiences latency spikes, does the consumer exhaust its thread pool? These aren&#8217;t hypothetical questions&#8212;they&#8217;re Tuesday morning at any company running distributed systems.</p></blockquote><h2>System Design Deep Dive</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4eXq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f384ee0-e3aa-4e28-9ce5-bfbec41b8004_7000x6000.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4eXq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f384ee0-e3aa-4e28-9ce5-bfbec41b8004_7000x6000.png 424w, https://substackcdn.com/image/fetch/$s_!4eXq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f384ee0-e3aa-4e28-9ce5-bfbec41b8004_7000x6000.png 848w, https://substackcdn.com/image/fetch/$s_!4eXq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f384ee0-e3aa-4e28-9ce5-bfbec41b8004_7000x6000.png 1272w, https://substackcdn.com/image/fetch/$s_!4eXq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f384ee0-e3aa-4e28-9ce5-bfbec41b8004_7000x6000.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4eXq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f384ee0-e3aa-4e28-9ce5-bfbec41b8004_7000x6000.png" width="562" height="481.7142857142857" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1f384ee0-e3aa-4e28-9ce5-bfbec41b8004_7000x6000.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1248,&quot;width&quot;:1456,&quot;resizeWidth&quot;:562,&quot;bytes&quot;:2497153,&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://sdcourse.substack.com/i/195223317?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f384ee0-e3aa-4e28-9ce5-bfbec41b8004_7000x6000.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_!4eXq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f384ee0-e3aa-4e28-9ce5-bfbec41b8004_7000x6000.png 424w, https://substackcdn.com/image/fetch/$s_!4eXq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f384ee0-e3aa-4e28-9ce5-bfbec41b8004_7000x6000.png 848w, https://substackcdn.com/image/fetch/$s_!4eXq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f384ee0-e3aa-4e28-9ce5-bfbec41b8004_7000x6000.png 1272w, https://substackcdn.com/image/fetch/$s_!4eXq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f384ee0-e3aa-4e28-9ce5-bfbec41b8004_7000x6000.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 class="callout-block" data-callout="true"><p>Preparing for a distributed systems interview?</p><p>&#8594;<a href="https://systemdrd.com/ebooks/sdcourse-distributed-systems-interview">Download the free Interview Pack</a></p><p>&#8594; <a href="https://sdcourse.substack.com/subscribe">Subscribe</a> now to access source code repository - 200 + coding lessons</p></div>
      <p>
          <a href="https://sdcourse.substack.com/p/day-63-chaos-engineering-building">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 62: Implement Backpressure Mechanisms for Load Management]]></title><description><![CDATA[What We&#8217;re Building Today]]></description><link>https://sdcourse.substack.com/p/day-62-implement-backpressure-mechanisms</link><guid isPermaLink="false">https://sdcourse.substack.com/p/day-62-implement-backpressure-mechanisms</guid><dc:creator><![CDATA[System Design Course]]></dc:creator><pubDate>Tue, 09 Jun 2026 09:01:08 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!jQFX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89681299-e8f1-4c64-b370-e1e459e781e2_7000x4750.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>What We&#8217;re Building Today</h2><blockquote><p>Today, we&#8217;re implementing production-grade backpressure mechanisms that protect our distributed log processing system from overload:</p></blockquote><ul><li><p><strong>Adaptive rate limiting</strong> with token bucket algorithms at the API gateway</p></li><li><p><strong>Kafka consumer lag monitoring</strong> with automatic throughput throttling</p></li><li><p><strong>Circuit breaker integration</strong> that triggers backpressure when downstream services degrade</p></li><li><p><strong>Reactive backpressure</strong> using Spring WebFlux for non-blocking flow control</p></li></ul><h2>Why This Matters: The Cost of Ignoring Backpressure</h2><blockquote><p>In 2020, a major e-commerce platform experienced a cascading failure during Black Friday when their log aggregation system accepted more events than it could process. Without backpressure, their Kafka consumers fell 2 hours behind, Redis caches expired prematurely, and the entire observability stack collapsed&#8212;leaving teams blind during their highest-traffic day.</p><p>Backpressure isn&#8217;t about rejecting work; it&#8217;s about <strong>controlled degradation</strong>. When Netflix&#8217;s API gateway detects rising latencies, it doesn&#8217;t crash&#8212;it applies backpressure to preserve core functionality. Uber&#8217;s real-time dispatch system uses backpressure to ensure that even during surge demand, critical ride matching continues while less critical analytics can lag.</p><p>The fundamental challenge: distributed systems have no single point of control. A producer publishing 100K logs/second doesn&#8217;t know that downstream consumers can only handle 20K. Without backpressure, queues grow unbounded, memory exhausts, and the system fails catastrophically.</p></blockquote><h2>System Design Deep Dive: Backpressure Patterns</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jQFX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89681299-e8f1-4c64-b370-e1e459e781e2_7000x4750.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jQFX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89681299-e8f1-4c64-b370-e1e459e781e2_7000x4750.png 424w, https://substackcdn.com/image/fetch/$s_!jQFX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89681299-e8f1-4c64-b370-e1e459e781e2_7000x4750.png 848w, https://substackcdn.com/image/fetch/$s_!jQFX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89681299-e8f1-4c64-b370-e1e459e781e2_7000x4750.png 1272w, https://substackcdn.com/image/fetch/$s_!jQFX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89681299-e8f1-4c64-b370-e1e459e781e2_7000x4750.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jQFX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89681299-e8f1-4c64-b370-e1e459e781e2_7000x4750.png" width="510" height="346.07142857142856" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/89681299-e8f1-4c64-b370-e1e459e781e2_7000x4750.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:988,&quot;width&quot;:1456,&quot;resizeWidth&quot;:510,&quot;bytes&quot;:2101601,&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://sdcourse.substack.com/i/195223310?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89681299-e8f1-4c64-b370-e1e459e781e2_7000x4750.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_!jQFX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89681299-e8f1-4c64-b370-e1e459e781e2_7000x4750.png 424w, https://substackcdn.com/image/fetch/$s_!jQFX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89681299-e8f1-4c64-b370-e1e459e781e2_7000x4750.png 848w, https://substackcdn.com/image/fetch/$s_!jQFX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89681299-e8f1-4c64-b370-e1e459e781e2_7000x4750.png 1272w, https://substackcdn.com/image/fetch/$s_!jQFX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89681299-e8f1-4c64-b370-e1e459e781e2_7000x4750.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 class="callout-block" data-callout="true"><p>Preparing for a distributed systems interview?</p><p>&#8594;<a href="https://systemdrd.com/ebooks/sdcourse-distributed-systems-interview">Download the free Interview Pack</a></p><p>&#8594; <a href="https://sdcourse.substack.com/subscribe">Subscribe</a> now to access source code repository - 200 + coding lessons</p></div>
      <p>
          <a href="https://sdcourse.substack.com/p/day-62-implement-backpressure-mechanisms">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Java Version : Dead Letter Queues That Actually Work]]></title><description><![CDATA[Most teams&#8217; Dead Letter Queues are accidentally where messages go to die unnoticed.]]></description><link>https://sdcourse.substack.com/p/dead-letter-queues-that-actually</link><guid isPermaLink="false">https://sdcourse.substack.com/p/dead-letter-queues-that-actually</guid><dc:creator><![CDATA[System Design Course]]></dc:creator><pubDate>Mon, 08 Jun 2026 05:42:20 GMT</pubDate><enclosure url="https://substackcdn.com/image/youtube/w_728,c_limit/Pr8w-EI-huw" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Most teams&#8217; Dead Letter Queues are accidentally where messages go to die unnoticed. This is a guide to building a DLQ that does what it&#8217;s supposed to do.</p><div><hr></div><h2>What a DLQ is for</h2><p>A Dead Letter Queue is a place to send messages that <strong>cannot be processed</strong>. The key word is &#8220;cannot.&#8221; A DLQ is not for transient failures.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://sdcourse.substack.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">LogStream &#8212; Build Distributed Systems is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</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>Transient failures</strong> (network blip, downstream service temporarily down): retry with exponential backoff. Don&#8217;t DLQ.</p><p><strong>Permanent failures</strong> (malformed payload, business rule violation, missing required field): DLQ immediately. No retries.</p><p>The first mistake teams make is conflating these. A consumer that DLQs on every error pollutes the DLQ with transient garbage &#8212; making the actual permanent-failure messages impossible to find.</p><div><hr></div><h2>What a DLQ message must preserve</h2><p>When a message is DLQ&#8217;d, you need to be able to answer three questions:</p><ol><li><p>What was the original message?</p></li><li><p>Why did it fail?</p></li><li><p>Can I safely reprocess it after fixing the bug?</p></li></ol><p>To answer those, the DLQ message must contain:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;json&quot;,&quot;nodeId&quot;:&quot;66995bc5-9e0d-4679-93c6-7ad093175d3c&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-json">{
  "original_message": { ... },
  "original_topic": "user-events",
  "original_partition": 4,
  "original_offset": 8472938,
  "consumer_id": "user-event-processor-7f3a",
  "failure_reason": "ValidationException: required field 'user_id' missing",
  "stack_trace": "...",
  "timestamp": "2025-12-09T14:32:18Z",
  "retry_count": 0
}
</code></pre></div><p>The <code>original_topic</code>, <code>partition</code>, and <code>offset</code> are the keys. They let you trace back to exactly where in the source stream the message came from &#8212; useful for diagnosing a producer bug, not just the consumer&#8217;s failure.</p><div><hr></div><h2>Operating a DLQ</h2><p>A DLQ that nobody looks at is worse than no DLQ &#8212; it gives the team false confidence that &#8220;we have one.&#8221;</p><h3>Alert on growth, not absolute count</h3><p>A DLQ with 1000 messages from 6 months ago that haven&#8217;t grown is fine. A DLQ with 50 messages added in the last hour is a fire.</p><p>Alert on <strong>rate of arrival</strong>, not on <strong>size</strong>:</p><ul><li><p>10 messages/minute &#8594; page on-call</p></li><li><p>100 messages in last hour &#8594; wake up the team</p></li><li><p>DLQ has any messages older than 7 days &#8594; ticket the team</p></li></ul><h3>Build a reprocessing tool</h3><p>When you fix the bug that caused messages to DLQ, you need to replay them. This needs:</p><ol><li><p>A way to filter by <code>failure_reason</code> (so you only replay messages affected by the bug you fixed)</p></li><li><p>A &#8220;dry run&#8221; mode that shows what would happen</p></li><li><p>A way to replay back to the original topic, not the DLQ</p></li><li><p>Logging of every replay attempt</p></li></ol><p>If you don&#8217;t have this tool, you&#8217;ll never replay messages. They&#8217;ll sit in the DLQ forever. The DLQ becomes a graveyard.</p><h3>Schedule a monthly DLQ review</h3><p>Once a month, the team that owns each consumer reviews their DLQ:</p><ul><li><p>What categories of failures showed up?</p></li><li><p>Are any persistent (suggesting a bug we haven&#8217;t fixed)?</p></li><li><p>Should any be auto-archived (after N days, move to cold storage)?</p></li></ul><p>This sounds like overkill until the third time you discover a 6-month-old bug because the DLQ surfaced it.</p><div><hr></div><h2>Three patterns for poison-pill protection</h2><p>A &#8220;poison pill&#8221; is a single message that breaks every consumer that processes it. Without protection, it can stop your entire partition.</p><h3>Pattern 1: Per-message retry counter</h3><p>Track retry count <em>in the message header</em>. Increment on each failed processing attempt. Skip and DLQ when count exceeds threshold:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;cef3b493-5eeb-4375-be17-a4ab91317178&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">int retries = record.headers().lastHeader("x-retry-count")...;
if (retries &gt;= MAX_RETRIES) {
    sendToDLQ(record, "Retry limit exceeded");
    return;
}
try {
    process(record);
} catch (Exception e) {
    sendToRetryTopic(record, retries + 1);
}
</code></pre></div><h3>Pattern 2: Schema validation at consumer entry</h3><p>Reject obviously malformed messages immediately, before they enter your processing logic:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;c34636e6-66ec-4d17-a3c2-70a61055d27f&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">if (!schemaValidator.isValid(record.value())) {
    sendToDLQ(record, "Schema validation failed");
    return;
}</code></pre></div><p>This catches producer bugs early. Don&#8217;t waste cycles on messages that can&#8217;t possibly succeed.</p><h3>Pattern 3: Fail-open with sampling</h3><p>For non-critical processing, sometimes &#8220;skip and log&#8221; is the right call. Don&#8217;t DLQ every event from a noisy producer &#8212; sample, alert on rate, and skip:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;cb4d7407-18f9-4474-830d-994d9e337d8c&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">if (failureRate.getRate() &gt; 0.1) {
    samplingFilter.recordFailure();
    if (samplingFilter.shouldSample()) {
        sendToDLQ(record, "High failure rate, sampled");
    }
    return;
}
</code></pre></div><p>This is appropriate for telemetry, not financial transactions. Pick the pattern based on the cost of dropping a message.</p><div><hr></div><h3><strong>GitHub Link:</strong></h3><pre><code><a href="https://github.com/sysdr/sdc-java/tree/main/day36/dlq-log-system">https://github.com/sysdr/sdc-java/tree/main/day36/dlq-log-system</a></code></pre><h2>What most teams get wrong</h2><p>In order of frequency:</p><ol><li><p><strong>No alerting on DLQ growth.</strong> The DLQ exists. Nobody knows when it&#8217;s growing.</p></li><li><p><strong>Original message context not preserved.</strong> &#8220;Failed to parse&#8221; with no source info &#8594; impossible to debug.</p></li><li><p><strong>No reprocessing tool.</strong> Engineers do it ad-hoc with one-off scripts every time.</p></li><li><p><strong>Treating all errors as DLQ candidates.</strong> Including transient ones, which floods the DLQ with noise.</p></li><li><p><strong>Single DLQ for all consumers.</strong> Should be per-consumer (or at least per-topic), so alerting and review can be team-specific.</p></li></ol><div><hr></div><h2><strong>Working Code Demo:</strong></h2><div id="youtube2-Pr8w-EI-huw" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;Pr8w-EI-huw&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/Pr8w-EI-huw?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><h2>A reference architecture</h2><pre><code><code>Producer &#8594; Topic A &#8594; Consumer A
                       &#8595; on permanent failure
                     DLQ-A (per consumer)
                       &#8595; daily
                     Cold archive (S3 + TTL)
                       &#8595; on demand
                     Reprocessing tool &#8594; Topic A (replay)
</code></code></pre><p>Each consumer has its own DLQ. Cold archive prevents the DLQ from growing forever. The reprocessing tool can replay back to the source topic with a filter, so fixed bugs replay only the affected messages.</p><div><hr></div><h2>Closing thought</h2><p>A DLQ is a confession that your processing pipeline isn&#8217;t perfect. That&#8217;s fine &#8212; no pipeline is. The point of a DLQ is to make imperfection <em>visible</em>, <em>diagnosable</em>, and <em>recoverable</em>.</p><p>If your DLQ doesn&#8217;t do all three, it&#8217;s a leak in disguise.</p><div><hr></div><p><em>More like this at <a href="https://sdcourse.substack.com/">SDCourse</a> &#8212; a hands-on distributed systems course covering building production-grade systems in Java + Spring Boot + Kafka + Python.</em></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://sdcourse.substack.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">LogStream &#8212; Build Distributed Systems is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</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[Day 61: Circuit Breakers for Handling Component Failures]]></title><description><![CDATA[What We&#8217;re Building Today]]></description><link>https://sdcourse.substack.com/p/day-61-circuit-breakers-for-handling</link><guid isPermaLink="false">https://sdcourse.substack.com/p/day-61-circuit-breakers-for-handling</guid><dc:creator><![CDATA[sdr11]]></dc:creator><pubDate>Tue, 02 Jun 2026 09:00:14 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!xXRz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce489146-ce04-4bd3-9c56-9905a23b0c68_6000x3900.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>What We&#8217;re Building Today</h2><blockquote><p>Yesterday we wired multi-region replication across our log pipeline. Today we harden that pipeline against the inevitable: components go down, networks partition, downstream services time out. We add <strong>circuit breakers</strong> &#8212; the single most important resilience pattern in any distributed system &#8212; directly into our log processing flow.</p></blockquote><ul><li><p><strong>Circuit breaker wrappers</strong> around every outbound service call (Kafka produce, Redis cache-write, PostgreSQL persist)</p></li><li><p><strong>State-machine-driven failure detection</strong> with configurable thresholds, timeouts, and half-open probing</p></li><li><p><strong>Fallback strategies</strong> that keep the pipeline moving when a downstream is dead</p></li><li><p><strong>Real-time health dashboards</strong> in Grafana that surface breaker trips before your on-call page fires</p></li></ul><div><hr></div><h2>Why This Matters</h2><blockquote><p>Multi-region replication (Day 60) gave us durability. But durability without availability is just a well-preserved corpse. A single slow PostgreSQL replica can hold up every consumer thread if we let synchronous calls block indefinitely. In production at scale, this is not a hypothetical &#8212; it is a certainty. Netflix&#8217;s Hystrix documentation famously documented how a single downstream latency spike in their recommendation service cascaded into a full outage because every thread in the calling service was stuck waiting.</p><p>Circuit breakers are the distributed-systems equivalent of an electrical fuse: they detect abnormal current (errors or latency), trip open to stop the cascade, and periodically probe to see if the downstream has recovered. The pattern converts a <em>hard failure</em> in one service into a <em>graceful degradation</em> across the entire system. Every FAANG-scale platform runs this pattern on every single outbound network call &#8212; no exceptions. Today we wire it into our log pipeline so that a failing PostgreSQL node, a saturated Kafka broker, or a flapping Redis instance cannot bring down our ingestion throughput.</p></blockquote><div><hr></div><h2>System Design Deep Dive</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xXRz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce489146-ce04-4bd3-9c56-9905a23b0c68_6000x3900.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xXRz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce489146-ce04-4bd3-9c56-9905a23b0c68_6000x3900.png 424w, https://substackcdn.com/image/fetch/$s_!xXRz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce489146-ce04-4bd3-9c56-9905a23b0c68_6000x3900.png 848w, https://substackcdn.com/image/fetch/$s_!xXRz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce489146-ce04-4bd3-9c56-9905a23b0c68_6000x3900.png 1272w, https://substackcdn.com/image/fetch/$s_!xXRz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce489146-ce04-4bd3-9c56-9905a23b0c68_6000x3900.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xXRz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce489146-ce04-4bd3-9c56-9905a23b0c68_6000x3900.png" width="576" height="374.24175824175825" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ce489146-ce04-4bd3-9c56-9905a23b0c68_6000x3900.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:946,&quot;width&quot;:1456,&quot;resizeWidth&quot;:576,&quot;bytes&quot;:3836181,&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://sdcourse.substack.com/i/187619009?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce489146-ce04-4bd3-9c56-9905a23b0c68_6000x3900.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_!xXRz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce489146-ce04-4bd3-9c56-9905a23b0c68_6000x3900.png 424w, https://substackcdn.com/image/fetch/$s_!xXRz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce489146-ce04-4bd3-9c56-9905a23b0c68_6000x3900.png 848w, https://substackcdn.com/image/fetch/$s_!xXRz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce489146-ce04-4bd3-9c56-9905a23b0c68_6000x3900.png 1272w, https://substackcdn.com/image/fetch/$s_!xXRz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce489146-ce04-4bd3-9c56-9905a23b0c68_6000x3900.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 class="callout-block" data-callout="true"><p>Preparing for a distributed systems interview?</p><p>&#8594;<a href="https://systemdrd.com/ebooks/sdcourse-distributed-systems-interview">Download the free Interview Pack</a></p><p>&#8594; <a href="https://sdcourse.substack.com/subscribe">Subscribe</a> now to access source code repository - 200 + coding lessons</p></div>
      <p>
          <a href="https://sdcourse.substack.com/p/day-61-circuit-breakers-for-handling">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Week 1 Java: Setting Up the Infrastructure]]></title><description><![CDATA[1.]]></description><link>https://sdcourse.substack.com/p/week-1-setting-up-the-infrastructure</link><guid isPermaLink="false">https://sdcourse.substack.com/p/week-1-setting-up-the-infrastructure</guid><dc:creator><![CDATA[sysdai]]></dc:creator><pubDate>Sat, 30 May 2026 08:30:55 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!1O7U!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80f40edc-64ac-4c27-82a0-a91551f381f1_6000x3800.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2><strong>1. Introduction</strong></h2><p>Task scheduling is one of those &#8220;boring&#8221; infrastructure concerns that quietly determines whether a backend behaves like a system or like a pile of endpoints. Real services don&#8217;t only react to inbound HTTP. They poll upstream systems, rotate files, refresh caches, emit periodic heartbeats, and enforce time-based policies. When those time-based behaviors are unreliable, everything else degrades: logs pile up, caches go stale, disk fills, and operators lose observability exactly when they need it most. </p><p>This integrated Week 1 project demonstrates scheduling as a concrete, inspectable part of a local log processing pipeline. It starts with simple time-driven behaviors (generation rate accounting and periodic stats), then connects them to more &#8220;operational&#8221; concerns like log parsing and file rotation. In code terms, this system is intentionally small, but it uses the same primitives you&#8217;d use in production Spring services:<strong> @Scheduled</strong> methods, a shared scheduler<strong> (ThreadPoolTaskScheduler),</strong> and a lightweight registry that tracks task state across runs.</p><p>This is written for a mid-level engineer who already knows Spring Boot basics and wants to treat scheduling as a first-class engineering concern. You&#8217;ll learn how scheduling interacts with thread pools and failure handling, how to keep periodic jobs observable, and how to integrate scheduled work into a pipeline without turning it into a ball of side effects.</p><h2><strong>2. From Fundamentals to a Unified System</strong></h2><h3><strong>Day 1 &#8212; Environment + a stable place to &#8220;run the system&#8221;</strong></h3><p>Day 1 is about getting a repeatable development environment and repository structure so infrastructure can actually be exercised. In this integrated app, that shows up as the ability to run &#8220;the system&#8221; with one entry point <strong>(com.example.week1.Week1IntegratedApplication)</strong> and a predictable set of endpoints <strong>(see com.example.week1.common.web.HomeController and SystemOverviewController)</strong>. The engineering concern is reproducibility: scheduled systems are hard to debug when you can&#8217;t reliably start, stop, and observe them.</p><h3><strong>Day 2 &#8212; Configurable log generator and time-driven behavior</strong></h3><p>Day 2 introduces a log generator that can produce sample events at a configurable rate. In the integrated project, the generator runs in <strong>com.example.week1.day2.service.Day2LogGenerationService</strong>, which uses an internal thread pool for generation and a scheduled method for per-second rate calculations:</p><ul><li><p><strong>Day2LogGenerationService.updateMetrics() is @Scheduled(fixedRate = 1000) and also annotated with @TrackedTask(id = "day2.updateMetrics", ...)</strong>.</p></li></ul><p>This maps directly to a common production pattern: time-window metrics (or control loops) that run regardless of inbound traffic. You can expose a generator as an HTTP API, but its behavior is only correct if the periodic bookkeeping is correct and thread-safe.</p><h3><strong>Day 3 &#8212; File-based collector and periodic reporting</strong></h3><p>Day 3 adds a log collector that reads local files, maintains offsets, and de-duplicates entries. In the integrated app, <code>com.example.week1.day3.service.Day3LogCollectorService</code> watches directories and periodically emits statistics:</p><ul><li><p><strong>Day3LogCollectorService.logStatistics() is @Scheduled(fixedRate = 60000) and @TrackedTask(id = "day3.logStatistics", ...).</strong></p></li></ul><p>The engineering concern here is &#8220;background work as a pipeline.&#8221; Watching a filesystem isn&#8217;t request/response; it&#8217;s event-driven plus periodic health/reporting. When you&#8217;re building infrastructure, the first step toward reliability is making the background work visible.</p><h3><strong>Day 4 &#8212; Parsing as a service, not a regex in the hot path</strong></h3><p>Day 4 implements parsing to extract structured data from common log formats. In the integrated project, parsing lives in <strong>com.example.week1.day4.service.Day4LogParsingService</strong>, and the raw-to-structured transformation is represented by <strong>com.example.week1.day4.service.Day4RawLogProcessor.</strong></p><p>The scheduling tie-in is subtle but real: parsing is often invoked by scheduled or asynchronous pipelines (batching, periodic scans, backfills). Even when parsing is triggered by file changes or Kafka, the system still needs predictable timing around reporting and policy enforcement.</p><h3><strong>Day 5 &#8212; Storage, rotation policies, and operational &#8220;tick&#8221; jobs</strong></h3><p>Day 5 introduces a storage mechanism using flat files with rotation. In the integrated project, rotation is a scheduled policy evaluation:</p><ul><li><p><strong>com.example.week1.day5.service.Day5RotationPolicyService.evaluateRotationPolicies() runs on @Scheduled(fixedRate = 300000) and is annotated with @TrackedTask(id = "day5.rotateColdFiles", ...).</strong></p></li></ul><p>This is exactly what a backend does in production: continuously enforce time/size policies. It&#8217;s not &#8220;feature code,&#8221; but it&#8217;s the code that prevents outages. Rotation jobs need predictable scheduling, bounded runtime, and strong observability when they fail.</p><h3><strong>Day 6 &#8212; Querying and filtering as an operational interface</strong></h3><p>Day 6 adds query APIs that filter stored logs with cache behavior and circuit breakers <strong>(com.example.week1.day6.service.Day6LogQueryService)</strong>. This day is about operator ergonomics: scheduled pipelines need query surfaces so you can validate that the system is behaving over time, not just at a single moment.</p><p>The engineering concern is feedback loops. Scheduled systems are prone to silent failure. Query endpoints <strong>(plus metrics)</strong> are how you close the loop.</p><h3><strong>Day 7 &#8212; Integration into a local pipeline</strong></h3><p>Day 7 is the integration day: connect generation, collection, parsing, and storage into a pipeline that can run locally. In this integrated project, the pipeline is mediated via a dispatch layer<strong> (com.example.week1.common.kafka.LogEventDispatchService) </strong>that can either publish to Kafka <strong>(when enabled)</strong> or persist directly <strong>(when Kafka is disabled).</strong></p><p>The scheduling concern is orchestration without tight coupling. The system can run local-only and still exercise scheduled tasks like metrics rollups and rotation. When Kafka is enabled, the same scheduled tasks still work; they just become part of a larger asynchronous pipeline.</p><h2><strong>3. Architecture Overview</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_!1O7U!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80f40edc-64ac-4c27-82a0-a91551f381f1_6000x3800.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1O7U!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80f40edc-64ac-4c27-82a0-a91551f381f1_6000x3800.png 424w, https://substackcdn.com/image/fetch/$s_!1O7U!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80f40edc-64ac-4c27-82a0-a91551f381f1_6000x3800.png 848w, https://substackcdn.com/image/fetch/$s_!1O7U!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80f40edc-64ac-4c27-82a0-a91551f381f1_6000x3800.png 1272w, https://substackcdn.com/image/fetch/$s_!1O7U!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80f40edc-64ac-4c27-82a0-a91551f381f1_6000x3800.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1O7U!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80f40edc-64ac-4c27-82a0-a91551f381f1_6000x3800.png" width="1456" height="922" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/80f40edc-64ac-4c27-82a0-a91551f381f1_6000x3800.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:922,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&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="" srcset="https://substackcdn.com/image/fetch/$s_!1O7U!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80f40edc-64ac-4c27-82a0-a91551f381f1_6000x3800.png 424w, https://substackcdn.com/image/fetch/$s_!1O7U!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80f40edc-64ac-4c27-82a0-a91551f381f1_6000x3800.png 848w, https://substackcdn.com/image/fetch/$s_!1O7U!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80f40edc-64ac-4c27-82a0-a91551f381f1_6000x3800.png 1272w, https://substackcdn.com/image/fetch/$s_!1O7U!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80f40edc-64ac-4c27-82a0-a91551f381f1_6000x3800.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>At runtime, the application is a single Spring Boot process with a few key internal layers that matter specifically for scheduling:</p><p>The outer boundary is the Spring application context <strong>(Week1IntegratedApplication). </strong>Inside that context, configuration beans provide core infrastructure:</p><ul><li><p><code>com.example.week1.common.config.SchedulingConfig</code> defines a shared <code>ThreadPoolTaskScheduler</code> used by Spring&#8217;s scheduling subsystem.</p></li><li><p><code>com.example.week1.common.config.JacksonConfig</code> and <code>RedisConfig</code> provide serialization and Redis clients that scheduled tasks use indirectly (e.g., rate limiter windows, file offset tracking).</p></li></ul><p>Scheduled task beans live in per-day modules:</p><ul><li><p>Day 2 metrics tick: <code>Day2LogGenerationService.updateMetrics()</code></p></li><li><p>Day 3 periodic collector stats: <code>Day3LogCollectorService.logStatistics()</code></p></li><li><p>Day 5 rotation policy evaluation: <code>Day5RotationPolicyService.evaluateRotationPolicies()</code></p></li></ul><p>To keep &#8220;background&#8221; behavior observable, the project adds a minimal task registry and tracking aspect:</p><ul><li><p><strong>com.example.week1.common.scheduling.TaskRegistry stores TaskState objects keyed by a stable task id.</strong></p></li><li><p><strong>com.example.week1.common.scheduling.TaskTrackingAspect wraps methods annotated with @TrackedTask and updates state on start/success/failure.</strong></p></li><li><p><strong>com.example.week1.common.web.TaskRegistryController exposes the registry at /api/week1/scheduler/tasks.</strong></p></li></ul><p>Finally, the external boundary is the JVM/OS clock, which triggers the scheduler&#8217;s timing wheel. In production you&#8217;d also model this boundary in terms of deployment topology and clock skew; locally it&#8217;s enough to treat it as &#8220;time ticks happen.&#8221;</p><h2><strong>4. Data / Control Flow</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_!a8Ie!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc33d58e6-629c-48bd-92d6-28d27eaccf4a_6000x4100.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!a8Ie!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc33d58e6-629c-48bd-92d6-28d27eaccf4a_6000x4100.png 424w, https://substackcdn.com/image/fetch/$s_!a8Ie!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc33d58e6-629c-48bd-92d6-28d27eaccf4a_6000x4100.png 848w, https://substackcdn.com/image/fetch/$s_!a8Ie!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc33d58e6-629c-48bd-92d6-28d27eaccf4a_6000x4100.png 1272w, https://substackcdn.com/image/fetch/$s_!a8Ie!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc33d58e6-629c-48bd-92d6-28d27eaccf4a_6000x4100.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!a8Ie!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc33d58e6-629c-48bd-92d6-28d27eaccf4a_6000x4100.png" width="1456" height="995" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c33d58e6-629c-48bd-92d6-28d27eaccf4a_6000x4100.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:995,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&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="" srcset="https://substackcdn.com/image/fetch/$s_!a8Ie!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc33d58e6-629c-48bd-92d6-28d27eaccf4a_6000x4100.png 424w, https://substackcdn.com/image/fetch/$s_!a8Ie!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc33d58e6-629c-48bd-92d6-28d27eaccf4a_6000x4100.png 848w, https://substackcdn.com/image/fetch/$s_!a8Ie!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc33d58e6-629c-48bd-92d6-28d27eaccf4a_6000x4100.png 1272w, https://substackcdn.com/image/fetch/$s_!a8Ie!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc33d58e6-629c-48bd-92d6-28d27eaccf4a_6000x4100.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>Even though the project ingests and stores logs, the scheduling lifecycle is the piece that makes the system &#8220;keep moving&#8221; without humans poking it.</p><p>When the application starts, Spring initializes beans, then scheduling infrastructure scans for<strong> @Scheduled</strong> methods. Those methods are scheduled onto the shared scheduler defined in <strong>SchedulingConfig</strong> and begin waiting for time-based triggers.</p><p>On each trigger cycle, the runtime flow looks like this:</p><p>Startup &#8594; scheduler initialized &#8594; <strong>@Scheduled</strong> methods registered &#8594; WAIT for time &#8594; clock fires &#8594; scheduler picks a worker thread &#8594; the scheduled method executes &#8594; it emits logs/metrics and may update storage &#8594; the method returns &#8594; the thread goes back to the pool &#8594; the scheduler waits for the next trigger.</p><p>The task tracking aspect turns that flow into observable state transitions. When a tracked scheduled method begins, it is marked RUNNING in the<strong> TaskRegistry.</strong> If the method returns normally it is marked SUCCESS; if an exception propagates it becomes FAILED. In both cases the registry returns the task to WAITING so the next trigger can proceed.</p><h2><strong>5. State Management</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_!fYC2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e3ad669-cd3f-4439-8d7b-1b3af21d6225_6000x3600.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!fYC2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e3ad669-cd3f-4439-8d7b-1b3af21d6225_6000x3600.png 424w, https://substackcdn.com/image/fetch/$s_!fYC2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e3ad669-cd3f-4439-8d7b-1b3af21d6225_6000x3600.png 848w, https://substackcdn.com/image/fetch/$s_!fYC2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e3ad669-cd3f-4439-8d7b-1b3af21d6225_6000x3600.png 1272w, https://substackcdn.com/image/fetch/$s_!fYC2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e3ad669-cd3f-4439-8d7b-1b3af21d6225_6000x3600.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!fYC2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e3ad669-cd3f-4439-8d7b-1b3af21d6225_6000x3600.png" width="1456" height="874" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7e3ad669-cd3f-4439-8d7b-1b3af21d6225_6000x3600.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:874,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&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="" srcset="https://substackcdn.com/image/fetch/$s_!fYC2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e3ad669-cd3f-4439-8d7b-1b3af21d6225_6000x3600.png 424w, https://substackcdn.com/image/fetch/$s_!fYC2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e3ad669-cd3f-4439-8d7b-1b3af21d6225_6000x3600.png 848w, https://substackcdn.com/image/fetch/$s_!fYC2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e3ad669-cd3f-4439-8d7b-1b3af21d6225_6000x3600.png 1272w, https://substackcdn.com/image/fetch/$s_!fYC2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e3ad669-cd3f-4439-8d7b-1b3af21d6225_6000x3600.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>A scheduled job isn&#8217;t just &#8220;a method that runs sometimes.&#8221; It has state that matters operationally: when it last ran, whether it is failing, and whether it is making progress. The integrated project tracks this state in-memory via <strong>TaskRegistry </strong>and <strong>TaskState</strong>:</p><ul><li><p><strong>TaskState.status records REGISTERED, WAITING, RUNNING, SUCCESS, FAILED, DISABLED.</strong></p></li><li><p><strong>TaskState.lastStartedAt</strong> and <strong>lastFinishedAt </strong>capture timing.</p></li><li><p><strong>lastSuccessAt</strong>, <strong>lastFailureAt</strong>, and <strong>lastErrorMessage </strong>capture health.</p></li><li><p><strong>totalRuns</strong>, <strong>totalSuccess</strong>, <strong>totalFailures </strong>capture a small history without needing a full timeseries DB.</p></li></ul><p>The mechanism is intentionally small and transparent: methods annotated with <code>@</code><strong>TrackedTask </strong>are intercepted by <strong>TaskTrackingAspect</strong>. This keeps the task beans themselves focused on their domain logic, while the cross-cutting concerns (timing, success/failure bookkeeping) live in one place.</p><p>You can view the current state at runtime via:</p><ul><li><p><code>GET /api/week1/scheduler/tasks</code> (implemented by <code>TaskRegistryController</code>)</p></li></ul><p>This is not meant to replace Prometheus/Grafana; it&#8217;s a debugging surface that makes scheduling correctness visible immediately during local development.</p><h2><strong>6. Step-by-Step Implementation Guide</strong></h2><h2>Github Link :</h2><p><a href="https://github.com/sysdr/sdc-java-p/tree/main/week_1_integrated_project/week_1_integrated_project">https://github.com/sysdr/sdc-java-p/tree/main/week_1_integrated_project/week_1_integrated_project</a></p><ol><li><p>Start from the single application entry point in <strong>com.example.week1.Week1IntegratedApplication</strong>. This is where <code>@</code><strong>EnableScheduling </strong>is activated and where component scanning is rooted.</p></li><li><p>Configure a real scheduler rather than relying on defaults. <strong>com.example.week1.common.config.SchedulingConfig</strong> provides a <strong>ThreadPoolTaskScheduler</strong> with a bounded pool and predictable thread names (<code>week1-scheduler-*</code>). This makes debugging and performance reasoning possible.</p></li><li><p>Define a minimal &#8220;task identity&#8221; abstraction with <strong>com.example.week1.common.scheduling.TrackedTask</strong>. In the real world, observability needs stable identifiers; method names are not enough once refactors begin.</p></li><li><p>Implement state storage with <strong>com.example.week1.common.scheduling.TaskRegistry</strong> and <strong>TaskState</strong>. Keep it thread-safe by construction <strong>(ConcurrentHashMap </strong>for registry, volatile fields on state).</p></li><li><p>Add cross-cutting tracking using <strong>com.example.week1.common.scheduling.TaskTrackingAspect.</strong> It wraps tracked scheduled methods and records RUNNING/SUCCESS/FAILED transitions along with timestamps and error summaries.</p></li><li><p>Annotate real scheduled methods so the registry reflects actual system behavior. In this project those methods live in:</p><ul><li><p><strong>Day2LogGenerationService.updateMetrics()</strong></p><ul><li><p><strong>Day3LogCollectorService.logStatistics()</strong></p><ul><li><p><strong>Day5RotationPolicyService.evaluateRotationPolicies()</strong></p></li></ul></li></ul></li></ul></li><li><p>Expose the scheduler&#8217;s state as an API via <strong>com.example.week1.common.web.TaskRegistryController</strong> at <strong>/api/week1/scheduler/tasks</strong>. This endpoint is a local operator interface for verifying that tasks are alive and healthy.</p></li><li><p>Validate the end-to-end system using the existing operational endpoints and flows:</p><ul><li><p><strong>POST /api/week1/day2/generator/start </strong>to create ongoing activity.</p><ul><li><p><strong>POST /api/week1/day1/logs</strong> to inject events.</p><ul><li><p><strong>GET /api/week1/scheduler/tasks</strong> to confirm periodic tasks are running and succeeding.</p></li></ul></li></ul></li></ul></li></ol><h2><strong>7. Key Engineering Insights</strong></h2><p>Thread safety isn&#8217;t optional in scheduled systems because there&#8217;s no user request boundary to &#8220;hide&#8221; behind.<strong> Day2LogGenerationService</strong> uses <strong>AtomicLong/AtomicInteger</strong> for counters because the scheduled tick <strong>(updateMetrics)</strong> is racing with generator threads that increment counters. If those updates weren&#8217;t atomic you&#8217;d get negative or inconsistent rates, which is the kind of bug that looks like &#8220;the system is flaky&#8221; rather than &#8220;the math is wrong.&#8221;</p><p>Fixed-rate and fixed-delay scheduling are not interchangeable. This project uses <strong>fixedRate</strong> for periodic accounting and rotation evaluation. In a production service you&#8217;d choose<strong> fixedDelay</strong> when work duration matters more than wall-clock alignment (e.g., &#8220;run 5 minutes after the last successful completion&#8221;), and <strong>fixedRate</strong> when you want alignment to time windows (e.g., &#8220;every second, compute a rolling rate&#8221;). Even locally, those differences show up when tasks get slow or the system is under load.</p><p>Cron expressions are powerful but brittle when you need dynamic behavior. This week&#8217;s code uses <code>@</code><strong>Scheduled </strong>with explicit intervals, which keeps behavior testable and easy to reason about. In later weeks, adding cron schedules (or Quartz) makes sense when you need calendar-aligned jobs, but you still need the same observability and state tracking; cron does not remove the need for task health.</p><p>Testability improves when scheduling is separated from work. The tracking layer in <strong>TaskTrackingAspect</strong> makes task state independent from the business logic. This means you can unit test the domain work<strong> (e.g., Day4LogParsingService.parseLogEntry)</strong> without time, and then separately exercise scheduling behavior via integration tests that assert <strong>/api/week1/scheduler/tasks</strong> transitions.</p><h2><strong>8. Success Metrics</strong></h2><h3><strong>Modularity</strong></h3><p>You should be able to point to scheduling-related code without digging through business logic. Concretely:</p><ul><li><p><strong>SchedulingConfig</strong> contains scheduler configuration only.</p></li><li><p>Task tracking lives only in <code>common/scheduling/*</code>.</p></li><li><p>Day modules<strong> (day2, day3, day5)</strong> keep scheduled logic in their own services.</p></li></ul><h3><strong>Readability</strong></h3><p>A reader should be able to answer &#8220;what tasks are scheduled?&#8221; quickly:</p><ul><li><p>The scheduled methods are visible via <strong>@Scheduled</strong> on:</p><ul><li><p><strong>Day2LogGenerationService.updateMetrics()</strong></p><ul><li><p><strong>Day3LogCollectorService.logStatistics()</strong></p><ul><li><p><strong>Day5RotationPolicyService.evaluateRotationPolicies()</strong></p></li></ul></li></ul></li></ul></li><li><p>Each of those methods has a stable id and description via <strong>@TrackedTask.</strong></p></li></ul><h3><strong>Correctness</strong></h3><p>Scheduling correctness isn&#8217;t &#8220;it compiles.&#8221; It&#8217;s observable behavior:</p><ul><li><p><strong>GET /api/week1/scheduler/tasks </strong>returns entries for <strong>day2.updateMetrics, day3.logStatistics, </strong>and <strong>day5.rotateColdFiles.</strong></p></li><li><p>Each task transitions through RUNNING &#8594; SUCCESS repeatedly under normal operation.</p></li><li><p>When a task fails,<strong> lastErrorMessage</strong> is populated and <strong>totalFailures </strong>increases.</p></li></ul><h3><strong>Extensibility</strong></h3><p>Adding a new scheduled task should not require copy/pasting tracking code:</p><ul><li><p>A new task is created by adding <strong>@Scheduled</strong> + <strong>@TrackedTask</strong> to a method on any bean.</p></li><li><p>The registry and endpoint automatically reflect the new task id.</p></li><li><p>The scheduler pool size and behavior can be tuned in one place <strong>(SchedulingConfig).</strong></p></li></ul><h2><strong>9. Conclusion</strong></h2><p>After building and running this integrated project, you should see scheduling as a system concern rather than an annotation. The core idea is that time-based work needs the same discipline as request-driven code: bounded concurrency <strong>(ThreadPoolTaskScheduler)</strong>, clear ownership (per-day modules), and observability (task state plus metrics).</p><p>From here, the natural next step is taking scheduling beyond a single JVM. Once you have multiple instances, &#8220;every instance runs the cron&#8221; becomes a correctness bug. That&#8217;s where distributed scheduling patterns come in: leader election, database-backed locks, Quartz clustered mode, or dedicated schedulers. The mechanics change, but the fundamentals you practiced here&#8212;explicit task identity, clear state, and careful concurrency&#8212;carry straight through.</p><h2>Working Code Demo :</h2><div id="youtube2-GVb_1fcMDOk" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;GVb_1fcMDOk&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/GVb_1fcMDOk?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>]]></content:encoded></item><item><title><![CDATA[Day 60: Multi-Region Replication for Log Data]]></title><description><![CDATA[What We&#8217;re Building Today]]></description><link>https://sdcourse.substack.com/p/day-60-multi-region-replication-for</link><guid isPermaLink="false">https://sdcourse.substack.com/p/day-60-multi-region-replication-for</guid><dc:creator><![CDATA[sdr11]]></dc:creator><pubDate>Tue, 26 May 2026 03:54:36 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!PalK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ff7e796-7bb7-40df-9bff-4582fe3f4781_6000x4100.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>What We&#8217;re Building Today</h2><blockquote><p>Yesterday you implemented active-passive failover so critical components recover automatically. Today, you&#8217;re taking that foundation and turning it into a <strong>globally replicated log pipeline</strong> &#8212; the backbone of every major cloud-native observability stack in production.</p><p>By the end of this lesson you will have:</p></blockquote><ul><li><p><strong>A multi-region Kafka replication topology</strong> that mirrors log events across two simulated geographic regions using MirrorMaker 2</p></li><li><p><strong>A conflict-resolution strategy</strong> for out-of-order and duplicate events that arrive from separate regions during a split-brain scenario</p></li><li><p><strong>Region-aware routing in the API Gateway</strong> that directs producers to the nearest region while keeping consumers globally consistent</p></li><li><p><strong>End-to-end monitoring</strong> that surfaces replication lag, cross-region throughput, and divergence alerts in Grafana</p></li></ul><div><hr></div><h2>Why This Matters</h2><blockquote><p>A single-region log system is an availability bet. The moment your datacenter loses power, your network partition hits, or your cloud provider has an outage affecting one zone, every log event generated during that window is either lost or delayed &#8212; and in observability, delayed logs are nearly as dangerous as missing logs because they break correlation windows used for incident diagnosis.</p><p>Multi-region replication is how Netflix kept its recommendation engine&#8217;s telemetry flowing during the 2012 US East outage, how Uber surfaces driver GPS traces in the nearest region while guaranteeing global query consistency, and how Amazon&#8217;s Route 53 health checks keep log ingestion alive across continents. The pattern is deceptively simple in marketing materials &#8212; &#8220;we just replicate&#8221; &#8212; but the engineering trade-offs around consistency, ordering, and deduplication are where real system designers earn their credibility. Today you&#8217;ll wrestle with those trade-offs hands-on.</p></blockquote><div><hr></div><h2>System Design Deep Dive</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!PalK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ff7e796-7bb7-40df-9bff-4582fe3f4781_6000x4100.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!PalK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ff7e796-7bb7-40df-9bff-4582fe3f4781_6000x4100.png 424w, https://substackcdn.com/image/fetch/$s_!PalK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ff7e796-7bb7-40df-9bff-4582fe3f4781_6000x4100.png 848w, https://substackcdn.com/image/fetch/$s_!PalK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ff7e796-7bb7-40df-9bff-4582fe3f4781_6000x4100.png 1272w, https://substackcdn.com/image/fetch/$s_!PalK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ff7e796-7bb7-40df-9bff-4582fe3f4781_6000x4100.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!PalK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ff7e796-7bb7-40df-9bff-4582fe3f4781_6000x4100.png" width="596" height="407.29395604395603" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2ff7e796-7bb7-40df-9bff-4582fe3f4781_6000x4100.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:995,&quot;width&quot;:1456,&quot;resizeWidth&quot;:596,&quot;bytes&quot;:3821225,&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://sdcourse.substack.com/i/187618540?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ff7e796-7bb7-40df-9bff-4582fe3f4781_6000x4100.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_!PalK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ff7e796-7bb7-40df-9bff-4582fe3f4781_6000x4100.png 424w, https://substackcdn.com/image/fetch/$s_!PalK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ff7e796-7bb7-40df-9bff-4582fe3f4781_6000x4100.png 848w, https://substackcdn.com/image/fetch/$s_!PalK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ff7e796-7bb7-40df-9bff-4582fe3f4781_6000x4100.png 1272w, https://substackcdn.com/image/fetch/$s_!PalK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ff7e796-7bb7-40df-9bff-4582fe3f4781_6000x4100.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 class="callout-block" data-callout="true"><p>Preparing for a distributed systems interview?</p><p>&#8594;<a href="https://systemdrd.com/ebooks/sdcourse-distributed-systems-interview">Download the free Interview Pack</a></p><p>&#8594; <a href="https://sdcourse.substack.com/subscribe">Subscribe</a> now to access source code repository - 200 + coding lessons</p></div><h3>1. Replication Topology: Active-Active vs. Active-Passive</h3><p>Day 59 gave you active-passive failover within a single region. Multi-region replication forces a harder question: do both regions write simultaneously, or does one region always own the write path?</p><p><strong>Active-passive replication</strong> keeps things simple. Region A is the primary; Region B is a hot standby that receives replicated data but does not accept producer writes under normal conditions. Failover promotes Region B to primary. The cost: Region B&#8217;s logs are always <em>behind</em> by the replication lag, so during a failover you accept a small window of potential data loss (RPO).</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://sdcourse.substack.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">Hands On System Design Course - Code Everyday  is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</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>Active-active replication</strong> lets both regions accept writes simultaneously and cross-replicate. Throughput doubles and RPO drops to near-zero, but you immediately introduce the <strong>split-brain problem</strong>: if the replication link between regions fails, both regions continue accepting writes independently. When the link recovers, you have two divergent histories and must merge them.</p><p>For a log processing system, active-active is almost always the right call. Logs are append-only, high-volume, and latency-sensitive. The deduplication cost of merging after a split is far less than the cost of dropping events during an outage. Today&#8217;s implementation uses active-active with <strong>idempotency-key-based deduplication</strong> at the consumer layer to resolve conflicts.</p><blockquote><p><strong>Architectural Insight:</strong> Kafka&#8217;s MirrorMaker 2 was designed for active-active. It uses topic-offset translation to prevent replication loops &#8212; Region A&#8217;s copy of Region B&#8217;s topic is tagged with a source prefix, so MirrorMaker in Region B does not re-replicate it back. Understanding this loop-prevention mechanism is what separates a working multi-region Kafka setup from one that spirals into infinite replication.</p></blockquote><h3>2. Ordering Guarantees Across Regions</h3><p>Kafka guarantees ordering <em>within a partition on a single broker</em>. Cross-region replication shatters that guarantee. An event produced in Region A at T=100ms may arrive in Region B at T=250ms, but an event produced in Region B at T=180ms is already sitting in Region B&#8217;s partition at T=180ms. A consumer reading Region B&#8217;s merged topic sees events out of order relative to their original production time.</p><p>The standard mitigation is a <strong>watermark-based reorder buffer</strong> at the consumer. Each consumer maintains a sliding window (configurable, typically 500ms&#8211;2s) and holds events until it&#8217;s confident no earlier event will arrive from the other region. Events older than the watermark are flushed in order; events that arrive after the watermark has passed are flagged as late arrivals and routed to a dead-letter partition for reconciliation.</p><p>This is exactly the pattern used in Google&#8217;s Dataflow and Flink&#8217;s event-time processing. The trade-off is clear: lower watermark = lower latency, higher risk of out-of-order emissions. Higher watermark = better ordering, higher end-to-end latency. Today&#8217;s implementation exposes the watermark as a tunable configuration property so you can observe the effect directly in your load tests.</p><h3>3. Deduplication Strategy</h3><p>When both regions accept writes and the replication link recovers after a split, some events will exist in both regions&#8217; topics. A naive consumer will process them twice &#8212; which, for a log indexing system, means duplicate entries in your search backend and inflated metrics.</p><p>The production pattern is <strong>server-side idempotency with a distributed cache</strong>. Each log event carries an <code>eventId</code> (a UUID generated by the producer at ingestion time). The consumer checks a Redis-backed bloom filter before processing. If the <code>eventId</code> is already present, the event is silently discarded. Bloom filters give you probabilistic deduplication with near-zero memory overhead &#8212; the false-positive rate (roughly 0.01% at our configuration) is an acceptable trade-off for the memory savings versus a full hash set.</p><p>Uber&#8217;s log platform uses a similar two-tier approach: a fast bloom filter for the hot path, backed by a slower exact-match store for audit trails. You&#8217;ll implement both tiers today.</p><h3>4. Region-Aware Routing</h3><p>The API Gateway needs to know which region a producer request should target. In a real deployment this is DNS-based (GeoDNS routes to the nearest region). In our simulated environment, the gateway reads a <code>X-Region</code> header and routes accordingly, with a fallback to the local region if the target is unhealthy.</p><p>The key design decision here is <strong>sticky routing</strong>: once a producer is assigned to a region for a given session or logical group (e.g., all logs from a single microservice instance), it should stay on that region until a health event forces migration. This minimizes cross-region replication pressure and keeps event ordering more predictable within a single producer&#8217;s stream.</p><h3>5. Monitoring Replication Health</h3><p>Replication lag is the single most important operational metric for a multi-region system. If Region B&#8217;s consumer offset falls more than 10 seconds behind Region A&#8217;s producer offset, you&#8217;re approaching your RPO budget. Prometheus scrapes both regions&#8217; Kafka exporters every 15 seconds; Grafana alerts fire when lag exceeds configurable thresholds.</p><p>Beyond lag, you need to track <strong>replication throughput</strong> (bytes/sec crossing the region boundary), <strong>split-brain duration</strong> (time between network partition and recovery), and <strong>deduplication hit rate</strong> (percentage of events filtered by the bloom filter). All four metrics are wired into today&#8217;s Grafana dashboard.</p><div><hr></div><h2>Implementation Walkthrough</h2><h3>GitHub Link :</h3><pre><code><a href="https://github.com/sysdr/sdc-java-p/tree/main/day60/day60-multi-region-log-replication">https://github.com/sysdr/sdc-java-p/tree/main/day60/day60-multi-region-log-replication</a></code></pre><h3>Step 1: MirrorMaker 2 Configuration</h3><p>The <code>docker-compose.yml</code> spins up two Kafka clusters (<code>kafka-region-a</code>, <code>kafka-region-b</code>) and two MirrorMaker 2 instances. Each MirrorMaker is configured with a <code>source.cluster</code> and <code>target.cluster</code>, and a replication factor of 2. The topic replication policy uses a regex filter (<code>log-events-.*</code>) so only your log topics are mirrored &#8212; not internal Kafka topics like <code>__consumer_offsets</code>.</p><p>The critical configuration property is <code>replication.lag.max.bytes</code>. Set this too high and your failover RPO balloons. Set it too low and MirrorMaker becomes a bottleneck under peak load. Start at 1MB and tune based on your load test results.</p><h3>Step 2: Region-Aware Producer</h3><p><code>KafkaProducerService</code> now accepts a <code>targetRegion</code> parameter. Under the hood it maintains two <code>KafkaProducer</code> instances &#8212; one per region &#8212; and selects the appropriate one based on the routing decision from the gateway. If the target region&#8217;s producer fails to send within the configured timeout, the service falls back to the local region and logs a <code>REGION_FALLBACK</code> event for monitoring.</p><h3>Step 3: Watermark Consumer</h3><p><code>ReplicationAwareConsumer</code> extends the base consumer with a <code>ReorderBuffer</code>. On each poll cycle, the buffer checks whether the current event&#8217;s <code>eventTimestamp</code> is within the watermark window. Events inside the window are held; events outside are emitted to the downstream processor in timestamp order. Late arrivals (events with timestamps older than the current watermark) are sent to the <code>log-events-late</code> dead-letter topic.</p><h3>Step 4: Bloom Filter Deduplication</h3><p><code>DeduplicationService</code> wraps a Guava <code>BloomFilter</code> backed by a Redis <code>HyperLogLog</code> for cross-instance coordination. Each consumer instance maintains its own local bloom filter for speed, and periodically syncs its state to Redis so that if a consumer instance restarts, it can rebuild from the shared state. The sync interval is configurable &#8212; 30 seconds is the default, balancing consistency with network overhead.</p><h3>Step 5: Integration and Load Testing</h3><p>The <code>load-test.sh</code> script fires 10,000 events split evenly across both simulated regions over 60 seconds, then pauses replication for 5 seconds (simulating a split) and resumes. The integration test suite validates that after recovery, the total unique events processed across both regions equals 10,000 &#8212; confirming that deduplication caught all duplicates and the reorder buffer caught all late arrivals.</p><h3>Working Demo Link :</h3><div id="youtube2-8nCvo85_4vs" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;8nCvo85_4vs&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/8nCvo85_4vs?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><h2>Production Considerations</h2><p><strong>Latency budget:</strong> MirrorMaker 2 adds 50&#8211;200ms of replication latency depending on network distance. If your log consumers have SLAs tighter than that, you need region-local consumption with eventual cross-region consistency, not strong consistency.</p><p><strong>Failure mode &#8212; MirrorMaker crash:</strong> If MirrorMaker goes down, replication stops but both clusters continue accepting writes independently. This is by design. When MirrorMaker restarts, it resumes from the last committed offset. No data is lost; lag temporarily spikes.</p><p><strong>Capacity planning:</strong> Each region needs enough Kafka broker capacity to handle its own write load <em>plus</em> the full replication load from the other region. In practice, this means sizing each region for roughly 1.8x its expected standalone throughput to account for replication overhead and burst traffic.</p><div><hr></div><h2>Scale Connection</h2><p>Netflix&#8217;s EVIPro (Event Processing Infrastructure) uses a topology nearly identical to what you built today: active-active Kafka clusters across three regions, MirrorMaker 2 for cross-region replication, and a custom deduplication layer at the consumer. Uber&#8217;s logging pipeline (documented in their 2021 engineering blog) applies the same watermark-based reorder buffer pattern for GPS event streams that must be globally consistent for driver tracking. Amazon&#8217;s CloudWatch Logs uses a similar region-aware routing strategy to keep log ingestion latency under 100ms globally.</p><p></p><h4><strong>This is just the starting point.</strong> </h4><p>The paid content includes advanced lessons, frameworks, templates, practical projects, and deeper explanations to accelerate your learning journey.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://sdcourse.substack.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">LogStream &#8212; Build Distributed Systems is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</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><hr></div><h2>Next Steps</h2><p>Tomorrow: circuit breakers with Resilience4j &#8212; how to keep your system healthy when downstream components start failing.</p>]]></content:encoded></item><item><title><![CDATA[Day 59: Implement Active-Passive Failover for Critical Components]]></title><description><![CDATA[What We&#8217;re Building Today]]></description><link>https://sdcourse.substack.com/p/day-59-implement-active-passive-failover</link><guid isPermaLink="false">https://sdcourse.substack.com/p/day-59-implement-active-passive-failover</guid><dc:creator><![CDATA[sdr11]]></dc:creator><pubDate>Tue, 19 May 2026 09:00:50 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!hBGV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a62f59-2b02-4304-b297-95383f16a840_6332x6000.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>What We&#8217;re Building Today</h2><ul><li><p><strong>Active-passive failover mechanism</strong> for Kafka consumers with automatic leader election</p></li><li><p><strong>Health monitoring system</strong> with heartbeat detection and failure recovery</p></li><li><p><strong>Stateful component migration</strong> with zero data loss guarantees</p></li><li><p><strong>Failover orchestration</strong> demonstrating sub-second recovery times</p></li></ul><h2>Why This Matters</h2><blockquote><p>High availability isn&#8217;t optional at scale&#8212;it&#8217;s the difference between 99.9% and 99.99% uptime, which translates to 8.76 hours versus 52 minutes of downtime per year. When Netflix streams to 200M+ subscribers or Uber coordinates millions of rides, a single point of failure can cascade into millions in lost revenue and eroded user trust.</p><p>Active-passive failover solves the fundamental distributed systems challenge: how do you ensure critical components continue operating when infrastructure fails? Unlike active-active architectures that require complex conflict resolution, active-passive provides simpler consistency guarantees while maintaining high availability. This pattern appears in everything from database replication (PostgreSQL streaming replication) to message broker cluster management (Kafka controller election) to API gateway redundancy.</p><p>Today&#8217;s implementation tackles the hardest part of failover: coordinating state migration without data loss while minimizing downtime. You&#8217;ll see why &#8220;just restart the service&#8221; isn&#8217;t sufficient at scale, and how distributed consensus enables automatic recovery.</p></blockquote><h2>System Design Deep Dive</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hBGV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a62f59-2b02-4304-b297-95383f16a840_6332x6000.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hBGV!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a62f59-2b02-4304-b297-95383f16a840_6332x6000.png 424w, https://substackcdn.com/image/fetch/$s_!hBGV!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a62f59-2b02-4304-b297-95383f16a840_6332x6000.png 848w, https://substackcdn.com/image/fetch/$s_!hBGV!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a62f59-2b02-4304-b297-95383f16a840_6332x6000.png 1272w, https://substackcdn.com/image/fetch/$s_!hBGV!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a62f59-2b02-4304-b297-95383f16a840_6332x6000.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hBGV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a62f59-2b02-4304-b297-95383f16a840_6332x6000.png" width="490" height="464.30827542640554" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/02a62f59-2b02-4304-b297-95383f16a840_6332x6000.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:6000,&quot;width&quot;:6332,&quot;resizeWidth&quot;:490,&quot;bytes&quot;:2327374,&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://sdcourse.substack.com/i/187618084?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c36df1b-d007-446a-b37f-b3827ca51f9b_8500x6000.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!hBGV!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a62f59-2b02-4304-b297-95383f16a840_6332x6000.png 424w, https://substackcdn.com/image/fetch/$s_!hBGV!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a62f59-2b02-4304-b297-95383f16a840_6332x6000.png 848w, https://substackcdn.com/image/fetch/$s_!hBGV!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a62f59-2b02-4304-b297-95383f16a840_6332x6000.png 1272w, https://substackcdn.com/image/fetch/$s_!hBGV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a62f59-2b02-4304-b297-95383f16a840_6332x6000.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 class="callout-block" data-callout="true"><p>Preparing for a distributed systems interview? </p><p>&#8594; <a href="https://systemdrd.com/ebooks/sdcourse-distributed-systems-interview">Download the free Interview Pack</a></p><p>&#8594;<a href="https://sdcourse.substack.com/subscribe">Subscribe</a> now to access source code repository - 200 + coding lessons </p></div>
      <p>
          <a href="https://sdcourse.substack.com/p/day-59-implement-active-passive-failover">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 58: Build a Search API for Programmatic Access]]></title><description><![CDATA[What We&#8217;re Building Today]]></description><link>https://sdcourse.substack.com/p/day-58-build-a-search-api-for-programmatic</link><guid isPermaLink="false">https://sdcourse.substack.com/p/day-58-build-a-search-api-for-programmatic</guid><dc:creator><![CDATA[sdr11]]></dc:creator><pubDate>Tue, 12 May 2026 11:19:19 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!E0zU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc761f3ac-f4a7-46a6-be99-30526a85498c_1500x1000.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>What We&#8217;re Building Today</h2><blockquote><p>Today we&#8217;re implementing a production-grade RESTful search API that exposes our distributed log analytics system to programmatic clients. You&#8217;ll build:</p></blockquote><ul><li><p><strong>RESTful API Gateway</strong> with versioned endpoints, pagination, and rate limiting</p></li><li><p><strong>Query DSL Parser</strong> that translates HTTP requests into optimized Elasticsearch queries</p></li><li><p><strong>Response Streaming</strong> for large result sets with cursor-based pagination</p></li><li><p><strong>Authentication &amp; Authorization</strong> layer with API key management and quota enforcement</p></li></ul><h2>Why This Matters</h2><blockquote><p>The gap between powerful analytics capabilities and programmatic access is where most distributed systems fail to deliver business value. Netflix processes 1 trillion events daily, but their value comes from exposing this data through APIs that power recommendations, fraud detection, and A/B testing. Your search infrastructure might index petabytes of logs, but without a well-designed API, teams resort to manual queries, CSV exports, and one-off scripts.</p><p>The challenge isn&#8217;t just exposing Elasticsearch through HTTP&#8212;it&#8217;s designing an API contract that remains stable as your backend evolves, scales to thousands of requests per second without crushing your cluster, and provides query flexibility while preventing abuse. Twitter&#8217;s Firehose API demonstrates this: they expose real-time tweet streams to thousands of clients while protecting cluster stability through sophisticated rate limiting and quota management. This lesson bridges analytics infrastructure and API design, teaching you to build interfaces that unlock data access without compromising system integrity.</p></blockquote><h2>System Design Deep Dive</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!E0zU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc761f3ac-f4a7-46a6-be99-30526a85498c_1500x1000.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!E0zU!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc761f3ac-f4a7-46a6-be99-30526a85498c_1500x1000.png 424w, https://substackcdn.com/image/fetch/$s_!E0zU!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc761f3ac-f4a7-46a6-be99-30526a85498c_1500x1000.png 848w, https://substackcdn.com/image/fetch/$s_!E0zU!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc761f3ac-f4a7-46a6-be99-30526a85498c_1500x1000.png 1272w, https://substackcdn.com/image/fetch/$s_!E0zU!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc761f3ac-f4a7-46a6-be99-30526a85498c_1500x1000.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!E0zU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc761f3ac-f4a7-46a6-be99-30526a85498c_1500x1000.png" width="574" height="382.7980769230769" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c761f3ac-f4a7-46a6-be99-30526a85498c_1500x1000.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;:574,&quot;bytes&quot;:285239,&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://sdcourse.substack.com/i/187617509?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc761f3ac-f4a7-46a6-be99-30526a85498c_1500x1000.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_!E0zU!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc761f3ac-f4a7-46a6-be99-30526a85498c_1500x1000.png 424w, https://substackcdn.com/image/fetch/$s_!E0zU!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc761f3ac-f4a7-46a6-be99-30526a85498c_1500x1000.png 848w, https://substackcdn.com/image/fetch/$s_!E0zU!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc761f3ac-f4a7-46a6-be99-30526a85498c_1500x1000.png 1272w, https://substackcdn.com/image/fetch/$s_!E0zU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc761f3ac-f4a7-46a6-be99-30526a85498c_1500x1000.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>
          <a href="https://sdcourse.substack.com/p/day-58-build-a-search-api-for-programmatic">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 57: Full-Text Search with Relevance Scoring]]></title><description><![CDATA[What We&#8217;re Building Today]]></description><link>https://sdcourse.substack.com/p/day-57-full-text-search-with-relevance</link><guid isPermaLink="false">https://sdcourse.substack.com/p/day-57-full-text-search-with-relevance</guid><dc:creator><![CDATA[sdr11]]></dc:creator><pubDate>Fri, 08 May 2026 07:53:28 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!QY1X!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb98a54f9-0f04-479e-9558-bfa725c6939c_6000x4000.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>What We&#8217;re Building Today</h2><ul><li><p><strong>Elasticsearch integration</strong> for distributed full-text search across log streams</p></li><li><p><strong>BM25 ranking algorithm</strong> implementation with custom scoring functions</p></li><li><p><strong>Multi-field search</strong> supporting structured and unstructured log data</p></li><li><p><strong>Real-time search API</strong> with sub-100ms query latency for millions of logs</p></li></ul><h2>Why This Matters</h2><blockquote><p>When Netflix processes 500 billion events daily, engineers need to find specific error patterns across distributed services in seconds, not hours. Traditional database queries fall apart at this scale&#8212;a <code>LIKE '%error%'</code> query on 100M log entries will bring PostgreSQL to its knees. Full-text search engines like Elasticsearch solve this by inverting the problem: instead of scanning documents for terms, they build inverted indices that map terms to documents instantly.</p><p>The challenge isn&#8217;t just speed&#8212;it&#8217;s relevance. When searching &#8220;authentication timeout user service,&#8221; you want logs matching all terms ranked higher than partial matches, recent errors prioritized over old ones, and critical severity logs surfaced first. This requires sophisticated scoring algorithms that understand both textual similarity and domain-specific importance signals.</p></blockquote><h2>System Design Deep Dive</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QY1X!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb98a54f9-0f04-479e-9558-bfa725c6939c_6000x4000.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QY1X!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb98a54f9-0f04-479e-9558-bfa725c6939c_6000x4000.png 424w, https://substackcdn.com/image/fetch/$s_!QY1X!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb98a54f9-0f04-479e-9558-bfa725c6939c_6000x4000.png 848w, https://substackcdn.com/image/fetch/$s_!QY1X!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb98a54f9-0f04-479e-9558-bfa725c6939c_6000x4000.png 1272w, https://substackcdn.com/image/fetch/$s_!QY1X!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb98a54f9-0f04-479e-9558-bfa725c6939c_6000x4000.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QY1X!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb98a54f9-0f04-479e-9558-bfa725c6939c_6000x4000.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b98a54f9-0f04-479e-9558-bfa725c6939c_6000x4000.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;:1611688,&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://sdcourse.substack.com/i/186707534?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb98a54f9-0f04-479e-9558-bfa725c6939c_6000x4000.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_!QY1X!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb98a54f9-0f04-479e-9558-bfa725c6939c_6000x4000.png 424w, https://substackcdn.com/image/fetch/$s_!QY1X!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb98a54f9-0f04-479e-9558-bfa725c6939c_6000x4000.png 848w, https://substackcdn.com/image/fetch/$s_!QY1X!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb98a54f9-0f04-479e-9558-bfa725c6939c_6000x4000.png 1272w, https://substackcdn.com/image/fetch/$s_!QY1X!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb98a54f9-0f04-479e-9558-bfa725c6939c_6000x4000.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>
          <a href="https://sdcourse.substack.com/p/day-57-full-text-search-with-relevance">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 56: Real-Time Indexing of Incoming Logs]]></title><description><![CDATA[What We&#8217;re Building Today]]></description><link>https://sdcourse.substack.com/p/day-56-real-time-indexing-of-incoming</link><guid isPermaLink="false">https://sdcourse.substack.com/p/day-56-real-time-indexing-of-incoming</guid><dc:creator><![CDATA[sdr11]]></dc:creator><pubDate>Mon, 04 May 2026 10:02:09 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!PDTD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3794f15f-c868-47e4-9358-2011b668fb10_7000x4500.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>What We&#8217;re Building Today</h2><ul><li><p><strong>Near-real-time indexing pipeline</strong> that indexes logs within 100ms of arrival</p></li><li><p><strong>Distributed inverted index</strong> with LSM-tree optimization for high write throughput</p></li><li><p><strong>Index coordination layer</strong> managing shard distribution and replication across nodes</p></li><li><p><strong>Query API</strong> with millisecond-latency searches over freshly indexed data</p></li></ul><h2>Why This Matters</h2><blockquote><p>Search latency directly impacts incident response time. When a production outage occurs, every second engineers spend waiting for logs to become searchable costs money and customer trust. Netflix processes 1 trillion events daily&#8212;if their indexing pipeline had even a 10-second delay, teams would be flying blind during critical incidents. Real-time indexing transforms logs from historical artifacts into actionable intelligence.</p><p>The challenge isn&#8217;t just speed&#8212;it&#8217;s maintaining search quality while ingesting 50,000+ events per second. Traditional batch indexing offers perfect consistency but unacceptable latency. Stream-based indexing delivers speed but introduces complexity around partial updates, segment management, and query consistency. Today&#8217;s architecture balances these trade-offs using proven patterns from Elasticsearch, Splunk, and Datadog.</p></blockquote><h2>System Design Deep Dive</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!PDTD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3794f15f-c868-47e4-9358-2011b668fb10_7000x4500.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!PDTD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3794f15f-c868-47e4-9358-2011b668fb10_7000x4500.png 424w, https://substackcdn.com/image/fetch/$s_!PDTD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3794f15f-c868-47e4-9358-2011b668fb10_7000x4500.png 848w, https://substackcdn.com/image/fetch/$s_!PDTD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3794f15f-c868-47e4-9358-2011b668fb10_7000x4500.png 1272w, https://substackcdn.com/image/fetch/$s_!PDTD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3794f15f-c868-47e4-9358-2011b668fb10_7000x4500.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!PDTD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3794f15f-c868-47e4-9358-2011b668fb10_7000x4500.png" width="1456" height="936" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3794f15f-c868-47e4-9358-2011b668fb10_7000x4500.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:936,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2387237,&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://sdcourse.substack.com/i/186286569?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3794f15f-c868-47e4-9358-2011b668fb10_7000x4500.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_!PDTD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3794f15f-c868-47e4-9358-2011b668fb10_7000x4500.png 424w, https://substackcdn.com/image/fetch/$s_!PDTD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3794f15f-c868-47e4-9358-2011b668fb10_7000x4500.png 848w, https://substackcdn.com/image/fetch/$s_!PDTD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3794f15f-c868-47e4-9358-2011b668fb10_7000x4500.png 1272w, https://substackcdn.com/image/fetch/$s_!PDTD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3794f15f-c868-47e4-9358-2011b668fb10_7000x4500.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>
          <a href="https://sdcourse.substack.com/p/day-56-real-time-indexing-of-incoming">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 55: Faceted Search for Multi-Dimensional Log Analytics]]></title><description><![CDATA[What We&#8217;re Building Today]]></description><link>https://sdcourse.substack.com/p/day-55-faceted-search-for-multi-dimensional</link><guid isPermaLink="false">https://sdcourse.substack.com/p/day-55-faceted-search-for-multi-dimensional</guid><dc:creator><![CDATA[sdr11]]></dc:creator><pubDate>Thu, 30 Apr 2026 10:41:06 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!ToB9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba1ec156-05b6-4b9d-8433-5aa1ee6a5d34_1750x1250.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>What We&#8217;re Building Today</h2><blockquote><p>Today we implement a production-grade faceted search system that enables simultaneous filtering across multiple dimensions of log data:</p></blockquote><ul><li><p><strong>Distributed faceted index</strong> with Elasticsearch supporting 10,000+ queries/sec</p></li><li><p><strong>Real-time facet aggregation</strong> computing filter counts across billions of log entries</p></li><li><p><strong>Multi-dimensional filtering</strong> enabling complex queries like &#8220;ERROR logs from service=auth AND host=prod-* in last 15 minutes&#8221;</p></li><li><p><strong>Intelligent caching layer</strong> with Redis reducing repeated aggregation overhead by 80%</p></li></ul><h2>Why This Matters: The Search at Scale Challenge</h2><blockquote><p>When Datadog ingests 1 trillion log events daily, users don&#8217;t just search for text&#8212;they filter by 20+ dimensions simultaneously: service name, environment, log level, HTTP status code, error type, region, host, container ID, and custom tags. Each facet must show real-time counts: &#8220;42,385 ERROR logs, 8,234 from auth-service, 3,102 in us-east-1.&#8221;</p><p>The naive approach&#8212;scanning all logs for each dimension&#8212;would require petabytes of I/O per second. Instead, production systems use inverted indexes, bitmap intersection, and distributed aggregation to deliver sub-second faceted search across massive datasets. Splunk&#8217;s faceted search handles 100,000+ concurrent users filtering terabytes of logs, while Elastic&#8217;s distributed aggregation framework powers real-time analytics for half of Fortune 500 companies.</p><p>The architectural challenge: how do you maintain accurate facet counts while ingesting 500,000 events/second, support complex boolean queries with 10+ filters, and cache strategically when facet distributions change every second? Today&#8217;s lesson implements the patterns that make billion-event search systems feel instantaneous.</p></blockquote><h2>System Design Deep Dive</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ToB9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba1ec156-05b6-4b9d-8433-5aa1ee6a5d34_1750x1250.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ToB9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba1ec156-05b6-4b9d-8433-5aa1ee6a5d34_1750x1250.png 424w, https://substackcdn.com/image/fetch/$s_!ToB9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba1ec156-05b6-4b9d-8433-5aa1ee6a5d34_1750x1250.png 848w, https://substackcdn.com/image/fetch/$s_!ToB9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba1ec156-05b6-4b9d-8433-5aa1ee6a5d34_1750x1250.png 1272w, https://substackcdn.com/image/fetch/$s_!ToB9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba1ec156-05b6-4b9d-8433-5aa1ee6a5d34_1750x1250.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ToB9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba1ec156-05b6-4b9d-8433-5aa1ee6a5d34_1750x1250.png" width="1456" height="1040" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ba1ec156-05b6-4b9d-8433-5aa1ee6a5d34_1750x1250.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1040,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:509867,&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://sdcourse.substack.com/i/186284087?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba1ec156-05b6-4b9d-8433-5aa1ee6a5d34_1750x1250.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_!ToB9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba1ec156-05b6-4b9d-8433-5aa1ee6a5d34_1750x1250.png 424w, https://substackcdn.com/image/fetch/$s_!ToB9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba1ec156-05b6-4b9d-8433-5aa1ee6a5d34_1750x1250.png 848w, https://substackcdn.com/image/fetch/$s_!ToB9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba1ec156-05b6-4b9d-8433-5aa1ee6a5d34_1750x1250.png 1272w, https://substackcdn.com/image/fetch/$s_!ToB9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba1ec156-05b6-4b9d-8433-5aa1ee6a5d34_1750x1250.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><h3>1. Inverted Indexes: The Foundation of Faceted Search</h3><p>Traditional log storage organizes by time: <code>2024-01-28 10:00:00 | ERROR | auth-service | Login failed</code>. Faceted search requires the inverse: given <code>level=ERROR</code>, which logs match? Elasticsearch and Solr build inverted indexes mapping each facet value to document IDs:</p><pre><code><code>service:auth-service &#8594; [doc1, doc5, doc89, doc234, ...]
level:ERROR &#8594; [doc1, doc12, doc89, doc156, ...]
region:us-east-1 &#8594; [doc5, doc12, doc234, ...]
</code></code></pre><p><strong>Trade-off Analysis</strong>: Inverted indexes consume 30-40% additional storage but reduce faceted query time from O(n) full scans to O(k) where k is the result set size. For 1 billion logs, this transforms a 10-minute scan into a 50ms index lookup. The cost: write amplification. Each log ingestion updates multiple indexes&#8212;one per facet. At scale, Datadog uses LSM-tree indexes (like Lucene) that batch writes and compact asynchronously, trading slightly stale facets (1-2 second lag) for 10x better write throughput.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://sdcourse.substack.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">Hands On System Design Course - Code Everyday  is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</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><h3>2. Bitmap Intersection: Combining Multiple Facets</h3><p>When users query <code>service=auth AND level=ERROR AND region=us-east-1</code>, the system must intersect three result sets. The naive approach iterates through each set sequentially&#8212;O(n1 + n2 + n3). Production systems use <strong>compressed bitmaps</strong> (Roaring Bitmaps) for bitwise AND operations completing in microseconds.</p><p>For 1 million matching document IDs, a sorted integer array consumes 4MB. A compressed bitmap uses 50KB with O(1) intersection. Twitter&#8217;s search infrastructure reduced facet query latency by 90% switching from hash-set intersection to roaring bitmaps. The pattern: represent document IDs as bit positions in a bitmap, use hardware-accelerated SIMD instructions for parallel intersection.</p><p><strong>Failure Mode</strong>: Sparse bitmaps (few set bits in large ranges) compress poorly and waste memory. Pinterest&#8217;s search team dynamically chooses between bitmaps and skip lists based on result set density&#8212;bitmaps for &gt;1% density, skip lists otherwise.</p><h3>3. Distributed Aggregation: Computing Facet Counts</h3><p>The hardest part of faceted search isn&#8217;t finding matching documents&#8212;it&#8217;s computing counts for each facet value in real-time. &#8220;Show me all ERROR logs AND tell me how many are from each service&#8221; requires scanning matching docs and aggregating dimensions.</p><p>Elasticsearch&#8217;s distributed aggregation uses a <strong>scatter-gather</strong> pattern:</p><ol><li><p><strong>Scatter</strong>: Send query to all shards (partitioned by time or hash)</p></li><li><p><strong>Local Aggregation</strong>: Each shard computes top-K facet values with counts</p></li><li><p><strong>Gather</strong>: Coordinator merges results, re-ranks, and returns final counts</p></li></ol><p>For a query matching 10 million logs across 50 shards, each shard processes 200K docs locally, returns top 1000 facet values. The coordinator merges 50 &#215; 1000 = 50K facet values into final top 1000. This reduces network transfer from 10 million to 50K results&#8212;a 200&#215; reduction.</p><p><strong>Scalability Bottleneck</strong>: Aggregation memory scales with cardinality (distinct facet values), not document count. A field with 1 million unique values requires 1M &#215; 8 bytes = 8MB per shard just for facet counts. LinkedIn&#8217;s search infrastructure uses <strong>HyperLogLog</strong> for approximate counts when exact values aren&#8217;t critical&#8212;1.5% error with 99% less memory.</p><h3>4. Intelligent Caching: Reducing Repeated Aggregation</h3><p>Facet distributions change slowly&#8212;the count of ERROR logs fluctuates, but relative proportions (auth-service: 30%, api-service: 25%) remain stable over minutes. Uber&#8217;s log search system caches facet aggregations in Redis with 60-second TTLs:</p><pre><code><code>cache_key = "facets:service:level=ERROR:last_15min:20240128T1000"
cache_value = {
  "auth-service": 8234,
  "api-service": 6012,
  "payment-service": 4829
}
</code></code></pre><p>The cache hit rate reaches 80% for dashboard queries where users repeatedly filter similar time ranges. Cache invalidation uses <strong>time-bucketed keys</strong>&#8212;cache expires naturally when time window shifts.</p><p><strong>Anti-Pattern</strong>: Caching final search results per user query. With 20 facets and 10+ values each, the query space explodes to billions of combinations. Cache aggregations at the <strong>dimension level</strong> (counts per facet), not query level.</p><h3>5. Query Optimization: Choosing Execution Paths</h3><p>Not all faceted queries are equal. <code>level=ERROR AND service=auth</code> (matching 0.1% of logs) should execute differently than <code>level!=ERROR AND service!=auth</code> (matching 99.9%). Production query planners use statistics to choose optimal execution:</p><p><strong>Strategy 1 - Filter First</strong>: For selective filters (matches &lt;5% of docs), retrieve matching doc IDs, then aggregate facets. Used when result set is small.</p><p><strong>Strategy 2 - Aggregate First</strong>: For broad filters (matches &gt;50%), compute all facet distributions, then filter. Avoids repeated aggregation for exploratory queries.</p><p>Elasticsearch&#8217;s query planner estimates cardinality using index statistics and chooses execution strategy automatically. Netflix&#8217;s search infrastructure reduced P99 latency from 8 seconds to 400ms by implementing cardinality-aware query planning&#8212;pre-computing aggregations for high-cardinality fields, streaming results for low-cardinality fields.</p><h2>Implementation Walkthrough</h2><h3>GitHub Link :</h3><pre><code><a href="https://github.com/sysdr/sdc-java/tree/main/day55/day55-faceted-search-system">https://github.com/sysdr/sdc-java/tree/main/day55/day55-faceted-search-system</a></code></pre><p>Our system implements faceted search with four services:</p><p><strong>1. Faceted Search Service (Spring Boot + Elasticsearch)</strong></p><p>The search service maintains Elasticsearch indexes with faceted fields. Each log document includes dimensions as analyzed fields:</p><pre><code><code>@Document(indexName = "logs")
public class LogDocument {
    private String id;
    private Instant timestamp;
    private String level;      // Facet: ERROR, WARN, INFO
    private String service;    // Facet: auth-service, api-service
    private String environment; // Facet: prod, staging
    private String host;       // Facet: prod-01, prod-02
    private String message;    // Full-text searchable
}
</code></code></pre><p>The search API accepts multi-dimensional filters and returns both matching logs and facet counts:</p><pre><code><code>@PostMapping("/search")
public FacetedSearchResponse search(@RequestBody SearchRequest request) {
    // Build Elasticsearch query with multiple filters
    BoolQueryBuilder query = QueryBuilders.boolQuery();
    request.getFilters().forEach((field, value) -&gt; 
        query.filter(QueryBuilders.termQuery(field, value))
    );
    
    // Add facet aggregations for each dimension
    SearchSourceBuilder searchBuilder = new SearchSourceBuilder()
        .query(query)
        .size(request.getLimit())
        .aggregation(AggregationBuilders.terms("by_level").field("level"))
        .aggregation(AggregationBuilders.terms("by_service").field("service"))
        .aggregation(AggregationBuilders.terms("by_environment").field("environment"));
    
    // Execute distributed query across all shards
    SearchResponse response = elasticsearchClient.search(searchBuilder);
    
    return buildFacetedResponse(response);
}
</code></code></pre><p><strong>2. Aggregation Service (Kafka Streams)</strong></p><p>Real-time facet counts flow through a Kafka Streams aggregation pipeline. As logs ingress, the service maintains materialized views of facet distributions:</p><pre><code><code>@Bean
public KStream&lt;String, LogEvent&gt; buildFacetAggregations(StreamsBuilder builder) {
    return builder.stream("logs")
        .groupBy((key, log) -&gt; log.getService())
        .windowedBy(TimeWindows.of(Duration.ofMinutes(5)))
        .count(Materialized.as("service-counts"))
        .toStream()
        .to("facet-aggregations");
}
</code></code></pre><p>These pre-computed aggregations seed the cache, reducing query-time aggregation overhead.</p><p><strong>3. Cache Layer (Redis)</strong></p><p>Facet aggregations cache in Redis with composite keys capturing query dimensions:</p><pre><code><code>public Map&lt;String, Long&gt; getCachedFacets(String field, Map&lt;String, String&gt; filters) {
    String cacheKey = buildFacetCacheKey(field, filters);
    Map&lt;Object, Object&gt; cached = redisTemplate.opsForHash().entries(cacheKey);
    
    if (!cached.isEmpty()) {
        return cached.entrySet().stream()
            .collect(Collectors.toMap(
                e -&gt; e.getKey().toString(),
                e -&gt; Long.parseLong(e.getValue().toString())
            ));
    }
    
    // Cache miss - compute from Elasticsearch
    Map&lt;String, Long&gt; facets = computeFacetsFromElasticsearch(field, filters);
    redisTemplate.opsForHash().putAll(cacheKey, facets);
    redisTemplate.expire(cacheKey, Duration.ofMinutes(1));
    return facets;
}
</code></code></pre><p><strong>4. Query Planning</strong></p><p>Before executing, the system estimates result set size using Elasticsearch count API and chooses execution strategy:</p><pre><code><code>public SearchStrategy chooseStrategy(SearchRequest request) {
    long estimatedMatches = elasticsearchClient.count(buildQuery(request));
    long totalDocs = elasticsearchClient.count(matchAllQuery());
    double selectivity = (double) estimatedMatches / totalDocs;
    
    // &lt;5% of docs: filter-first strategy (retrieve docs, then aggregate)
    if (selectivity &lt; 0.05) {
        return SearchStrategy.FILTER_FIRST;
    }
    // &gt;50% of docs: aggregate-first strategy (compute facets, then filter)
    else if (selectivity &gt; 0.50) {
        return SearchStrategy.AGGREGATE_FIRST;
    }
    // Medium selectivity: standard scatter-gather
    return SearchStrategy.SCATTER_GATHER;
}
</code></code></pre><h3>Working Demo Link:</h3><div id="youtube2-VqYdlEguo9I" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;VqYdlEguo9I&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/VqYdlEguo9I?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><h2>Production Considerations</h2><p><strong>Performance Optimization</strong>: Elasticsearch heap size must accommodate aggregation memory. For 100M unique facet values per shard, allocate 4GB heap minimum. Monitor <code>indices.fielddata.memory_size</code> and implement circuit breakers to prevent OOM during high-cardinality aggregations.</p><p><strong>Facet Explosion</strong>: Users creating custom tags can introduce unbounded cardinality. Implement dynamic field limits&#8212;Splunk restricts to 10,000 unique values per facet per day. Beyond that, treat as full-text searchable but not faceted.</p><p><strong>Failure Scenarios</strong>: When Elasticsearch shards become unavailable, return partial results with a &#8220;incomplete data&#8221; warning rather than failing completely. Netflix&#8217;s search UI shows &#8220;Search results from 45/50 datacenters&#8221; during partial outages, maintaining user trust through transparency.</p><p><strong>Monitoring</strong>: Track facet cache hit rates (target &gt;70%), P99 aggregation latency (target &lt;500ms), and Elasticsearch heap usage (alert above 85%). Set up alerts for abnormal cardinality growth indicating potential facet explosion attacks or bugs.</p><h2>Scale Connection: FAANG-Level Faceted Search</h2><p><strong>Datadog</strong> processes 100,000 faceted search queries per second across 1 trillion daily log events. Their distributed search cluster uses 500+ Elasticsearch nodes, each maintaining sharded time-series indexes. Facet aggregations execute in parallel across shards with results merged in &lt;200ms. They cache aggregations in a distributed Redis cluster with 100+ nodes, achieving 85% cache hit rates for common queries.</p><p><strong>Elastic Cloud</strong> powers faceted search for companies like Tinder, Slack, and Walmart. Their most demanding workload&#8212;Walmart&#8217;s inventory search&#8212;handles 50,000 queries/sec with 15+ simultaneous facets across 500 billion documents. The system uses Elasticsearch&#8217;s frozen tier to archive old indexes while maintaining query support, reducing storage costs by 90%.</p><h2>Next Steps</h2><p>Tomorrow we implement <strong>real-time indexing with minimal latency</strong>, building sub-second indexing pipelines that make logs searchable within 100ms of generation&#8212;the final piece for production-grade observability.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://sdcourse.substack.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">Hands On System Design Course - Code Everyday  is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</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[Day 54: Implement a Query Language for Complex Log Searches]]></title><description><![CDATA[Stop reading about architecture and start building it. Theory only gets you so far.]]></description><link>https://sdcourse.substack.com/p/day-54-implement-a-query-language</link><guid isPermaLink="false">https://sdcourse.substack.com/p/day-54-implement-a-query-language</guid><dc:creator><![CDATA[sdr11]]></dc:creator><pubDate>Sat, 25 Apr 2026 23:38:57 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Inn2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17783cf9-d98f-4211-ab89-ef214e0d7c87_6000x4500.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div><hr></div><p><strong>Stop reading about architecture and start building it.</strong> Theory only gets you so far. Commit to a daily coding habit where you implement distributed systems from the ground up. No abstractions, no shortcuts&#8212;just pure engineering. <strong>Start your first lesson today. </strong>Upgrade to <strong><a href="http://sdcourse.substack.com/subscribe">Lifetime Access subscription</a></strong> &amp; Get one year free subscription to our hands on <strong>course portal : &#8220;systemdrd.com&#8221;</strong> that offers wide variety of hands on courses on covering multiple high demanding technologies.</p><div><hr></div><div><hr></div><h2>What We&#8217;re Building Today </h2><p>Today we&#8217;re implementing a production-grade SQL-like query language for distributed log analytics. By the end of this lesson, you&#8217;ll have:</p><ul><li><p><strong>Query Parser &amp; Lexer</strong>: ANTLR-based parser supporting SELECT, WHERE, GROUP BY, ORDER BY, and aggregation functions</p></li><li><p><strong>Distributed Query Executor</strong>: Coordinator that pushes query execution to indexed nodes from Day 53&#8217;s distributed index</p></li><li><p><strong>Query Optimizer</strong>: Cost-based optimizer that rewrites queries to leverage existing indexes and minimize network traffic</p></li><li><p><strong>Result Aggregator</strong>: Merge-sort implementation that combines partial results from multiple nodes while maintaining memory efficiency</p></li></ul><h2>Why This Matters</h2><p>Every log analytics platform at scale needs a query interface that abstracts complexity while maintaining performance. Elasticsearch powers queries at Uber processing 10+ billion logs daily. Splunk&#8217;s Search Processing Language handles petabytes at major financial institutions. Google&#8217;s Dremel (BigQuery) executes SQL queries across distributed columnar storage.</p><p>The challenge isn&#8217;t just parsing syntax&#8212;it&#8217;s distributing execution intelligently. A naive query that scans all logs across 100 nodes will timeout. The key architectural insight: <strong>push computation to data, not data to computation</strong>. Query coordinators must rewrite queries into node-local operations, leverage distributed indexes, and aggregate results incrementally.</p><p>This lesson bridges your Day 53 distributed indexing with practical querying. Without a sophisticated query layer, your indexes are useless. Users need SQL familiarity, not custom APIs. Production query engines must handle complex predicates, joins across time windows, and real-time aggregations while maintaining sub-second latency.</p><h2>System Design Deep Dive</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Inn2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17783cf9-d98f-4211-ab89-ef214e0d7c87_6000x4500.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Inn2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17783cf9-d98f-4211-ab89-ef214e0d7c87_6000x4500.png 424w, https://substackcdn.com/image/fetch/$s_!Inn2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17783cf9-d98f-4211-ab89-ef214e0d7c87_6000x4500.png 848w, https://substackcdn.com/image/fetch/$s_!Inn2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17783cf9-d98f-4211-ab89-ef214e0d7c87_6000x4500.png 1272w, https://substackcdn.com/image/fetch/$s_!Inn2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17783cf9-d98f-4211-ab89-ef214e0d7c87_6000x4500.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Inn2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17783cf9-d98f-4211-ab89-ef214e0d7c87_6000x4500.png" width="1456" height="1092" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/17783cf9-d98f-4211-ab89-ef214e0d7c87_6000x4500.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1092,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2024529,&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://sdcourse.substack.com/i/186283619?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17783cf9-d98f-4211-ab89-ef214e0d7c87_6000x4500.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_!Inn2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17783cf9-d98f-4211-ab89-ef214e0d7c87_6000x4500.png 424w, https://substackcdn.com/image/fetch/$s_!Inn2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17783cf9-d98f-4211-ab89-ef214e0d7c87_6000x4500.png 848w, https://substackcdn.com/image/fetch/$s_!Inn2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17783cf9-d98f-4211-ab89-ef214e0d7c87_6000x4500.png 1272w, https://substackcdn.com/image/fetch/$s_!Inn2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17783cf9-d98f-4211-ab89-ef214e0d7c87_6000x4500.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>
          <a href="https://sdcourse.substack.com/p/day-54-implement-a-query-language">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 53: Distributed Indexing Across Multiple Nodes]]></title><description><![CDATA[What We&#8217;re Building Today]]></description><link>https://sdcourse.substack.com/p/day-53-distributed-indexing-across</link><guid isPermaLink="false">https://sdcourse.substack.com/p/day-53-distributed-indexing-across</guid><dc:creator><![CDATA[sdr11]]></dc:creator><pubDate>Wed, 22 Apr 2026 01:20:35 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!mciy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe024a204-749a-4d53-8463-81d91f441008_7000x4500.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>What We&#8217;re Building Today</h2><ul><li><p><strong>Partitioned search index</strong> spanning 3+ independent index nodes using consistent hashing</p></li><li><p><strong>Scatter-gather query coordinator</strong> that parallelizes searches across shards</p></li><li><p><strong>Index replication layer</strong> ensuring fault tolerance with primary/replica topology</p></li><li><p><strong>Shard routing service</strong> that maps log entries to appropriate index partitions based on tenant ID</p></li></ul><h2>Why This Matters</h2><blockquote><p>Yesterday&#8217;s inverted index hit a wall at ~500GB of log data. Single-node indexes face three critical bottlenecks: index size exceeds available RAM forcing disk swaps, write throughput caps at disk I/O limits (~10K writes/sec), and query latency degrades linearly with index growth. Elasticsearch solves this by distributing indexes across hundreds of nodes, processing 10M+ documents per second. LinkedIn&#8217;s distributed search infrastructure handles 15TB of indexed data across 200+ nodes, serving queries in &lt;50ms p99. Today we&#8217;re implementing the core pattern that powers these systems: horizontal index partitioning with coordinated scatter-gather queries.</p><p>The architectural insight: <strong>distributed indexes trade consistency for availability and partition tolerance</strong>. When you shard an index, you&#8217;re choosing AP over CA in the CAP theorem&#8212;accepting eventual consistency in exchange for horizontal scalability and fault tolerance. Understanding this trade-off is fundamental to system design at scale.</p></blockquote><h2>System Design Deep Dive</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!mciy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe024a204-749a-4d53-8463-81d91f441008_7000x4500.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!mciy!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe024a204-749a-4d53-8463-81d91f441008_7000x4500.png 424w, https://substackcdn.com/image/fetch/$s_!mciy!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe024a204-749a-4d53-8463-81d91f441008_7000x4500.png 848w, https://substackcdn.com/image/fetch/$s_!mciy!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe024a204-749a-4d53-8463-81d91f441008_7000x4500.png 1272w, https://substackcdn.com/image/fetch/$s_!mciy!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe024a204-749a-4d53-8463-81d91f441008_7000x4500.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!mciy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe024a204-749a-4d53-8463-81d91f441008_7000x4500.png" width="1456" height="936" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e024a204-749a-4d53-8463-81d91f441008_7000x4500.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:936,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2244327,&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://sdcourse.substack.com/i/186160988?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe024a204-749a-4d53-8463-81d91f441008_7000x4500.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_!mciy!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe024a204-749a-4d53-8463-81d91f441008_7000x4500.png 424w, https://substackcdn.com/image/fetch/$s_!mciy!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe024a204-749a-4d53-8463-81d91f441008_7000x4500.png 848w, https://substackcdn.com/image/fetch/$s_!mciy!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe024a204-749a-4d53-8463-81d91f441008_7000x4500.png 1272w, https://substackcdn.com/image/fetch/$s_!mciy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe024a204-749a-4d53-8463-81d91f441008_7000x4500.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>
          <a href="https://sdcourse.substack.com/p/day-53-distributed-indexing-across">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 52: Implement a Simple Inverted Index for Log Searching]]></title><description><![CDATA[Looking for Professional Growth ?]]></description><link>https://sdcourse.substack.com/p/day-52-implement-a-simple-inverted</link><guid isPermaLink="false">https://sdcourse.substack.com/p/day-52-implement-a-simple-inverted</guid><dc:creator><![CDATA[sdr11]]></dc:creator><pubDate>Sat, 18 Apr 2026 04:17:13 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!qENL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb989fd88-cb5c-4d0c-af26-3fdb81b01ad0_7000x4500.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>Looking for Professional Growth</strong> ? </p><p>The difference between a "design interview" and a "production system" is massive. Close that gap today with the <strong>Hands on</strong> <strong>Distributed Log System Building</strong> course. <strong>Get 40% off for a limited time:</strong> <a href="https://sdcourse.substack.com/fbbab0d8">https://sdcourse.substack.com/fbbab0d8</a></p><div><hr></div><h2>What We&#8217;re Building Today</h2><ul><li><p><strong>Real-time inverted index</strong> that tokenizes and indexes log messages as they arrive via Kafka</p></li><li><p><strong>Search API</strong> with relevance scoring and ranked results for natural language queries</p></li><li><p><strong>Index persistence layer</strong> using Redis for hot data and PostgreSQL for cold storage</p></li><li><p><strong>Query processing engine</strong> supporting boolean operators and phrase matching</p></li></ul><h2>Why This Matters</h2><p>Every major observability platform&#8212;Splunk, Datadog, Elastic&#8212;runs on inverted indices. When you search &#8220;ERROR user authentication failed&#8221; across billions of log entries and get results in milliseconds, you&#8217;re querying an inverted index. This data structure powers everything from application monitoring to security incident response.</p><p>Without inverted indices, log search would require scanning every log entry linearly&#8212;O(n) complexity that becomes impossible at scale. An inverted index transforms this into O(k) lookups where k is the number of query terms, enabling sub-second searches across terabytes of logs. Understanding inverted indices is fundamental to building search infrastructure that scales from thousands to trillions of documents.</p><p>Today&#8217;s implementation bridges the gap between local prototypes and production search engines, showing how the same architectural patterns scale from single-node deployments to distributed clusters processing petabytes daily.</p><h2>System Design Deep Dive</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!qENL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb989fd88-cb5c-4d0c-af26-3fdb81b01ad0_7000x4500.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qENL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb989fd88-cb5c-4d0c-af26-3fdb81b01ad0_7000x4500.png 424w, https://substackcdn.com/image/fetch/$s_!qENL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb989fd88-cb5c-4d0c-af26-3fdb81b01ad0_7000x4500.png 848w, https://substackcdn.com/image/fetch/$s_!qENL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb989fd88-cb5c-4d0c-af26-3fdb81b01ad0_7000x4500.png 1272w, https://substackcdn.com/image/fetch/$s_!qENL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb989fd88-cb5c-4d0c-af26-3fdb81b01ad0_7000x4500.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qENL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb989fd88-cb5c-4d0c-af26-3fdb81b01ad0_7000x4500.png" width="1456" height="936" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b989fd88-cb5c-4d0c-af26-3fdb81b01ad0_7000x4500.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:936,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1790170,&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://sdcourse.substack.com/i/186064300?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb989fd88-cb5c-4d0c-af26-3fdb81b01ad0_7000x4500.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_!qENL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb989fd88-cb5c-4d0c-af26-3fdb81b01ad0_7000x4500.png 424w, https://substackcdn.com/image/fetch/$s_!qENL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb989fd88-cb5c-4d0c-af26-3fdb81b01ad0_7000x4500.png 848w, https://substackcdn.com/image/fetch/$s_!qENL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb989fd88-cb5c-4d0c-af26-3fdb81b01ad0_7000x4500.png 1272w, https://substackcdn.com/image/fetch/$s_!qENL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb989fd88-cb5c-4d0c-af26-3fdb81b01ad0_7000x4500.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>
          <a href="https://sdcourse.substack.com/p/day-52-implement-a-simple-inverted">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 51: Build Dashboards for Visualizing Analytics Results]]></title><description><![CDATA[What We&#8217;re Building Today]]></description><link>https://sdcourse.substack.com/p/day-51-build-dashboards-for-visualizing</link><guid isPermaLink="false">https://sdcourse.substack.com/p/day-51-build-dashboards-for-visualizing</guid><dc:creator><![CDATA[sdr11]]></dc:creator><pubDate>Tue, 14 Apr 2026 11:30:53 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!peaU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23e2d479-515c-45c7-951d-726de6585fff_1750x1125.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>What We&#8217;re Building Today</h2><ul><li><p><strong>Real-time analytics dashboard</strong> consuming aggregated metrics from Kafka streams</p></li><li><p><strong>WebSocket-based push architecture</strong> delivering sub-second metric updates to browsers</p></li><li><p><strong>Multi-dimensional visualization service</strong> supporting time-series, histograms, and geographic heatmaps</p></li><li><p><strong>Query optimization layer</strong> with Redis caching and PostgreSQL time-series partitioning</p></li></ul><h2>Why This Matters</h2><blockquote><p>At scale, the gap between generating metrics and making them actionable determines your incident response time. Netflix processes 500 billion events daily, but their dashboard systems compress this into 200ms query responses because engineers can&#8217;t wait 30 seconds to see if a deployment broke something. When Uber&#8217;s surge pricing algorithms trigger, dashboard systems must surface the decision rationale within 100ms or drivers can&#8217;t understand why rates changed.</p><p>The architectural challenge isn&#8217;t building charts&#8212;it&#8217;s designing systems that maintain query responsiveness as data volume grows exponentially. Your dashboard becomes the bottleneck between detecting problems and fixing them. Poor dashboard architecture means your monitoring system generates alerts 5 minutes before your engineers can see the underlying data.</p></blockquote><h2>System Design Deep Dive</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!peaU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23e2d479-515c-45c7-951d-726de6585fff_1750x1125.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!peaU!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23e2d479-515c-45c7-951d-726de6585fff_1750x1125.png 424w, https://substackcdn.com/image/fetch/$s_!peaU!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23e2d479-515c-45c7-951d-726de6585fff_1750x1125.png 848w, https://substackcdn.com/image/fetch/$s_!peaU!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23e2d479-515c-45c7-951d-726de6585fff_1750x1125.png 1272w, https://substackcdn.com/image/fetch/$s_!peaU!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23e2d479-515c-45c7-951d-726de6585fff_1750x1125.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!peaU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23e2d479-515c-45c7-951d-726de6585fff_1750x1125.png" width="1456" height="936" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/23e2d479-515c-45c7-951d-726de6585fff_1750x1125.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:936,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:308021,&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://sdcourse.substack.com/i/185948798?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23e2d479-515c-45c7-951d-726de6585fff_1750x1125.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_!peaU!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23e2d479-515c-45c7-951d-726de6585fff_1750x1125.png 424w, https://substackcdn.com/image/fetch/$s_!peaU!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23e2d479-515c-45c7-951d-726de6585fff_1750x1125.png 848w, https://substackcdn.com/image/fetch/$s_!peaU!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23e2d479-515c-45c7-951d-726de6585fff_1750x1125.png 1272w, https://substackcdn.com/image/fetch/$s_!peaU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23e2d479-515c-45c7-951d-726de6585fff_1750x1125.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>
          <a href="https://sdcourse.substack.com/p/day-51-build-dashboards-for-visualizing">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 50: Alert Generation Based on Log Patterns]]></title><description><![CDATA[Upgrade to get one month free subscription to our hands on course systemdrd.com that offer wide variety of hands on courses on covering various technologies.]]></description><link>https://sdcourse.substack.com/p/day-50-alert-generation-based-on</link><guid isPermaLink="false">https://sdcourse.substack.com/p/day-50-alert-generation-based-on</guid><dc:creator><![CDATA[sdr11]]></dc:creator><pubDate>Fri, 10 Apr 2026 04:30:54 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Ixe-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3e064ae-4540-4492-a0e2-d7b71e822091_1750x1125.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a href="https://sdcourse.substack.com/subscribe">Upgrade</a> to get one month free subscription to our hands on <strong>course <a href="http://systemdrd.com">systemdrd.com</a></strong> that offer wide variety of hands on courses on covering various technologies.</p><p>Subscribe to our portal for <strong><a href="http://systemdrd.com">systemdrd.com</a> </strong>&amp; get <strong>lifetime access</strong> to &#8220;<strong>Hands On System Design</strong> with &#8220;Distributed Systems Implementation with <strong>python and javascript</strong>&#8221; and this &#8220;Distributed Log Implementation With <strong>Java &amp; Spring Boot</strong>&#8221;</p><div><hr></div><h2>What We&#8217;re Building Today</h2><blockquote><p>A production-grade distributed alerting system that monitors log patterns in real-time and triggers intelligent notifications:</p></blockquote><ul><li><p><strong>Real-time alert rule engine</strong> processing 50,000+ events/second with Kafka Streams</p></li><li><p><strong>Smart alert manager</strong> with deduplication, correlation, and escalation logic</p></li><li><p><strong>Multi-channel notification service</strong> supporting email, Slack, and PagerDuty integration</p></li><li><p><strong>Alert configuration API</strong> for dynamic rule management without system restarts</p></li></ul><h2>Why This Matters</h2><blockquote><p>Alert generation is where distributed log processing transitions from passive observation to active operational response. At scale, naive alerting becomes your biggest operational burden&#8212;Netflix processes 2 billion alerts daily but only acts on 0.01% of them. The challenge isn&#8217;t detecting problems; it&#8217;s preventing alert fatigue while ensuring critical issues never slip through.</p><p>Poor alerting architectures create alert storms during outages (compounding incident response), suffer from flapping alerts that erode trust, generate excessive false positives that train teams to ignore notifications, and fail during the very incidents they&#8217;re designed to detect. Production alerting requires sophisticated state management, intelligent suppression, and fault-tolerant delivery mechanisms that work when your primary systems are degraded.</p></blockquote><h2>System Design Deep Dive</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Ixe-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3e064ae-4540-4492-a0e2-d7b71e822091_1750x1125.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Ixe-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3e064ae-4540-4492-a0e2-d7b71e822091_1750x1125.png 424w, https://substackcdn.com/image/fetch/$s_!Ixe-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3e064ae-4540-4492-a0e2-d7b71e822091_1750x1125.png 848w, https://substackcdn.com/image/fetch/$s_!Ixe-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3e064ae-4540-4492-a0e2-d7b71e822091_1750x1125.png 1272w, https://substackcdn.com/image/fetch/$s_!Ixe-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3e064ae-4540-4492-a0e2-d7b71e822091_1750x1125.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Ixe-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3e064ae-4540-4492-a0e2-d7b71e822091_1750x1125.png" width="1456" height="936" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e3e064ae-4540-4492-a0e2-d7b71e822091_1750x1125.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:936,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:503374,&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://sdcourse.substack.com/i/185949000?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3e064ae-4540-4492-a0e2-d7b71e822091_1750x1125.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_!Ixe-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3e064ae-4540-4492-a0e2-d7b71e822091_1750x1125.png 424w, https://substackcdn.com/image/fetch/$s_!Ixe-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3e064ae-4540-4492-a0e2-d7b71e822091_1750x1125.png 848w, https://substackcdn.com/image/fetch/$s_!Ixe-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3e064ae-4540-4492-a0e2-d7b71e822091_1750x1125.png 1272w, https://substackcdn.com/image/fetch/$s_!Ixe-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3e064ae-4540-4492-a0e2-d7b71e822091_1750x1125.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><h3>Pattern 1: Stateful Stream Processing for Alert Evaluation</h3>
      <p>
          <a href="https://sdcourse.substack.com/p/day-50-alert-generation-based-on">
              Read more
          </a>
      </p>
   ]]></content:encoded></item></channel></rss>