Skip to content
Plurafy

Caching Strategies with Redis

Redis is an in-memory data store that enables high-performance caching. Learn caching strategies, Redis data structures, and patterns for improving application performance.

Implement Redis caching strategies to reduce database load, improve response times, and build scalable distributed systems.

In-Memory Storage: Lightning-fast data access (microseconds) Atomic Operations: Thread-safe operations without locks Data Structures: Strings, Lists, Sets, Hashes, Sorted Sets, Streams Persistence: Optional durability with RDB snapshots and AOF logs Replication: Master-slave replication for high availability Pub/Sub: Real-time message delivery

Cache-Aside (Lazy Loading): Load data into cache on demand Write-Through: Write to both cache and database simultaneously Write-Behind: Asynchronously write to database Cache Invalidation: TTL, event-based, or manual invalidation

const redis = require('redis');
const client = redis.createClient({
host: 'localhost',
port: 6379,
db: 0,
retry_strategy: (options) => {
if (options.error && options.error.code === 'ECONNREFUSED') {
return new Error('End of retry');
}
if (options.total_retry_time > 1000 * 60 * 60) {
return new Error('Retry time exhausted');
}
if (options.attempt > 10) {
return undefined;
}
return Math.min(options.attempt * 100, 3000);
}
});
client.on('error', (err) => console.log('Redis Error', err));
client.on('connect', () => console.log('Redis Connected'));
module.exports = client;
const redis = require('redis');
const client = redis.createClient();
async function getCachedUser(userId) {
// Try to get from cache
const cached = await client.get(`user:${userId}`);
if (cached) {
return JSON.parse(cached);
}
// If not in cache, fetch from database
const user = await fetchUserFromDatabase(userId);
// Store in cache with TTL (1 hour)
await client.setEx(`user:${userId}`, 3600, JSON.stringify(user));
return user;
}
async function fetchUserFromDatabase(userId) {
// Simulate database query
return { id: userId, name: 'John Doe', email: 'john@example.com' };
}
async function updateUserWithCache(userId, userData) {
// Update database
const updatedUser = await db.users.update(userId, userData);
// Update cache simultaneously
await client.setEx(
`user:${userId}`,
3600,
JSON.stringify(updatedUser)
);
return updatedUser;
}
async function deleteUserWithCacheInvalidation(userId) {
// Delete from database
await db.users.delete(userId);
// Invalidate cache
await client.del(`user:${userId}`);
}
// Strings - Key-value pairs
await client.set('session:abc123', JSON.stringify(sessionData));
const session = JSON.parse(await client.get('session:abc123'));
// Lists - Ordered collections
await client.rPush('activity:log', 'User logged in');
const logs = await client.lRange('activity:log', 0, -1);
// Sets - Unique collections
await client.sAdd('active:users', userId1, userId2);
const activeUsers = await client.sMembers('active:users');
// Hashes - Field-value pairs
await client.hSet('user:123', { name: 'John', email: 'john@example.com' });
const user = await client.hGetAll('user:123');
// Sorted Sets - Ranked collections
await client.zAdd('leaderboard', { score: 100, member: 'user1' });
const topUsers = await client.zRevRange('leaderboard', 0, 9);
// Streams - Append-only logs
await client.xAdd('events', '*', { type: 'login', userId: '123' });
const session = require('express-session');
const RedisStore = require('connect-redis').default;
const redis = require('redis');
const client = redis.createClient();
client.connect();
app.use(
session({
store: new RedisStore({ client }),
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {
secure: process.env.NODE_ENV === 'production',
httpOnly: true,
maxAge: 24 * 60 * 60 * 1000, // 24 hours
},
})
);
async function isRateLimitExceeded(userId, limit = 100, windowMs = 60000) {
const key = `rate:${userId}`;
const current = await client.incr(key);
if (current === 1) {
// Set expiration on first request
await client.expire(key, Math.ceil(windowMs / 1000));
}
return current > limit;
}
app.use(async (req, res, next) => {
const exceeded = await isRateLimitExceeded(req.user?.id, 100);
if (exceeded) {
return res.status(429).json({ error: 'Rate limit exceeded' });
}
next();
});
  1. Set Appropriate TTL

    • Balance between freshness and cache hit rate
    • Use different TTLs for different data types
    • Implement cache invalidation strategies
  2. Handle Cache Misses

    • Implement graceful degradation
    • Prevent cache stampede (thundering herd)
    • Use locks or callbacks for heavy operations
  3. Monitor Cache Performance

    • Track hit/miss ratios
    • Monitor memory usage
    • Measure eviction rates
  4. Security

    • Encrypt sensitive cached data
    • Use password authentication
    • Restrict network access
  5. High Availability

    • Use Redis Sentinel for failover
    • Implement Redis Cluster for scaling
    • Regular backups and disaster recovery
  • Session Storage: Distributed session management
  • Rate Limiting: API rate limiting and throttling
  • Real-Time Analytics: Event counters and aggregations
  • Feed Caching: Social media feeds and recommendations
  • Task Queues: Background job processing