<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Gaurav Sharma</title>
    <description>The latest articles on DEV Community by Gaurav Sharma (@gaurav_sharma_c2ef5dd7646).</description>
    <link>https://dev.to/gaurav_sharma_c2ef5dd7646</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2057038%2F363a6933-a83d-4a8a-af41-8fe5e4d9dbf0.jpg</url>
      <title>DEV Community: Gaurav Sharma</title>
      <link>https://dev.to/gaurav_sharma_c2ef5dd7646</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gaurav_sharma_c2ef5dd7646"/>
    <language>en</language>
    <item>
      <title>System Design: A popular cache key expires and 40,000 requests hit your database. How do you fix it?</title>
      <dc:creator>Gaurav Sharma</dc:creator>
      <pubDate>Wed, 12 Aug 2026 19:49:37 +0000</pubDate>
      <link>https://dev.to/gaurav_sharma_c2ef5dd7646/system-design-a-popular-cache-key-expires-and-40000-requests-hit-your-database-how-do-you-fix-it-i3l</link>
      <guid>https://dev.to/gaurav_sharma_c2ef5dd7646/system-design-a-popular-cache-key-expires-and-40000-requests-hit-your-database-how-do-you-fix-it-i3l</guid>
      <description>&lt;p&gt;You are in a Staff Engineer system design interview. The interviewer draws a simple architecture on the whiteboard: an API, a Redis cache, and a Postgres database. &lt;/p&gt;

&lt;p&gt;Then they drop the scenario:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"A highly popular key reaches its TTL (Time-To-Live) and expires. In the exact same second, 40,000 requests arrive looking for that key. What happens, and what do you change to prevent the database from melting?"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Most engineers immediately start talking about scaling the database or adding read replicas. &lt;strong&gt;But if you say that, you've missed the hidden signal the interviewer is actually scoring you on.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here is exactly how a Staff Engineer tackles the &lt;strong&gt;Cache Stampede&lt;/strong&gt; (also known as a Thundering Herd) problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Do the arithmetic before you name a fix
&lt;/h2&gt;

&lt;p&gt;Take the premise at 40,000 requests a second and assume building the cache value takes &lt;strong&gt;200 milliseconds&lt;/strong&gt; (a complex join or calculation). &lt;/p&gt;

&lt;p&gt;Every single request that arrives while the rebuild is in-flight will register as a cache miss, because nothing has been written back to Redis yet. That is &lt;strong&gt;8,000 requests in the 200ms gap&lt;/strong&gt;, and every one of them starts its own copy of the exact same query against the database. &lt;/p&gt;

&lt;p&gt;The database is not serving 8,000 different questions. It is serving &lt;em&gt;one&lt;/em&gt; question 8,000 times.&lt;/p&gt;

&lt;p&gt;State that number out loud in an interview. It changes the shape of the answer, because it shows the problem is &lt;strong&gt;duplication rather than volume&lt;/strong&gt;. You do not need a bigger database; you need 7,999 of those requests to stop asking.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Note: The same arithmetic tells you when this is not worth solving. If the rebuild takes 2 milliseconds, the gap holds 80 requests. 80 duplicate queries is a spike your database won't even notice. Cache stampede is a function of rebuild latency, not popularity alone).&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. The Fix: Serialise or serve stale
&lt;/h2&gt;

&lt;p&gt;There are two families of fixes, and the choice between them is a product decision rather than a technical one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option A: Single-flight (Serialise)
&lt;/h3&gt;

&lt;p&gt;The first request to miss takes a short-lived lock on the key in Redis, does the DB query, writes the value, and releases the lock. Every other request finds the lock held and waits, then reads the freshly-written value. &lt;/p&gt;

&lt;p&gt;In Redis, this looks like &lt;code&gt;SET key:lock token NX EX 5&lt;/code&gt; (create only if absent, expire after 5 seconds). &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Trade-off:&lt;/strong&gt; Everybody gets fresh data, but everyone also pays the full rebuild latency. Your p99 latency for that second spikes to 200 milliseconds.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Option B: Stale-while-revalidate
&lt;/h3&gt;

&lt;p&gt;Store the value with its own logical "freshness" time and keep it in the cache past that point. A reader arriving past the freshness time returns the old bytes immediately to the user, but triggers an asynchronous refresh in the background. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Trade-off:&lt;/strong&gt; Latency stays completely flat for everyone, but readers see data up to one rebuild cycle (200ms) old.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Say which you are choosing and why: &lt;em&gt;"This is a product listing, so I serve stale for 200 milliseconds; but if this were an account balance, I’d use the lock."&lt;/em&gt; That single sentence does more for you in an interview than reciting every technique in existence.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The stampede you cause next week
&lt;/h2&gt;

&lt;p&gt;Fixing the rebuild doesn't fix the pattern that produced it. If every key is written with the exact same lifetime by the same warm-up job, they all expire together. The expiry itself becomes a synchronised event. &lt;/p&gt;

&lt;p&gt;You must add &lt;strong&gt;jitter&lt;/strong&gt; at write time so the herd disperses.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;

&lt;span class="c1"&gt;# A nominal five-minute life, spread over the last 10 per cent of it.
# Ten thousand keys written together will no longer expire together.
&lt;/span&gt;&lt;span class="n"&gt;BASE_TTL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;
&lt;span class="n"&gt;ttl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BASE_TTL&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BASE_TTL&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ttl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. What happens when the lock fails?
&lt;/h2&gt;

&lt;p&gt;The single-flight lock answer is only complete if you explain what happens when the rebuilding request dies. &lt;/p&gt;

&lt;p&gt;Suppose the single request holding the lock times out against the database. The lock is still held in Redis until its own TTL expires. Every waiter is blocked on a value that is never coming. If they wait naively, &lt;strong&gt;you've converted a stampede into a stall&lt;/strong&gt;, which is harder to diagnose because the database looks perfectly healthy!&lt;/p&gt;

&lt;p&gt;To survive this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The lock must carry a short expiry so it cannot outlive a dead holder.&lt;/li&gt;
&lt;li&gt;Waiters must have their own deadline, shorter than the lock's, after which they return an error rather than waiting indefinitely. &lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Know the Rubric. Pass the Interview.
&lt;/h2&gt;

&lt;p&gt;This is just one of over &lt;strong&gt;900 highly-detailed technical scenarios&lt;/strong&gt; we've built at &lt;a href="https://preptima.com" rel="noopener noreferrer"&gt;Preptima&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Most interview platforms just give you a model answer. Preptima gives you the &lt;strong&gt;hidden grading rubrics&lt;/strong&gt; that Staff and Principal engineers actually use to score you. &lt;/p&gt;

&lt;p&gt;If you are preparing for a backend, data, or system design interview, stop guessing what the interviewer wants. &lt;a href="https://preptima.com" rel="noopener noreferrer"&gt;Check out the full Preptima curriculum here&lt;/a&gt; and get the scorecard.&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>architecture</category>
      <category>redis</category>
      <category>backend</category>
    </item>
    <item>
      <title>Designing a Practical IIoT Architecture</title>
      <dc:creator>Gaurav Sharma</dc:creator>
      <pubDate>Tue, 31 Mar 2026 16:25:27 +0000</pubDate>
      <link>https://dev.to/gaurav_sharma_c2ef5dd7646/designing-a-practical-iiot-architecture-1cnn</link>
      <guid>https://dev.to/gaurav_sharma_c2ef5dd7646/designing-a-practical-iiot-architecture-1cnn</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Industrial IoT (IIoT) architectures often look clean in diagrams but become messy when implemented in real systems.&lt;/p&gt;

&lt;p&gt;While exploring this space, I tried to structure a more practical reference architecture that balances clarity with real-world concerns like scalability, reliability, and multi-tenancy.&lt;/p&gt;

&lt;p&gt;This is a work in progress, and I’d love feedback from others building similar systems.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem with Typical IoT Architectures
&lt;/h2&gt;

&lt;p&gt;Most reference architectures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;stay too high-level&lt;/li&gt;
&lt;li&gt;don’t separate concerns clearly (telemetry vs command)&lt;/li&gt;
&lt;li&gt;ignore multi-tenancy&lt;/li&gt;
&lt;li&gt;don’t address edge vs cloud trade-offs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This creates challenges when moving from POC → production.&lt;/p&gt;




&lt;h2&gt;
  
  
  Proposed Architecture Overview
&lt;/h2&gt;

&lt;p&gt;At a high level, the system is divided into four layers:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr71vwgg0lymy86gyx7qp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr71vwgg0lymy86gyx7qp.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Device &amp;amp; Controller Layer
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Sensors, controllers, PLCs&lt;/li&gt;
&lt;li&gt;Communicate via MQTT or similar lightweight protocols&lt;/li&gt;
&lt;li&gt;Separate channels for telemetry and command&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  2. Edge Layer
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Local processing and filtering&lt;/li&gt;
&lt;li&gt;Handles intermittent connectivity&lt;/li&gt;
&lt;li&gt;Reduces latency for critical operations&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  3. Cloud Ingestion Layer
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;MQTT broker → event streaming pipeline&lt;/li&gt;
&lt;li&gt;Separation of:

&lt;ul&gt;
&lt;li&gt;telemetry (data ingestion)&lt;/li&gt;
&lt;li&gt;command (control path)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  4. Application Layer
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Multi-tenant SaaS architecture&lt;/li&gt;
&lt;li&gt;Monitoring dashboards&lt;/li&gt;
&lt;li&gt;Command and control APIs&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Key Design Considerations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Telemetry vs Command Separation
&lt;/h3&gt;

&lt;p&gt;Combining both leads to complexity. Keeping them separate improves scalability and clarity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Edge vs Cloud Responsibilities
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Edge: real-time, low-latency decisions
&lt;/li&gt;
&lt;li&gt;Cloud: aggregation, analytics, orchestration
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Multi-Tenancy
&lt;/h3&gt;

&lt;p&gt;Needs to be built-in from the start (not bolted on later).&lt;/p&gt;




&lt;h2&gt;
  
  
  Open Questions / Trade-offs
&lt;/h2&gt;

&lt;p&gt;Some areas I’m still exploring:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to design reliable command execution (ACK/NACK, retries, idempotency)&lt;/li&gt;
&lt;li&gt;Where to draw the boundary between edge and cloud&lt;/li&gt;
&lt;li&gt;Best approaches for tenant isolation at scale&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;p&gt;I’ve put together a more detailed version (with diagrams) here:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://gauravs19.github.io/iiot-reference-architecture/" rel="noopener noreferrer"&gt;https://gauravs19.github.io/iiot-reference-architecture/&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Looking for Feedback
&lt;/h2&gt;

&lt;p&gt;If you’ve worked on IoT/IIoT systems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What patterns have worked well for you?&lt;/li&gt;
&lt;li&gt;Where do architectures typically break?&lt;/li&gt;
&lt;li&gt;What would you change here?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Open to suggestions and alternative approaches.&lt;/p&gt;

</description>
      <category>iot</category>
      <category>architecture</category>
      <category>systemdesign</category>
      <category>cloud</category>
    </item>
  </channel>
</rss>
