By Mehraj H.
Every time you visit a webpage, Chrome quietly runs a check — is this URL malicious?
It doesn't call a server. It doesn't scan a massive database. It uses a Bloom filter. And it gets an answer in microseconds. That's the magic of this data structure. Small. Fast. Brilliant. So what exactly is a Bloom filter?
It's a probabilistic data structure — a fancy way of saying it trades a small chance of being wrong for massive gains in speed and memory. Here's how it works: you have a bit array (just a row of 0s and 1s) and a few hash functions. When you add an item, the hash functions each point to a position in the array and flip those bits to 1. When you query for an item, you check those same positions. All 1s? Probably in the set. Even one 0? Definitely not in the set.
That "definitely not" is the superpower. Why does that matter? Imagine you're Cassandra or HBase, and someone queries for a key that doesn't exist. Without a Bloom filter, you'd do a full disk read — expensive, slow. With one, you check in memory first. If it says "definitely not here," you skip the disk entirely. Gone. Saved.
Medium uses Bloom filters to avoid recommending articles you've already read. Akamai uses them to decide whether a URL is worth caching. Redis has them built in. One data structure, sitting quietly behind some of the biggest systems in the world.
The honest trade-off: Bloom filters can give false positives — they might say "probably yes" when the answer is actually no. But they never give false negatives. If it says no, trust it completely. And the memory savings? For 1 million items, a HashSet needs ~100MB. A Bloom filter? Around 1MB. Same job. 100x less memory. When should you actually use one?
When you need to check membership at scale, can tolerate rare false positives, and can't afford the cost of always hitting disk or a remote database. Spell checkers, fraud detection, network routers, CDN caches — the use cases are everywhere once you start looking.
It's not a replacement for a database. It's the bouncer at the door that turns away the obvious misses before they waste anyone's time. One bit array. A few hash functions. Millions of expensive lookups saved every second. Not bad for a 1970 invention.
#SystemDesign #BloomFilter #DataStructures #SoftwareEngineering #BackendDevelopment #DistributedSystems #DatabaseOptimization #WebPerformance #Programming #TechLeadership #ComputerScience #SoftwareArchitecture
By Mehraj H.
"There are only two hard things in computer science: cache invalidation and naming things." — Phil Karlton
I used to laugh at this quote. Then I spent a week debugging why our users were seeing prices from 3 hours ago. I stopped laughing. Here's what nobody tells you about caching: the moment you add one, you stop having one source of truth. You now have two—your database and your cache. And keeping them in sync? That's the real job. Why is it so genuinely hard? It's not a single problem. It's a cluster of problems wearing a trench coat. Data changes in unpredictable ways. A user updates their profile. An inventory item sells out. A price gets revised. Your cache doesn't know any of this happened — it just happily keeps serving the old value, convinced it's being helpful. Then there's timing. Even when you do invalidate the cache, there's a window — however small — where stale data leaks through. In distributed systems with dozens of nodes, that window multiplies. And then the classic trap hits: you delete a cache entry right as another process is reading it, a third process is writing to the DB, and a fourth is about to repopulate the cache with the old value. Welcome to race conditions. The strategies engineers actually use: → TTL (Time-to-Live): Set an expiry. Simple, predictable. But you're accepting "stale for up to X minutes" as a business decision, not just a tech one. → Write-through: Update cache and DB together on every write. Consistent, but adds latency to your writes. → Write-behind (write-back): Update cache first, sync to DB asynchronously. Fast writes are risky—if the cache dies before the sync, you lose data. → Event-driven invalidation: Publish a change event whenever data updates; subscribers invalidate the relevant cache keys. Elegant at scale, complex to implement correctly. The lesson I keep coming back to: Caching is never just a performance decision. It's a consistency decision. Every cache entry is a bet that the data won't change before the TTL expires — or that you'll catch it when it does. The engineers who get burned by cache bugs aren't the ones who don't understand caching. They're the ones who underestimated how many moving parts stand between "data changed in the DB" and "cache reflects that change." Phil Karlton said it in the 90s. Thirty years of distributed systems later, it's still true. If you're building anything at scale, treat cache invalidation with the same seriousness you'd give schema migrations or API versioning. It deserves it.
By Mehraj H.
Why the Load Balancer is Dead in Modern Cloud-Native Architectures
The traditional Load Balancer has served us well for over two decades. But in 2026, for microservices and cloud-native applications, it is rapidly becoming obsolete.
Here’s why smart engineering teams are moving away from classic load balancers and adopting Service Mesh instead.
The Evolution of Scaling
Fifteen years ago, when traffic grew, we added more servers behind a Load Balancer. It worked perfectly — round-robin, least connections, health checks, done.
But today’s applications are no longer monolithic. We now run hundreds of microservices, each with multiple instances, across multiple clusters and regions.
Suddenly, the Load Balancer becomes a bottleneck and a point of complexity.
Limitations of Traditional Load Balancers
- Acts as an extra network hop
- Limited visibility into service-to-service communication
- Difficult to implement advanced traffic routing (canary, blue-green, A/B testing)
- Security (mTLS) and observability become fragmented
- Service discovery has to be handled separately
In short, Load Balancers were designed for north-south traffic. They were never built for the massive east-west traffic that dominates modern distributed systems.
Enter Service Mesh — The New Standard
A Service Mesh is a dedicated infrastructure layer that handles service-to-service communication.
Instead of one centralized load balancer, every service gets a lightweight sidecar proxy (usually Envoy). This sidecar becomes the control plane for all networking logic.
What Service Mesh actually does:
- Intelligent Load Balancing
- Automatic mTLS encryption
- Advanced Traffic Management (Canary, Circuit Breaking, Retry, Timeout)
- Golden Metrics & Distributed Tracing (out of the box)
- Service Discovery
- Fault Injection & Chaos Engineering
- Fine-grained observability
All of this happens without changing a single line of application code.
Popular Service Mesh tools in 2026:
- Istio (most popular)
- Linkerd
- Cilium Service Mesh
- Consul
Real-World Impact
Teams using Service Mesh report:
- 40-60% reduction in networking-related incidents
- Much faster deployment cycles
- Significantly better observability
- Standardized security across all services
The Future is Mesh-Native
Load Balancers are not completely dead — they still make sense at the edge (ingress) for global traffic routing. But inside your cluster, for service communication, Service Mesh has already won.
The question is no longer “Should we use a Service Mesh?”
The question is “Which Service Mesh should we adopt and when?”
If you’re still managing microservices with traditional load balancers, API gateways, and separate monitoring tools, you’re carrying unnecessary operational complexity.
By Mehraj H.
I spent a lot of time confused by this topic. "Eventual consistency", "linearizability", "causal consistency" — every article threw around these terms like I was supposed to already know what they meant. So I went deep, took notes, and here's the clearest breakdown I could write.
First, what even is a Consistency Model?
Think of it as a formal contract between your distributed system and anyone building on top of it. It answers one question: given everything written to the data so far, which values can a read operation legally return?
In distributed systems, data lives on multiple replicas for availability and fault tolerance. But the moment you replicate data, you introduce a problem — updating every replica instantly is physically impossible due to network latency, partitions, and failures. Consistency models exist to manage that trade-off.
The Spectrum (from strongest to weakest)
Consistency isn't a binary switch. It's a spectrum, and where you sit on it determines your performance, availability, and latency characteristics.
Strongest → Linearizability
Sequential Consistency
Strict Serializability
Causal Consistency
PRAM / FIFO Consistency
Weakest → Eventual Consistency
Every step down the spectrum costs you some guarantee. Every step up costs you performance.
Linearizability — The Gold Standard
This is the strongest single-operation model. The entire system behaves as if there's only one copy of the data, and every operation happens atomically in real time.
If operation A completes before operation B starts, every single client will see A before B. No exceptions. It's the closest thing a distributed system can get to running on a single machine.
Where it shines: bank balances, distributed locks, leader election, payment processing.
Where it hurts: high latency, reduced availability during network partitions, lower throughput. You wouldn't use this for a social media like counter — that's overkill.
Eventual Consistency — The Pragmatist's Choice
At the other end: if no new writes happen, all replicas will eventually agree on the same value. The catch? "Eventually" has no time bound. It could be milliseconds. It could be hours.
What you gain: blazing fast writes, massive scalability, high availability.
What you lose: you might read stale data, operations have no ordering guarantees.
Conflict resolution strategies matter here — Last-Write-Wins, Vector Clocks, and CRDTs (Conflict-free Replicated Data Types) are the main tools for deciding what happens when two replicas disagree.
Where it shines: DNS, CDNs, social media likes, view counts, recommendations.
Where it fails hard: inventory systems, banking, payments. Overselling or double-spending are real risks here.
Causal Consistency — The Sweet Spot
This one is underrated.
The idea: if event A causes event B, then anyone who sees B must have already seen A. Causally unrelated operations can appear in any order — that's fine.
The classic violation scenario: Alice posts something. Bob replies to it. Carol sees Bob's reply but not Alice's original post. That's confusing and wrong. Causal consistency prevents exactly this.
Where it shines: social feeds, comment threads, collaborative editing (think Google Docs), chat apps.
Many modern applications use a blend of eventual + causal consistency — you get most of the performance of eventual with just enough ordering to make sense to users.
Client-Centric Models — Often Overlooked
These don't give system-wide guarantees. They focus on making a single user's experience coherent:
These are cheap to implement relative to strong consistency, and they eliminate some of the worst UX bugs in distributed systems.
How to Choose the Right Model
Ask yourself three questions:
A real e-commerce system doesn't use one consistency model. It uses several:
| Data | Model |
|---|---|
| Inventory & payments | Linearizable / Strict Serializable |
| Product descriptions & pricing | Eventual |
| Comments & reviews | Causal |
| Recommendations & likes | Eventual |
DynamoDB, Cassandra, MongoDB, and Spanner all support per-operation tunable consistency for exactly this reason. You don't pick a model — you pick the right model for each piece of data.
The Key Takeaway
Always choose the weakest model that still satisfies your requirements — not the strongest one you can justify. Strong consistency is expensive. If your use case can tolerate eventual consistency, use it. If it needs causality but not real-time ordering, use causal. Reserve linearizability for what genuinely needs it.
Real systems are almost always mixed. The goal isn't purity — it's correctness where it matters and speed everywhere else.