Unlock Faster Performance: A Beginner's Guide to Using Redis for Database Caching
Tags: javascript, redis, beginners, tutorial
Published: 2023-01-15 18:38:14

When it comes to web development, speed and scalability are crucial for providing a seamless user experience. One way to improve the performance of a web application is by implementing a caching system. Caching stores frequently accessed data in a fast storage system, allowing for quick retrieval the next time the data is needed, without having to hit the database. 

In this article, we will dive into Redis, an in-memory data structure store that can be used as a cache, database, and message broker. We will explore the benefits of using Redis for database caching, including setup and integration with a web application. By the end of this article, you will have the knowledge and tools to unlock lightning-fast performance for your website.


## Pre-requisite

Before diving into the world of Redis and its benefits for database caching, it's important to note that this guide assumes that you already have Node.js, Redis, and MySQL installed on your computer. If you don't have these software programs installed, please follow these links to download and install them:
-[Node.js](https://nodejs.org/en/download/)
-[Redis](https://redis.io/download)
-[MySQL](https://dev.mysql.com/downloads/mysql/)

Once these prerequisites are installed, you're ready to follow along with the rest of the article.

**Note**: Redis is not currently compatible with Windows operating systems. To use Redis on Windows, you must install Windows Subsystem for Linux (WSL) either by downloading it from Microsoft Store or following the instructions [here](https://learn.microsoft.com/en-us/windows/wsl/install).


## What we’ll learn

Database caching is effective when dealing with data that is frequently accessed. In this example, we would use caching to make our API calls faster. We'll achieve this by saving the user's information to Redis when they log in and use that saved information for subsequent API calls instead of getting it again. 

To simplify the process, we will not be implementing a full authentication system. Instead, we would hardcode the ID of an existing user record in a `users` table I have previously created.


## Setup

To start a new Node.js project using npm, you can use the `npm init` command.

Open a terminal or command prompt in the directory where you want to create your project.

Run the command below to start the initialization process. 

```
npm init
```

This command will prompt you to enter information about your project, such as the name, version, and description. You can press enter to accept the default values or enter your own.

Once you have entered all of the required information, npm will create a package.json file in your project directory. This file contains all of the information you entered, as well as the dependencies and scripts for your project.

## Redis setup

Before starting this tutorial, you need to have Redis installed on your local environment. You can follow the installation guides for your specific platform to do this.

[Installation for Mac](https://phoenixnap.com/kb/install-redis-on-mac)
[Installation for Ubuntu](https://www.digitalocean.com/community/tutorials/how-to-install-and-secure-redis-on-ubuntu-18-04)
[Installation for Windows](https://redis.com/blog/redis-on-windows-10/)

Next, we add a start script in the `package.json` file to start running our server.

```
"start": "node src/index.js"
```


## Installing Dependencies

Next, we will install the necessary dependencies needed for our API. To achieve this, on your command line run the code below.

```
npm install express dotenv ioredis mysql2
```
Then, we create a directory `/src` in our root folder and a file `redis.js` in the directory. Inside this file, we add the code below

```
import Redis from 'ioredis';
import mysql from 'mysql2';

export default class DataCache {
    constructor() {
        this.redis = new Redis();
        this.connection = mysql.createConnection({
            host: process.env.DB_HOST,
            user: process.env.DB_USER,
            password: process.env.DB_PASSWORD,
            database: process.env.DB_DATABASE,
        });
    }

    async getUserFromDB(id) {
        return new Promise((resolve, reject) => {
            this.connection.query(`SELECT * FROM users WHERE id = ${id}`, function (err, results) {
                if (err) {
                    reject(err);
                }
                resolve(results);
            });
        });
    }

    async getUser(id) {
        // session found in cache, send back to caller;
        let data = JSON.parse(await this.redis.get(`data:${id}`));
        if (!data) {
            // session not found in cache, fetch from the database
            data = await this.getUserFromDB(id);
            this.redis.setex(`data:${id}`, 60 * 60 * 1, JSON.stringify(data));
        }
        return data;
    }
}

```

Here, we define a class called `DataCache`. The class has a constructor that creates a connection to a Redis server and a MySQL server using the database credentials. The class has one method called `getUser()`, this method first checks if the data exist in the Redis server and returns it, if it does not exist, it retrieves the data from the MySQL server and store it in the Redis server for one hour before returning it.

Next, we create another file `index.js` in the `/src` directory. This would be the entry file of our API

```
import express from 'express';
import DataCache from './redis.js';
import env from 'dotenv';

env.config({path: process.env.ENV_FILE_PATH});
const app = express();

app.use(express.urlencoded({ extended: false }));
app.use(express.json());


// A middleware function to check if the user's session is cached in Redis
async function sessionMiddleware(req, res, next) {
    const dataCache = new DataCache();
    let id = "4";
    try {
        const userData = await dataCache.getUser(id);
        req.session = userData[0];
        next();
    } catch (err) {
        console.log(err);
        res.status(500).send("Error while trying to retrieve session from cache");
    }
}

// Use the middleware in a route
app.use("/login", sessionMiddleware, function (req, res) {
    // console.log(req.session);
    res.send(req.session.email + " Logged in");
});

app.listen(5000, console.log('Server is running...'))
```

Here, we would create a middleware function called `sessionMiddleware`. The function creates a new DataCache instance and uses its getUser method to get the user data by passing the user's id, which is hardcoded as 4 in this case. Typically, this id can be gotten by decoding the jwt token sent with in the authorization header.

Next, we run start server by running

```
npm start
```
We should get a `Server is running…` message logged on your console

Now, to test our application, we would make a GET request to the `/login` endpoint.

A comparison of the initial request, which queries the database for user information, shows a response time of 382 milliseconds..

![database response time](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n84ikptyv15c1lfsmzb7.png)

However, when the same request is sent again, the response time is significantly reduced to 22 milliseconds! This is a 17X improvement in speed!

![redis response time](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y5sxkqee9s9mvi34vsig.png)

By including the `sessionMiddleware` function in subsequent authenticated requests, user data will be retrieved from cache, which will make our API faster. 

## Conclusion

Redis is a powerful tool that can improve the performance of your application by caching frequently accessed data. This article provided a beginner's guide on how to use Redis for database caching, including how it works, benefits, and implementation steps. Redis should be used to complement your main data storage, not replace it. With the right approach, Redis can help to improve the performance of your application and user experience.