Redis vs Memcached: Architecture and Use Cases
An in-depth look at Redis and Memcached, comparing their architectures, data types, persistence models, and ideal use cases.
Search for a command to run...
An in-depth look at Redis and Memcached, comparing their architectures, data types, persistence models, and ideal use cases.
No comments yet. Be the first to comment.
Applying Domain-Driven Design (DDD) principles to define microservice boundaries and create a more coherent architecture.
A comparison of Blue-Green and Canary deployment strategies for releasing new code with minimal risk and downtime.
An overview of Global Server Load Balancing (GSLB) techniques, using DNS to route traffic across multiple data centers.
Using the Bulkhead pattern to isolate elements of a system into pools so that if one fails, the others will continue to function.
An overview of auto-scaling principles, including metric-based and schedule-based scaling, to dynamically adjust capacity.
Tech Unfolded
94 posts
It was the kind of meeting every engineer dreads. The graphs on the projector screen all pointed up and to the right: user growth, requests per minute, revenue. But one graph, database CPU utilization, was hugging the 90% ceiling, and another, p99 response time, was starting a slow, ominous climb. We were a victim of our own success. The monolith that had served us so well was groaning under the strain of a thousand concurrent read queries to the same handful of popular product tables.
"We need a cache," our newest senior engineer announced, with the confidence of someone who had just discovered fire. "Let's put Memcached in front of the product service. It's simple, it's screaming fast, and it will take the load off the database."
He wasn't wrong. It sounded logical. It was the textbook answer from a dozen blog posts. So, we did it. We spent a sprint instrumenting our code, deploying a Memcached cluster, and carefully populating it. The graphs immediately improved. The database breathed a sigh of relief. We celebrated our quick win.
The celebration lasted three months. Then came the new feature request: "display real-time inventory counts on the product page." Suddenly, our simple, opaque blob of cached product data was a liability. We needed to atomically decrement a value inside that blob. Then came the request for "recently viewed items," which required appending to a list for each user. Our application code became a horrifying mess of get, deserialize, modify, serialize, cas (check-and-set) operations, riddled with race conditions and complexity. We had solved a performance problem by creating a much deeper architectural one.
This experience taught me a hard lesson that has formed the bedrock of my approach to system design. The choice between tools like Redis and Memcached is not a simple evaluation of performance benchmarks. It is a fundamental decision about whether you are caching inert data or building a platform for stateful application logic. Treating Redis as just a "better Memcached" is a category error that leads to bloated, complex, and fragile systems. The most elegant solution is not the one with the most features; it is the one that correctly models the problem you are actually trying to solve.
On the surface, Redis and Memcached seem to occupy the same niche. They are both in-memory, key-value stores used to accelerate applications. This is where the similarity ends. Digging into their core architectures reveals two fundamentally different philosophies. Understanding this difference is the key to avoiding the trap my team fell into.
Memcached is a pure cache. It was designed with one job in mind: to be a blazingly fast, distributed, in-memory bucket for strings and objects. Its architecture is a masterclass in purpose-built simplicity.
This diagram illustrates the core architectural pattern of Memcached. Incoming client requests are handled by a listener thread, which then dispatches the work to one of many worker threads. These threads perform the simple GET, SET, and DELETE operations directly on a shared memory space managed by a slab allocator. This multi-threaded design allows Memcached to scale vertically on multi-core machines, efficiently handling many concurrent, simple requests. The key takeaway is its shared-nothing-per-request nature; each operation is independent.
Redis, on the other hand, is architected as an in-memory data structure server. This is a crucial distinction. It's not just a key-value store; it's a server that provides structured data types (Lists, Hashes, Sets, etc.) and a rich command set to manipulate them.
This diagram reveals a completely different model. All client commands are funneled into a single queue and processed sequentially by a single-threaded event loop. While this might sound like a bottleneck, it's actually Redis's superpower. Because all operations are serialized through this single thread, every command is atomic by default. There is no need for locks or fear of race conditions when you execute a command like INCR (increment a number) or LPUSH (add an element to a list). This design intentionally trades raw multi-core scaling for simple operations in favor of predictable, atomic execution of complex ones.
My favorite analogy for this is to think of a high-performance pit crew. Memcached is the tire gun. It does one job (changing lug nuts) with incredible speed and efficiency. You can add more tire guns and more crew members to change all four tires faster. It is specialized and optimized for a single, parallelizable task.
Redis, however, is the crew chief with the master playbook. The crew chief doesn't just change tires. They direct the entire, complex, sequential operation: jack up the car, change tires, refuel, adjust the wing, clean the visor, and send the car out. Each step must happen in order, and the entire sequence is an atomic "pit stop" operation. You don't get faster by having four crew chiefs yelling different instructions at once. You get faster by making each step in the sequence as efficient as possible, which is exactly what Redis's C implementation does.
This fundamental difference in architecture has profound implications, which are often lost in simple feature-list comparisons.
| Feature | Memcached | Redis | Architectural Implication |
| Core Architecture | Multi-threaded I/O per request | Single-threaded event loop | Memcached scales with cores for many simple, concurrent GET/SETs. Redis scales horizontally with more instances, avoiding lock contention on complex, multi-key operations and ensuring atomicity. |
| Data Model | Simple Strings (up to 1MB) | Rich Data Structures (Strings, Lists, Hashes, Sets, Sorted Sets, Streams, HyperLogLogs) | Memcached forces all data manipulation logic onto the client application. This increases network round trips, code complexity, and the potential for race conditions. Redis moves this logic to the server, simplifying client code and guaranteeing atomicity. |
| Persistence | None (Purely volatile) | RDB (Point-in-time snapshots) & AOF (Append-only log of writes) | Memcached is a pure cache; data loss on restart is expected and must be handled by the application. Redis can function as a "warm" cache or even a primary, fast-access database for certain workloads, simplifying cold-start scenarios. |
| Replication & HA | None natively (Client-side sharding) | Built-in Primary-Replica Replication & Sentinel/Cluster for HA | High availability for Memcached requires significant client-side logic or third-party proxies. Redis provides robust, out-of-the-box solutions for read scaling and automatic failover, reducing operational burden. |
| Extensibility | None | Lua Scripting, Redis Modules | Redis is a platform. You can build new, atomic server-side commands using Lua or create high-performance extensions with Modules. Memcached is a fixed-function appliance. |
The mistake my team made was choosing the tire gun when what we really needed was the crew chief. We needed to perform a complex, stateful operation (decrement inventory), but we had chosen a tool designed for simple, stateless retrieval. The result was a tangled mess in our application code trying to replicate the coordinated, atomic behavior that Redis provides for free.
The path to enlightenment is not about crowning one tool as the victor. It is about developing the architectural wisdom to diagnose the true "job-to-be-done" for your data. I now guide teams using a principle-based blueprint rather than a feature checklist.
Principle 1: Cache Opaque Blobs, Not Living Data
Use Memcached when your data fits the "opaque blob" model. This is data that you generate once through an expensive process and then serve many times without modification.
SETs the value and GETs the value. That's the entire contract.SETs the result in Memcached with the URL as the key, and sets a reasonable TTL. Subsequent requests are served in microseconds, and the backend systems are shielded.Principle 2: Move Computation to the Data
Use Redis when your "cache" is an active participant in your application's logic. If you find yourself fetching data, modifying it in your application, and writing it back, you are fighting your tools. You are moving data to the computation, which is inefficient and error-prone. The Redis way is to move the computation to the data.
ZADD leaderboard_2024 1500 player_xyz. The server handles the complexity of inserting the score and re-ranking the entire set. Doing this with Memcached would require fetching the entire leaderboard, updating it, and writing it back, a classic race condition nightmare.INCR on a key like ratelimit:user_id:timestamp combined with a TTL gives you a perfect sliding window counter. It is atomic, fast, and requires minimal client-side logic.LPUSH (add to queue) and BRPOP (blocking pop from queue) commands. Your worker processes can listen efficiently without hammering the server in a busy-wait loop.HSET session:abc cart_items 5 command, rather than fetching, deserializing, updating, serializing, and writing back the entire session object.This decision-making process can be codified into a simple flow.
This decision flow guides you away from a simple "which is faster" question to the more critical architectural questions. It forces you to define the data's role: is it a passive blob or an active component? Does it need to survive a server restart? Is it a single value or part of a larger structure? Answering these questions makes the choice obvious.
As with any popular technology, a mythology has grown around these tools. Navigating it requires a healthy dose of skepticism.
GET requests for small keys, a multi-threaded Memcached on a 64-core machine will likely show higher throughput than a single Redis instance. But no real-world workload looks like that. The moment you need an atomic INCR or a ZADD, Redis's single-threaded, lock-free model often pulls ahead in terms of predictable latency because it avoids the overhead of locking and context switching that a multi-threaded system would need for such operations.get-and-set. Then you need atomicity, so you use cas. Then you need to manage lists, so you build a complex serialization format and locking mechanism in your application. Before you know it, you have spent six months building a buggy, slow, and unmaintainable version of Redis inside your own service. You are paying the complexity tax without any of the benefits of a purpose-built, battle-tested tool.The choice between Redis and Memcached is a microcosm of a larger architectural philosophy. Do you push complexity into your application layer, or do you leverage specialized, purpose-built infrastructure?
Your core argument should be this: Memcached is a tactical optimization. Redis is a strategic platform. You use Memcached to solve a localized performance bottleneck. You adopt Redis to build a foundation for new, stateful, real-time features that would be too complex or slow to build directly on your primary database.
Seeing them in this light changes the entire conversation. It's no longer about replacing one with the other. A mature architecture might use both. Memcached could be caching fully rendered pages for anonymous users, while Redis powers the real-time comment system and logged-in user session data on that very same page. They are not competitors; they are different tools for different jobs.
Your First Move on Monday Morning:
Instead of asking "Should we use Redis or Memcached?", gather your team and perform a data-job audit. Pick a key data entity in your system that is causing performance issues. Get everyone in front of a whiteboard and map out every single read and write access pattern for that entity.
The answers will be illuminating. You will quickly see where you are using a simple tire gun to perform complex surgery and where you are using a sophisticated crew chief just to hand a driver a bottle of water. This exercise will reveal the true nature of your data's job and make your next architectural decision self-evident.
So, I'll leave you with this question: As our systems become more distributed and our need for real-time state management grows, are you still thinking about caching as just a speed boost, or are you ready to think of it as the central nervous system of your application?
ZADD), rate limiters (INCR), job queues (LPUSH/BRPOP), and managing complex objects like user sessions (HSET). Move the computation to the data.