Skip to main content
โšก Calmops

Caching Strategies: Client, Server, CDN

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

  1. 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);
    
  2. 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);
    }
    
  3. 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

Next Steps

Comments