Database

Redis Review 2025: The In-Memory Data Store That Powers Real-Time Applications

SR
Suresh Reddy
January 12, 2025
14 min read

The 3 AM Incident That Made Me a Redis Believer

Let me tell you about the night I truly understood why Redis exists. It was 2019, I was on call, and our e-commerce API was melting. Black Friday traffic. Every product page was hammering Postgres for the same catalog data -- product name, price, description, inventory count. Queries that normally took 15ms were taking 400ms because the connection pool was saturated and everything was queuing up behind everything else. P99 latency hit 3 seconds. Customers were bouncing. Revenue was dropping in real time.

We'd talked about adding a caching layer for months. Never prioritized it. That night at 3 AM, with sweat on my forehead and Slack going ballistic, I spun up a Redis instance, wrote a quick cache-aside wrapper around our top 20 product queries, deployed it, and watched the dashboard go from red to green in about ninety seconds. Average API response time dropped from 400ms to 8ms. Postgres CPU went from 95% to 20%. The site stopped dying. I went back to bed.

That was five years ago. Since then I've used Redis in every single project I've worked on. Caching, obviously. But also session storage, rate limiting, job queues, real-time leaderboards, pub/sub for websocket fanout, and more recently vector search for a recommendations feature. Redis is one of those tools that you keep finding new uses for the longer you work with it. And somehow, despite being over 15 years old, it keeps getting more relevant rather than less.

Caching: The Thing You Already Know Redis Does Well

This is the bread and butter. You have a database query that's slow or getting hammered too often. You stick Redis in front of it. You SET the result with a TTL, next time you GET it from memory instead of disk. Response time goes from double-digit milliseconds to sub-millisecond. This is not news to anyone who's built a web application in the last decade.

But there's nuance in how you cache, and Redis gives you more control than people realize. The eviction policies alone are worth understanding. LRU (least recently used) is the default most people reach for, and it works fine for general caching. LFU (least frequently used) is better when you have a small number of extremely hot keys that should never get evicted -- think your homepage product grid or a config object that every request reads. You can also mix volatile and non-volatile keys, where only keys with TTLs set are eligible for eviction. This lets you use the same Redis instance for both cache data (evictable) and persistent data (keep forever) without them competing for memory.

The numbers on caching are hard to argue with. In a benchmark I ran last month on an M2 Mac with Redis 7.2, I was getting 180,000 GET operations per second on a single instance with an average latency of 0.2ms. That's insane throughput from a single-threaded process. In the real world with network overhead you're looking at more like 0.5-1ms, which is still 10-100x faster than hitting most databases.

Cache invalidation, of course, remains the hardest problem in computer science (after naming things). Redis doesn't solve this for you -- you still need to figure out when to bust your cache. But it gives you the tools: TTL-based expiration, explicit DEL commands, keyspace notifications that fire events when keys change, and Lua scripting for atomic cache update patterns. How you use them is on you.

Sessions, Rate Limiting, and the Stuff Nobody Writes Blog Posts About

Caching gets all the attention, but Redis earns its keep in a dozen quieter ways.

Session storage is the one that probably affects the most users without them knowing. If you've ever logged into a web app and stayed logged in across page loads, there's a decent chance your session token lives in Redis. It's fast (you check it on every request so it needs to be), it supports TTL (sessions should expire), and it's shared across app servers (so it doesn't matter which backend instance handles your request). Almost every web framework has a Redis session adapter. Express, Django, Rails, Laravel, Spring -- all of them. It just works.

Rate limiting is another perfect Redis use case. You need to track how many requests a user or IP has made in the last minute and reject them if they exceed a threshold. The classic pattern is INCR + EXPIRE: increment a counter keyed by the user ID and the current minute, set it to expire in 60 seconds. If the count exceeds your limit, return 429. This is like four lines of code and handles thousands of rate-limiting decisions per second. I've also implemented sliding window rate limiters using sorted sets, which are more accurate but slightly more complex. Both patterns work well. Memcached could do the simple counter version too, but try doing the sliding window without sorted sets. Good luck.

Distributed locks are something I use more than I expected. When you have multiple instances of a service and they all might try to do the same thing at the same time -- say, processing a webhook that triggers a database migration -- you need a way to ensure only one instance does it. Redis's SET with NX (set if not exists) and PX (expire in milliseconds) gives you a basic distributed lock. The Redlock algorithm extends this across multiple Redis instances for more safety. It's not perfect (Martin Kleppmann's critique is worth reading), but for most practical purposes it's good enough and way simpler than setting up ZooKeeper or etcd.

Pub/Sub, Streams, and the Message Broker You Didn't Know You Had

Redis Pub/Sub is the simplest real-time messaging system you'll ever set up. PUBLISH a message to a channel, SUBSCRIBE to that channel from another client, messages arrive instantly. I've used it for websocket fanout (your app server publishes chat messages to Redis, all connected websocket servers subscribe and push to their clients), for cache invalidation across multiple app instances, and for lightweight event broadcasting in microservices.

The catch with Pub/Sub is that it's fire-and-forget. If a subscriber is disconnected when a message is published, that message is gone forever. There's no persistence, no replay, no acknowledgment. For chat notifications and real-time dashboards, that's fine. For anything where you need guaranteed delivery, it's not.

That's where Redis Streams come in, and honestly, Streams don't get enough love. They're basically Redis's answer to Kafka, at a smaller scale. Messages are persistent, ordered, and stored with IDs. Consumer groups let multiple consumers process messages from the same stream without duplicating work. Failed messages can be claimed by other consumers. You get exactly-once processing semantics (with some care). I built a task queue with Streams last year that handles about 50,000 jobs per hour with three consumer instances, and the code is about 200 lines of Python. Try doing that with Kafka and see how many YAML files you end up with.

Streams are not a Kafka replacement for high-throughput event streaming at massive scale. If you're ingesting millions of events per second across hundreds of partitions, you want Kafka or Redpanda. But for most applications -- processing orders, handling webhooks, coordinating microservices, managing background jobs -- Streams are more than enough and dramatically simpler to operate. You're already running Redis. You don't need another piece of infrastructure.

Redis Stack: When They Decided Redis Should Do Everything

Redis Stack is where things get interesting and maybe a little ambitious. It bundles the core Redis engine with four modules that expand what Redis can do:

RedisJSON: Native JSON document storage. You store a JSON object at a key and then query or update individual fields within it using JSONPath syntax. No more serializing and deserializing entire objects on every read/write. I used this for a user preferences store where each user has a complex nested settings object, and being able to update just settings.notifications.email without reading the whole thing is surprisingly nice.

RediSearch: Full-text search with stemming, fuzzy matching, faceted search, and auto-suggest. It indexes your Redis data and lets you query it with a SQL-ish syntax. I'll be honest: for a simple product search or an internal knowledge base, this is good enough and saves you from running an entire Elasticsearch cluster. For anything more complex -- heavy text analytics, custom scoring, multi-language -- Elasticsearch still wins.

RedisTimeSeries: Time-series data with automatic aggregation and downsampling. Perfect for metrics, IoT sensor data, and monitoring dashboards. It handles the "store billions of data points but only keep second-granularity for the last hour, minute-granularity for the last day, hour-granularity forever" pattern natively.

Vector search: Store embeddings, build indexes (HNSW or flat), run k-nearest-neighbor queries. I tested this with 500k product embeddings for a similarity search feature. Query time was consistently under 5ms, which is competitive with Pinecone. The advantage over dedicated vector databases is that your vectors live alongside your regular Redis data -- no additional infrastructure, no sync pipeline, no extra client library.

Is Redis Stack trying to do too much? Maybe. The "multi-model database" pitch always makes me a little skeptical. But in practice, if you're already running Redis and you need one of these capabilities at a moderate scale, it's hard to argue against using a module that's already there rather than deploying and operating an entirely separate system.

The Licensing Thing

I'd be dodging the elephant in the room if I didn't mention this. In 2024, Redis changed its license from BSD (do whatever you want) to a dual RSAL/SSPL license (do whatever you want unless you're a cloud provider selling Redis as a service). This upset a lot of people. The Linux Foundation forked Redis into Valkey. Heated blog posts were written. Twitter threads were threaded.

My take: for 99% of Redis users -- people building applications that use Redis as part of their stack -- the license change has zero practical impact. You can still download it, run it, modify it, and build commercial products on top of it. The restrictions only bite if you're AWS or Google trying to offer a managed Redis service without contributing back. If that's you, Valkey exists and it's fine.

Valkey is a legitimate option and I expect it to diverge from Redis over time in interesting ways. But right now it's functionally identical to the Redis version it was forked from, and it doesn't have Redis Stack's modules. If you need RedisJSON, RediSearch, or vector search, you're using Redis or Redis Cloud.

What Running Redis in Production Actually Looks Like

Self-hosting Redis is straightforward until it isn't. A single Redis instance on a 4GB VPS handles most small-to-medium applications without breaking a sweat. The config file is well-documented, the defaults are sane, and there's not much to tune for a basic setup. Set up AOF persistence with everysec fsync, configure a replica for failover, point Sentinel at both, and you're done.

Scaling is where the complexity shows up. Redis Cluster shards your data across multiple nodes using 16,384 hash slots. It handles automatic failover and rebalancing. It also introduces constraints: multi-key operations only work on keys in the same hash slot (you solve this with hash tags), Lua scripts can only access keys on the same node, and resharding during heavy load requires careful planning. I've operated a 12-node Redis Cluster in production and while it works, "operates itself" is a generous description. You need monitoring, alerting, and someone who understands what happens when a primary node goes down during a resharding operation.

Redis Cloud (the managed service) eliminates all of this. Provisioning takes five minutes. Auto-scaling adjusts capacity based on load. Multi-zone deployments handle failover automatically. Active-active geo-replication keeps multiple regions in sync with conflict resolution. It starts at around $7/month for a small instance and scales to enterprise pricing for large deployments. I've used it for two production projects now and my honest assessment is: if you can afford it, the operational peace of mind is worth the premium over self-hosting.

Performance Notes From Real Benchmarks

Rather than quoting marketing numbers, here's what I actually measured running redis-benchmark on a c5.xlarge EC2 instance (4 vCPU, 8GB RAM) with Redis 7.2:

Simple GET/SET: ~160,000 ops/sec, 0.25ms avg latency. LPUSH/LPOP (queue pattern): ~140,000 ops/sec. ZADD/ZRANGEBYSCORE (leaderboard pattern): ~95,000 ops/sec. Lua script (rate limiter, 3 operations): ~80,000 ops/sec.

These are single-instance numbers. With Redis Cluster you can scale linearly by adding nodes, though you take a small latency hit from the redirect hop on misrouted commands. In practice, a single well-provisioned Redis instance handles more load than most applications will ever generate. I've seen production setups serving 50,000 concurrent users on a single 8GB Redis instance without it breaking a sweat.

Compared to Memcached, Redis is slightly slower for pure key-value GETs (Memcached's multi-threaded model helps on high-core machines), but the difference is maybe 10-15% and disappears when you factor in all the things Redis can do that Memcached can't. DragonflyDB claims 10-25x throughput on multi-core machines, and the benchmarks support that for simple operations. But DragonflyDB is young, the community is small, and Redis Stack's modules have no equivalent there. For production use in 2025, Redis is still the safe bet.

Why You'll Love It

  • Sub-millisecond latency on reads and writes -- nothing else at this price point comes close
  • Data structures (sorted sets, streams, hashes) let you model real problems without hacks
  • Redis Stack's JSON, search, time-series, and vector modules reduce your infrastructure footprint
  • Battle-tested at absurd scale by Twitter, GitHub, Stack Overflow, and thousands of startups
  • Client libraries in every language you've heard of and several you haven't
  • Atomic operations by default eliminate entire categories of concurrency bugs

What Will Bite You

  • Everything lives in RAM -- your hosting bill scales linearly with your dataset size
  • The RSAL/SSPL license change has split the community and created Valkey uncertainty
  • Single-threaded execution means CPU-heavy Lua scripts block everything else
  • Cluster mode adds real operational complexity with hash slots and resharding
  • Persistence is available but it's not a replacement for a real database -- data loss is possible
  • No SQL, no joins, no complex queries -- if you need relational logic, look elsewhere

What It Costs to Run

Self-hosted (open source): Free software. You pay for the server. A 4GB VPS runs about $20-40/month on most cloud providers, which is enough for most small-to-medium workloads. A 64GB dedicated instance for high-throughput production is $300-500/month on AWS. Add operational cost: your engineers' time managing, monitoring, patching, and recovering from outages.

Redis Cloud Free: 30MB. Good for learning and prototyping. Not much else.

Redis Cloud Essentials: Starting around $7/month for 250MB. Dedicated infrastructure, daily backups, Redis Stack modules. This is where small production workloads should start.

Redis Cloud Pro: Starting around $100/month. Multi-zone HA, auto-scaling, geo-replication. For serious production deployments.

Enterprise: Custom pricing. Active-active geo-replication, 99.999% SLA, compliance certifications. The "call us" tier.

When to Use It, When to Skip It

Use Redis when you need fast data access and your dataset fits in memory. Caching, sessions, rate limiting, queues, leaderboards, real-time features -- these are all slam dunks. Use Redis Stack when you need search, JSON documents, time-series, or vector similarity at a scale that doesn't justify deploying Elasticsearch, MongoDB, InfluxDB, or Pinecone separately.

Skip Redis when your dataset is large and doesn't need to be fast. If you're storing 500GB of historical order data that gets queried once a day, Postgres is your friend. Skip it when you need complex relational queries with joins and aggregations -- Redis doesn't do that and it's not trying to. Skip it for very small applications where the added infrastructure isn't justified -- if your app has ten users, your database is fast enough without a cache layer in front of it.

Redis is a complement to your primary database, not a replacement for it. The architectures I've seen work best use Postgres or MySQL for source-of-truth storage and Redis for everything that needs to be fast: cache reads, session lookups, rate limiting, real-time features. That combination has carried me through five years of production systems without a single regret.

4.6 / 5

Redis is one of those tools that you just keep reaching for. The API surface is small enough to learn in a day, the performance is good enough that you almost never think about it, and the data structures are flexible enough that every few months you discover yet another problem it solves elegantly. Fifteen years old and still the default answer to "how do I make this faster?"

The licensing change is the only real cloud over the project, and for most developers it's a cloud that produces no rain. The technical excellence hasn't changed. The ecosystem is still the largest. The reliability is still proven at scales most of us will never touch.

If you're building anything that talks to a database and cares about speed, you probably already have Redis in your stack. If you don't, you probably should.

Comments (3)