Logo

dev-resources.site

for different kinds of informations.

Top 5 Caching Patterns for High-Performance Applications

Published at
11/29/2024
Categories
cache
node
typescript
Author
wallacefreitas
Categories
3 categories in total
cache
open
node
open
typescript
open
Author
14 person written this
wallacefreitas
open
Top 5 Caching Patterns for High-Performance Applications

Caching is a powerful technique to enhance the performance and scalability of applications. By storing frequently accessed data in faster storage layers, you can reduce latency, alleviate database load, and provide a smoother user experience.

In this article, we’ll explore the top five caching patterns that every developer should know. Using TypeScript and Node.js, we’ll demonstrate how these patterns can be implemented to optimize application performance.

1️⃣ In-Memory Cache
An in-memory cache stores data in memory for fast read and write operations. It is ideal for storing small, frequently accessed data like session information or configuration settings.

Example: Caching with Node.js

class InMemoryCache<T> {
  private cache: Map<string, T> = new Map();

  set(key: string, value: T) {
    this.cache.set(key, value);
  }

  get(key: string): T | undefined {
    return this.cache.get(key);
  }

  delete(key: string) {
    this.cache.delete(key);
  }
}

// Usage
const cache = new InMemoryCache<number>();
cache.set('user:123', 42);
console.log(cache.get('user:123')); // Output: 42
Enter fullscreen mode Exit fullscreen mode

2️⃣ Write-Through Cache

In a write-through cache, writes are first made to the cache and then immediately written to the underlying data store. This ensures that the cache is always in sync with the database.

Example: Write-Through Cache

class WriteThroughCache<T> {
  private cache: Map<string, T> = new Map();

  async write(key: string, value: T, writeToDb: (key: string, value: T) => Promise<void>) {
    this.cache.set(key, value);
    await writeToDb(key, value); // Write to database
  }

  get(key: string): T | undefined {
    return this.cache.get(key);
  }
}

// Simulated database function
async function dbWrite(key: string, value: any) {
  console.log(`Writing ${key}: ${value} to database`);
}

// Usage
const writeCache = new WriteThroughCache<string>();
writeCache.write('key1', 'value1', dbWrite);
console.log(writeCache.get('key1')); // Output: 'value1'
Enter fullscreen mode Exit fullscreen mode

3️⃣ Cache-aside Pattern

In the cache-aside pattern, the application checks the cache first. If the data is not available, it retrieves it from the database and stores it in the cache for future requests.

Example: Cache-aside with Redis

import redis from 'redis';
import { promisify } from 'util';

const client = redis.createClient();
const getAsync = promisify(client.get).bind(client);
const setAsync = promisify(client.set).bind(client);

async function getData(key: string, fetchFromDb: () => Promise<string>): Promise<string> {
  const cachedValue = await getAsync(key);

  if (cachedValue) {
    console.log('Cache hit');
    return cachedValue;
  }

  console.log('Cache miss');
  const value = await fetchFromDb();
  await setAsync(key, value);
  return value;
}

// Simulated database fetch
async function fetchFromDb() {
  return 'Database Value';
}

// Usage
getData('user:123', fetchFromDb).then(console.log);
Enter fullscreen mode Exit fullscreen mode

4️⃣ Read-Through Cache

In a read-through cache, all read requests go through the cache. If the data is not present, the cache fetches it from the data store and updates itself automatically.

Example: Read-Through Cache

class ReadThroughCache<T> {
  private cache: Map<string, T> = new Map();

  async get(key: string, fetchFromDb: () => Promise<T>): Promise<T> {
    if (this.cache.has(key)) {
      console.log('Cache hit');
      return this.cache.get(key)!;
    }

    console.log('Cache miss');
    const value = await fetchFromDb();
    this.cache.set(key, value);
    return value;
  }
}

// Usage
const readCache = new ReadThroughCache<string>();
readCache.get('user:123', async () => 'Fetched from DB').then(console.log);
Enter fullscreen mode Exit fullscreen mode

5️⃣ Distributed Cache

A distributed cache stores data across multiple nodes, ensuring scalability and fault tolerance. It is commonly used in large-scale systems to handle high traffic efficiently.

Example: Using Redis as a Distributed Cache

import { createClient } from 'redis';

const client = createClient();

async function setCache(key: string, value: string) {
  await client.connect();
  await client.set(key, value);
  console.log(`Set ${key}: ${value}`);
  await client.disconnect();
}

async function getCache(key: string) {
  await client.connect();
  const value = await client.get(key);
  console.log(`Get ${key}: ${value}`);
  await client.disconnect();
  return value;
}

// Usage
setCache('session:abc', 'active');
getCache('session:abc');
Enter fullscreen mode Exit fullscreen mode

Caching patterns are essential for building high-performance, scalable applications. Whether you’re using simple in-memory caches or complex distributed caching solutions, choosing the right pattern for your use case can significantly improve your application’s speed and reliability.

List of strategies of cache with diagrams

By implementing these patterns in Node.js with TypeScript, you can optimize your system's performance and enhance user experience. Start with the basics and scale as your application's needs evolve.

Happy coding ❤️

cache Article's
30 articles in total
Favicon
Caching in Node.js: Using Redis for Performance Boost
Favicon
Building the Perfect Caching System: A Comprehensive Guide
Favicon
Cache your function computation in React Server Components
Favicon
From Heartbeats to Cache Misses: Making Big Numbers Hit Home
Favicon
Redis Cache - A String story
Favicon
Boosting Backend Performance with Distributed Cache: A Comprehensive Guide
Favicon
🌟 Mastering Caching in JavaScript for Optimizing Performance 🚀
Favicon
Cache NLogN🏎️
Favicon
System Design 02 - Caching: The Art of Keeping Users Happy Without Breaking a Sweat
Favicon
Stale cache, the holy grail of performance
Favicon
Top 5 Caching Patterns for High-Performance Applications
Favicon
How to Effectively Handle Caching in Your Application: Lazy Loading vs Write-Through
Favicon
Using Caching in React with useGetProducts: Improve Performance and UX
Favicon
The Role of Cache Memory in Enhancing Processing Speed
Favicon
Mastering Android App Visuals: A Comprehensive Guide to Effortless Image Uploading, Storage, and Sharing.
Favicon
That way to build High-Performance APIs in .NET - Part 2: Caching
Favicon
Understanding CDN Cache in NextJs
Favicon
Supercharge your applications queries with caching
Favicon
Can Postgres replace Redis as a cache?
Favicon
Difference between cache vs cookie
Favicon
Monitor Squid Proxy with Goaccess
Favicon
Speeding Up Your Website Using Cloudflare Cache
Favicon
Finally found a solution to clear the CDN cache using GitHub Actions!
Favicon
Stale-while-revalidate and it's usage with Next.js
Favicon
Why do we need NoSql Database
Favicon
Go Redis Crud quickly example
Favicon
How to build a caching layer for your Laravel API
Favicon
Davide's Code and Architecture Notes - Cache Expiration vs Cache Eviction (and Eviction Policies)
Favicon
Entendendo porque o Cache Lock é sinônimo de integridade
Favicon
Mastering Frontend Performance: Harnessing the Power of Caching

Featured ones: