Caching Strategies: Client, Server, CDN
Caching improves performance significantly. This article covers caching strategies and implementation.
Introduction
Caching provides:
- Faster load times
- Reduced bandwidth
- Lower server load
- Better scalability
- Improved user experience
Caching Layers
Browser Caching
// โ
Good: HTTP caching headers
app.get('/api/users/:id', (req, res) => {
res.set('Cache-Control', 'public, max-age=3600');
res.set('ETag', '"abc123"');
res.json(user);
});
// โ
Good: Service Worker caching
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js');
}
// โ
Good: LocalStorage caching
localStorage.setItem('user', JSON.stringify(user));
const cached = JSON.parse(localStorage.getItem('user'));
Server Caching
// โ
Good: Redis caching
const redis = require('redis');
const client = redis.createClient();
async function getUser(id) {
const cached = await client.get(`user:${id}`);
if (cached) return JSON.parse(cached);
const user = await User.findById(id);
await client.setex(`user:${id}`, 3600, JSON.stringify(user));
return user;
}
// โ
Good: Cache invalidation
async function updateUser(id, updates) {
const user = await User.findByIdAndUpdate(id, updates);
await client.del(`user:${id}`);
return user;
}
CDN Caching
// โ
Good: CDN configuration
// Serve static assets from CDN
<script src="https://cdn.example.com/app.js"></script>
<link rel="stylesheet" href="https://cdn.example.com/style.css" />
// โ
Good: Cache headers for CDN
app.get('/static/*', (req, res) => {
res.set('Cache-Control', 'public, max-age=31536000, immutable');
res.sendFile(req.path);
});
Cache Strategies
Cache-Aside
// โ
Good: Cache-aside pattern
async function getUser(id) {
// Check cache
const cached = await cache.get(`user:${id}`);
if (cached) return cached;
// Fetch from database
const user = await User.findById(id);
// Store in cache
await cache.set(`user:${id}`, user, 3600);
return user;
}
Write-Through
// โ
Good: Write-through pattern
async function updateUser(id, updates) {
// Update database
const user = await User.findByIdAndUpdate(id, updates);
// Update cache
await cache.set(`user:${id}`, user);
return user;
}
Write-Behind
// โ
Good: Write-behind pattern
async function updateUser(id, updates) {
// Update cache immediately
await cache.set(`user:${id}`, updates);
// Update database asynchronously
setTimeout(async () => {
await User.findByIdAndUpdate(id, updates);
}, 1000);
}
Best Practices
-
Set appropriate TTL:
// โ Good: Appropriate TTL await cache.setex('user:1', 3600, user); // 1 hour await cache.setex('config', 86400, config); // 1 day // โ Bad: No TTL await cache.set('user:1', user); -
Invalidate cache:
// โ Good: Invalidate on update async function updateUser(id, updates) { await User.findByIdAndUpdate(id, updates); await cache.del(`user:${id}`); } // โ Bad: No invalidation async function updateUser(id, updates) { await User.findByIdAndUpdate(id, updates); } -
Use cache headers:
// โ Good: Cache headers res.set('Cache-Control', 'public, max-age=3600'); // โ Bad: No cache headers res.json(data);
Summary
Caching is essential. Key takeaways:
- Use browser caching
- Implement server caching
- Use CDN
- Set appropriate TTL
- Invalidate cache
- Use cache headers
- Monitor cache hit rate
- Improve performance
Related Resources
Next Steps
- Learn about Monitoring
- Explore DevOps
- Study Infrastructure
- Practice caching
- Improve performance
Comments