Kembali

A Practical Guide to Redis Caching in Node.js Applications

Fadil Bafagih

Fadil Bafagih

5 September 20264 menit baca

TIPEArtikel
KATEGORIWeb
38 views
A Practical Guide to Redis Caching in Node.js Applications

What is Redis?

Redis (which stands for Remote Dictionary Server) is an open-source, in-memory data structure store. It is primarily used as a fast, highly scalable key-value database, a cache, a message broker, and a streaming engine.

Unlike traditional relational databases (like MySQL or PostgreSQL) that store data on hard drives or SSDs, Redis stores all of its data directly in the server's main memory (RAM). This architectural choice allows it to deliver incredibly fast, sub-millisecond response times because it eliminates the need to access slower disk storage.

TL;DR: Redis is your database's best friend. It handles the heavy lifting so your primary database can chill.

Key Characteristics

Feature

What It Means

What It Means

In-Memory Performance

Data lives in RAM, so reads and writes are insanely fast (millions of ops/sec)

Can snapshot data to disk so you don't lose everything on a crash

In-Memory Performance

Data lives in RAM, so reads and writes are insanely fast (millions of ops/sec)

Can snapshot data to disk so you don't lose everything on a crash

In-Memory Performance

Data lives in RAM, so reads and writes are insanely fast (millions of ops/sec)

Can snapshot data to disk so you don't lose everything on a crash

In-Memory Performance

Data lives in RAM, so reads and writes are insanely fast (millions of ops/sec)

Can snapshot data to disk so you don't lose everything on a crash

Common Data Structures

Redis isn't just a boring key-value store — it supports a ton of built-in data structures out of the box:

  • Strings — The most basic type. Store text, numbers, or serialized objects.

  • Lists — Collections of string elements sorted by insertion order. Perfect for queues.

  • Sets — Unordered collections of unique strings. Great for tracking unique visitors.

  • Hashes — Maps composed of fields and values (similar to objects or dictionaries in programming languages). Ideal for storing user profiles.

  • Sorted Sets — Like Sets, but every string is associated with a score, allowing elements to be sorted automatically. Perfect for leaderboards.

Primary Use Cases

Here are the top real-world scenarios where Redis absolutely shines:

  1. Caching — Storing the results of frequent database queries or API calls so that subsequent requests can be served instantly without overloading the primary database.

  2. Session Management — Holding user login sessions and tokens for fast verification in web applications.

  3. Real-Time Analytics — Counting and processing fast-moving data streams, such as tracking website traffic or monitoring system metrics in real-time.

  4. Gaming Leaderboards — Using Sorted Sets to instantly calculate and retrieve a player's global rank.

  5. Pub/Sub Messaging — Acting as a lightweight message broker where publishers send messages to channels, and subscribers listen for those messages in real-time (useful for chat applications).

Before vs. After Redis

Let's visualize what happens when you add Redis to your architecture:

Before Redis

This side illustrates a standard architecture where the web application relies solely on PostgreSQL for all data operations.

  • Direct Disk I/O — Every time a user makes a request, the web application queries PostgreSQL directly. Because PostgreSQL stores its data on a physical disk (Hard Drive or SSD), it has to perform Disk I/O operations, which are significantly slower than reading from memory.

  • High Latency — The delay caused by waiting for the disk to find and return the data results in a high latency response for the user.

  • Database Strain — Processing every single query, especially repetitive reads, consumes CPU and memory resources, eventually causing a bottleneck as traffic increases.

After Redis

This side shows how adding Redis dramatically improves performance and relieves the PostgreSQL database.

  • In-Memory Speed (RAM) — Redis is placed between the web application and PostgreSQL. When the app needs data, it checks Redis first. Because Redis stores data in RAM, it provides ultra-fast read and write speeds.

  • Low Latency — Retrieving data from RAM eliminates the slow Disk I/O, resulting in a low latency response that feels instantaneous to the user.

  • Cache Miss and Sync — If Redis doesn't have the data (a "Cache Miss"), the system will fetch it from PostgreSQL and then store it in Redis for next time. Data writes or cache updates can be handled via asynchronous persistence in the background without slowing down the user's experience.

  • A Happy Database — By letting Redis handle the bulk of the repetitive read requests, PostgreSQL is protected from being overwhelmed. PostgreSQL now has plenty of resources freed up to handle complex queries and essential data writes efficiently.

Implementation in Express.js Application

Alright, enough theory. Let's build a Product API that integrates Redis as a caching layer using the Service-Repository Pattern for clean, SOLID architecture.

Project Structure

TEXT
src/
├── config/
│   ├── database.config.ts
│   ├── env.config.ts
│   └── redis.config.ts
├── controllers/
│   └── product.controller.ts
├── middlewares/
│   ├── error.middleware.ts
│   └── validation.middleware.ts
├── models/
│   └── product.model.ts
├── repositories/
│   ├── product.repository.interface.ts
│   └── product.repository.ts
├── routes/
│   └── product.routes.ts
├── services/
│   ├── product.service.interface.ts
│   └── product.service.ts
├── app.ts
└── server.ts

Environment Configuration

First, let's handle our environment variables. This centralized config makes it super clean to access settings across the entire app.

src/config/env.config.ts

TYPESCRIPT
import dotenv from "dotenv";

dotenv.config();

export const envConfig = {
  port: parseInt(process.env.PORT || "3000", 10),
  nodeEnv: process.env.NODE_ENV || "development",
  db: {
    host: process.env.DB_HOST || "localhost",
    port: parseInt(process.env.DB_PORT || "5432", 10),
    user: process.env.DB_USER || "postgres",
    password: process.env.DB_PASSWORD || "postgres",
    name: process.env.DB_NAME || "redis_demo",
  },
  redis: {
    host: process.env.REDIS_HOST || "localhost",
    port: parseInt(process.env.REDIS_PORT || "6379", 10),
    password: process.env.REDIS_PASSWORD || undefined,
    ttl: parseInt(process.env.REDIS_TTL || "3600", 10),
  },
} as const;

Key Takeaways

  1. Redis is a performance multiplier — From 190ms to 5ms, the numbers speak for themselves.

  2. Cache-Aside is your go-to pattern — Check cache first, fallback to DB, then populate cache.

  3. Graceful degradation matters — If Redis dies, your app should still work (just slower).

  4. Clean architecture pays off — Interfaces + Dependency Injection = testable, swappable, maintainable code.

  5. Security is non-negotiable — Parameterized queries, input validation, and sort column whitelisting protect you from nasty attacks.

Full Source Code

GitHub Repository

TAGS
#IT#Tutorial#Web#Tips
38 views