Cache trong nodejs với redis và test hiệu suất với benchmark

Nội dung bài viết

Caching in Node.js using Redis - Đã có nhiều bài viết nói về sự lợi hại của cache. Nhưng để chứng minh điều đó, thì họ lại không nói. Các bài viết thiên về SEO hơn chúng ta nghĩ. Và đây là bài viết của dân kỹ thuật, tôi sẽ chứng minh sức mạng của việc sử dụng cache.

Với những ai chưa biết về Redis thì đó là một tiếc nuối trong công việc của mình, đó là lời tôi nói thật. Redis là một cơ sở dữ liệu trong bộ nhớ mạnh mẽ và linh hoạt. Vì sao nó mạnh mẽ và linh hoạt thì tôi đã viết quá nhiều ở các bài viết giới thiệu về Redis rồi. Ở đây không nói nữa.

Nhưng nên nhớ khi sử dụng Redis thì có 3 vấn đề chính khi sử dụng redis mà bạn không thể quên được, nó có thể kiến bạn mất việc đấy.

Như thường lệ, tôi tóm tắt trước cho các bạn, để các bạn sẽ biết thêm được những gì ở bài viết này, không nữa mất công.

Bạn sẽ học được gì?

  • Cách install redis docker, nhanh gọn lẹ...
  • Cách sử dụng cache trong Node.js với Redis
  • Cách check hiệu suất sử dụng thư viện benchmark
  • Một số câu hỏi cho trình độ cao khi sử dụng redis.

Install redis docker

Tôi khuyên bạn nên sử dụng docker cho mỗi trường hợp demo như thế này.

Step 1: Get Image

AnonyStick$ docker run -p 6379:6379 -d --name redis-name redis:latest
Unable to find image 'redis:latest' locally
latest: Pulling from library/redis
69692152171a: Pull complete 
a4a46f2fd7e0: Pull complete 
bcdf6fddc3bd: Pull complete 
2902e41faefa: Pull complete 
df3e1d63cdb1: Pull complete 
fa57f005a60d: Pull complete 
Digest: sha256:7e2c6181ad5c425443b56c7c73a9cd6df24a122345847d1ea9bb86a5afc76325
Status: Downloaded newer image for redis:latest
11090f217b03d31c70b44f7b9e62e0f625d59307cfd81b73a0c4652815b73ff8

Step 2: Run redis in docker

AnonyStick$ docker exec -it redis-name sh
# redis-cli
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> 
127.0.0.1:6379> info server
# Server
redis_version:6.2.4
redis_git_sha1:00000000
redis_git_dirty:0
...

Ok, như vậy đã xong việc cài đặt redis với docker.

Mô hình cache như thế nào?

Tôi lấy hình ảnh trên internet và để dưới đây làm một ví dụ. Caching in nodejs with redis Các bạn nhìn vào thì sẽ thấy ở đây có 3 luồng cụ thể:

  • Trường hợp 1 nếu dữ liệu có trong cache rồi thì không lấy database nữa.
  • Trường hợp 2, dữ liệu không có không cache thì sẽ truy vấn tại database, và sau đó cập nhật lại cho cache
  • Trường hợp 3 là truy vấn lại key ở trường hợp 2, nhưng giờ đây đã có trong cache.

Hướng dẫn thiết lập cache redis với node.js

Step 1: Check redis đã PING hay chưa?

AnonyStick$ redis-cli
127.0.0.1:6379> 
127.0.0.1:6379> 
127.0.0.1:6379> ping
PONG

Thấy PONG là ok rồi.

Step 2: Create file index.js

const axios = require("axios");
const express = require("express");
const redis = require("redis");

const app = express();
const redisClient = redis.createClient(6379); // Redis server started at port 6379
const MOCK_API = "https://jsonplaceholder.typicode.com/users/";

// trường hợp truy vấn dữ liệu qua email thông qua database

app.get("/users", (req, res) => {
    const email = req.query.email;

    try {
        axios.get(`${MOCK_API}?email=${email}`).then(function (response) {
            const users = response.data;

            console.log("User successfully retrieved from the API");

            res.status(200).send(users);
        });
    } catch (err) {
        res.status(500).send({ error: err.message });
    }
});

// trường hợp truy vấn dữ liệu qua email thông qua cache

app.get("/cached-users", (req, res) => {
    const email = req.query.email;

    try {
        redisClient.get(email, (err, data) => {
            if (err) {
                console.error(err);
                throw err;
            }

            if (data) {
                console.log("User successfully retrieved from Redis");

                res.status(200).send(JSON.parse(data));
            } else {
                axios.get(`${MOCK_API}?email=${email}`).then(function (response) {
                    const users = response.data;
                    redisClient.setex(email, 600, JSON.stringify(users));

                    console.log("User successfully retrieved from the API");

                    res.status(200).send(users);
                });
            }
        });
    } catch (err) {
        res.status(500).send({ error: err.message });
    }
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
    console.log(`Server started at port: ${PORT}`);
});

Notes: Ở đây dữ liệu Users được lấy từ API, JSONPlaceholder.

Run nodejs

node index.js

Bạn chạy http://localhost:3000/usershttp://localhost:3000/cached-users nếu tinh ý bạn đã thấy sự khác biệt trong hai truy vấn đó. Có thể đối với dữ liệu ít thì nó cũng không mang lại lợi thế lắm, nhưng việc truy vấn đồng thời 100 truy vấn cùng một lúc, thì sẽ thấy hiệu suất nhanh chậm rõ ràng.

*Step 3: Check hiệu suất sử dụng api-benchmark, tạo file benchmark.js

var apiBenchmark = require("api-benchmark");
const fs = require("fs");

var services = {
  server1: "http://localhost:3000/",
};
var options = {
  minSamples: 100,
};

var routeWithoutCache = { route1: "users?email=Nathan@yesenia.net" };
var routeWithCache = { route1: "cached-users?email=Nathan@yesenia.net" };

apiBenchmark.measure(
  services,
  routeWithoutCache,
  options,
  function (err, results) {
    apiBenchmark.getHtml(results, function (error, html) {
      fs.writeFile("no-cache-results.html", html, function (err) {
        if (err) return console.log(err);
      });
    });
  }
);

apiBenchmark.measure(
  services,
  routeWithCache,
  options,
  function (err, results) {
    apiBenchmark.getHtml(results, function (error, html) {
      fs.writeFile("cache-results.html", html, function (err) {
        if (err) return console.log(err);
      });
    });
  }
);

Run benchmark.js

node benchmark.js

Các bạn sẽ thấy sau khi chạy benchmark.js trong project của bạn sẽ xuất hiện 2 file html đó là cache-results.htmlno-cache-results.html. Tương ứng với hai hình ảnh mà tôi đã chụp sau đây:

Sử dụng Cache Redis Caching in nodejs with redis

No Cache Redis Caching in nodejs with redis

nhìn vào hai hình ảnh đó bạn thấy khi sử dụng cache redis thì thời gian chỉ 1 second ngược lại không sử dụng cache mất đến 11 seconds.

Tóm lại

Các bạn nên Clone git source về chạy xem, có nhiều điều trong bài viết này bạn nên thành thạo như việc sử dụng docker, cách sử dụng thư viện benchmark để test các trường hợp sau này.

Ref: appsignal.com

Có thể bạn đã bị missing