2024-08-28
Optimize application performance with Redis caching, data structures, pub/sub messaging, and advanced patterns.
Redis is an in-memory data structure store used as a database, cache, and message broker. This guide covers Redis data types, caching strategies, performance patterns, and production deployment best practices.
# Strings - Simple key-value
SET user:1000 "John Doe"
GET user:1000
INCR page_views
EXPIRE session:abc123 3600
# Lists - Ordered collections
LPUSH notifications:user:1000 "New message"
LRANGE notifications:user:1000 0 9
RPOP queue:emails
# Sets - Unique values
SADD tags:post:100 "redis" "caching" "database"
SINTER tags:post:100 tags:post:101
SCARD online_users
# Sorted Sets - Scored unique values
ZADD leaderboard 95 "Alice" 87 "Bob" 92 "Charlie"
ZREVRANGE leaderboard 0 9 WITHSCORES
ZRANK leaderboard "Alice"
# Hashes - Field-value pairs
HSET user:1000 name "John" email "john@example.com" age 30
HGETALL user:1000
HINCRBY user:1000 login_count 1
# Bitmaps - Bit operations
SETBIT user:login:2024-01 1000 1
BITCOUNT user:login:2024-01
# HyperLogLog - Cardinality estimation
PFADD unique_visitors "user123" "user456"
PFCOUNT unique_visitors
async function getData(key) {
// Check cache first
let data = await redis.get(key);
if (!data) {
// Cache miss - fetch from database
data = await database.fetch(key);
// Store in cache with TTL
await redis.setex(key, 3600,
JSON.stringify(data));
} else {
data = JSON.parse(data);
}
return data;
}
async function saveData(key, value) {
// Write to cache and database
const pipeline = redis.pipeline();
pipeline.setex(key, 3600,
JSON.stringify(value));
await Promise.all([
pipeline.exec(),
database.save(key, value)
]);
return value;
}
// Store session with automatic expiration
async function createSession(userId, sessionData) {
const sessionId = generateSessionId();
const key = `session:${sessionId}`;
await redis.hset(key, {
userId,
...sessionData,
createdAt: Date.now()
});
await redis.expire(key, 3600); // 1 hour TTL
return sessionId;
}
// Extend session on activity
async function touchSession(sessionId) {
const key = `session:${sessionId}`;
await redis.expire(key, 3600);
}
// Sliding window rate limiter
async function checkRateLimit(userId, limit = 100) {
const key = `rate_limit:${userId}`;
const now = Date.now();
const windowStart = now - 60000; // 1 minute window
// Remove old entries
await redis.zremrangebyscore(key, 0, windowStart);
// Count requests in window
const count = await redis.zcard(key);
if (count < limit) {
// Add current request
await redis.zadd(key, now, `${now}-${Math.random()}`);
await redis.expire(key, 60);
return { allowed: true, remaining: limit - count - 1 };
}
return { allowed: false, remaining: 0 };
}
// Acquire lock with timeout
async function acquireLock(resource, ttl = 5000) {
const lockId = generateId();
const key = `lock:${resource}`;
const acquired = await redis.set(
key, lockId, 'PX', ttl, 'NX'
);
return acquired ? lockId : null;
}
// Release lock safely
async function releaseLock(resource, lockId) {
const key = `lock:${resource}`;
// Lua script for atomic check and delete
const script = `
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
else
return 0
end`;
return await redis.eval(script, 1, key, lockId);
}
// Publisher
const publisher = redis.duplicate();
async function publishEvent(channel, data) {
await publisher.publish(channel, JSON.stringify(data));
}
// Subscriber
const subscriber = redis.duplicate();
subscriber.on('message', (channel, message) => {
const data = JSON.parse(message);
console.log(`Received on ${channel}:`, data);
// Process message based on channel
switch(channel) {
case 'orders:new':
processNewOrder(data);
break;
case 'users:updated':
invalidateUserCache(data.userId);
break;
}
});
// Subscribe to channels
subscriber.subscribe('orders:new', 'users:updated');
Pipeline Commands
Batch multiple commands together to reduce network round trips and improve throughput.
Memory Optimization
Use appropriate data structures, enable compression, and set proper eviction policies (LRU, LFU).
Persistence Strategy
Choose between RDB snapshots for backups and AOF for durability based on your needs.
Connection Pooling
Reuse connections with proper pool configuration to avoid connection overhead.
Published on 2024-08-28 • Category: Database
← Back to BlogFree online developer tools and utilities for encoding, formatting, generating, and analyzing data. No registration required - all tools work directly in your browser.
Built for developers, by developers. Privacy-focused and open source.
Free online tools for Base64 encoding, JSON formatting, URL encoding, hash generation, UUID creation, QR codes, JWT decoding, timestamp conversion, regex testing, and more.
© 2024 NarvikHub. All rights reserved.