*Redis和NodeJS缓存入门指南

*通过缓存到Redis来加速NodeJS应用程序

近年来,Redis已成为Node.js应用程序栈中的常客。尽管Redis最受欢迎的用例是缓存,但是Redis还有许多其他用例,比如快速的内存数据库。

在本教程中,我们将为您快速介绍Redis。我们还将使用Redis为Node应用程序创建一个简单的缓存,以了解它如何影响其性能。

*特色图片

*什么是Redis?

Redis是开放源代码(BSD许可)的内存中数据结构存储,用作数据库,缓存和消息代理。

您可以将其视为No-SQL数据库,该数据库将数据作为键值对存储在系统内存中。如果需要,Redis也支持磁盘持久数据存储。

Redis支持存储多种数据结构和数据类型 ,包括字符串,列表,哈希,集合和排序集合。受支持的数据结构使Redis在许多用例中都具有多功能性。

在需要在最短时间内检索数据并将其交付给客户端的情况下,Redis是最佳选择。


*Redis用例

*Redis缓存

Redis最受欢迎的用例之一是缓存。

什么是缓存?

缓存是将数据副本存储在缓存中以允许应用程序更快地访问和检索数据的过程。缓存的目的是比数据库或远程服务器所允许的速度更好地加快数据访问操作。昂贵的(及时的)操作尤其如此。

作为后端开发人员,我们的任务是尽快完成客户的请求。有时,查询需要执行多项操作,例如从数据库中检索数据,执行计算,从其他服务中检索其他数据等,这些操作都会降低我们的性能。

在这里缓存非常出色,因为我们可以处理一次数据,将其存储在缓存中,然后稍后直接从缓存中检索数据,而无需执行所有那些昂贵的操作。然后,我们将定期更新缓存,以便用户可以查看更新的信息。

缓存和Redis

由于Redis是内存数据库,因此它的数据访问操作比任何其他磁盘绑定数据库可以提供的速度都要快。它使Redis成为缓存的理想选择。它的键值数据存储是另一个优点,因为它使数据存储和检索更加简单。

在本教程中,我们将看到如何使用Redis和Node.js进行缓存。

*Redis实时分析

Redis承诺进行亚毫秒级的长时间数据处理操作。它使Redis成为依赖实时数据分析的应用程序的理想之选。

例如,在实施实时欺诈检测服务时,可以使用Redis存储用户身份及其交易详细信息。Redis甚至提供了AI支持的更快的交易评分系统和更快的统计模型,以更好地执行此用例。

实时分析中的其他用例包括实时库存管理系统和游戏排行榜。

*Redis用于会话管理

如果您的应用程序使用会话来跟踪经过身份验证的用户并管理特定于用户的数据,则Redis非常适合用作会话存储。使用Redis可以显着提高系统性能,同时使处理用户数据(包括凭据,最近的活动,甚至是购物车之类的系统)更加容易。

*Redis作为队列

您可以使用Redis将需要很长时间才能完成的应用程序任务排队。您可以实施FIDO(先进先出)队列,也可以创建延迟的队列以将任务实施延迟到预定的时间。


*使用Node和Redis进行缓存

现在,让我们从本教程的主要重点开始:使用Redis在NodeJS应用程序中进行缓存。

使用Redis进行缓存的过程非常简单。当我们收到对启用了缓存的路由的用户请求时,我们首先检查所请求的数据是否已经存储在缓存中。如果是,我们可以快速从Redis检索数据并发送响应。

但是,如果数据没有存储在高速缓存中(我们称其为高速缓存未命中),则必须首先从数据库或外部API中检索数据,然后将其发送给客户端。我们还确保将检索到的数据存储在缓存中,以便下次收到相同的请求时,我们可以简单地将缓存的数据更快地发送给用户。

现在,您对我们将要做什么有了一个清晰的想法,让我们开始实施。


*安装Redis

如果尚未安装,则需要为本教程安装Redis。

您可以使用以下命令下载二进制文件并轻松编译它们。

wget https://download.redis.io/releases/redis-6.0.9.tar.gz
tar xzf redis-6.0.9.tar.gz
cd redis-6.0.9
make
make install

要确保Redis服务器正常运行,请使用来向服务器发送ping命令redis-cli

redis-cli ping

如果收到pong响应,则Redis服务器正在成功运行。

如果出现问题,请阅读官方的快速入门指南以获取更好的主意。


*生成NodeJS应用程序

*基本设置

像这样为Node应用程序设置初始样板。

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

app.listen(process.env.PORT || 3000, () => {
    console.log("Node server started");
});

请注意,我们如何使用另外两个名为axios和的软件包redisredis是Node的标准Redis客户端。axios在本教程中,我们用于从外部API检索数据。

在继续之前,请确保使用npm安装这两个软件包。

npm install axios redis --save

*从外部API检索数据

我们将使用GitHub Jobs API 来获取与世界各地不同位置的编程工作相关的数据。

您可以将与您要查找的工作相关的搜索词传递给API,并以json格式检索一系列可用的工作。对API的示例请求如下所示。

https://jobs.github.com/positions.json?search=node.js

img

POSTMAN-GitHub Jobs API结果

在我们的Node应用程序中,我们定义了一个名为的路由/jobs,该路由从上述API中检索作业数据并将其发送回客户端。

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

app.get("/jobs", async (req, res) => {
    const searchTerm = req.query.search;
    try {
        const jobs = await axios.get(`https://jobs.github.com/positions.json?search=${searchTerm}`);
        res.status(200).send({
            jobs: jobs.data,
        }); 
    } catch(err) {
        res.status(500).send({message: err.message});
    }
});

app.listen(process.env.PORT || 3000, () => {
    console.log("Node server started");
});

在这里,我们使用axios带有用户提供的搜索词的GET请求发送到GitHub Jobs API。

让我们看看现在使用Postman的路线是如何工作的。

img

邮递员-我们的API结果

*缓存结果

现在,让我们看看如何通过缓存来提高应用程序的性能。

首先,我们需要通过我们的应用程序连接到Redis服务器。我们使用已安装的redis软件包来完成此任务。

const redisPort = 6379
const client = redis.createClient(redisPort);

//log error to the console if any occurs
client.on("error", (err) => {
    console.log(err);
});

Redis服务器默认侦听端口6379。因此,我们传递端口号以连接到Redis并创建一个客户端。

然后,实现逻辑以从高速缓存存储和检索数据。

app.get("/jobs", (req, res) => {
    const searchTerm = req.query.search;
    try {
        client.get(searchTerm, async (err, jobs) => {
            if (err) throw err;

            if (jobs) {
                res.status(200).send({
                    jobs: JSON.parse(jobs),
                    message: "data retrieved from the cache"
                });
            } else {
                const jobs = await axios.get(`https://jobs.github.com/positions.json?search=${searchTerm}`);
                client.setex(searchTerm, 600, JSON.stringify(jobs.data));
                res.status(200).send({
                    jobs: jobs.data,
                    message: "cache miss"
                });
            }
        });
    } catch(err) {
        res.status(500).send({message: err.message});
    }
});

这里发生了什么?

当我们接收到/ jobs路由的客户请求时,首先,我们获得了带有该请求的查询参数的搜索词。

const searchTerm = req.query.search;

然后,我们尝试通过传递搜索词来从缓存中检索请求的数据,在将数据存储到缓存中时,我们将其用作关键字。由于Redis软件包没有对Promise的本机支持,因此我们必须传递一个回调来处理检索到的数据。

client.get(searchTerm, async (err, jobs) => {
    if (err) throw err;
});

如果从Redis返回的值不为null,则意味着相关数据存在于缓存中,因此很容易在响应中返回该数据。只需确保将字符串回退为JSON。

if (jobs) {
    res.status(200).send({
        jobs: JSON.parse(jobs),
        message: "data retrieved from the cache"
    });
}

如果返回的值为null,则必须向外部API发送请求以检索相关数据。

else {
    const jobs = await axios.get(`https://jobs.github.com/positions.json?search=${searchTerm}`);
     client.setex(searchTerm, 600, JSON.stringify(jobs.data));
     res.status(200).send({
          jobs: jobs.data,
          message: "cache miss"
     });
}

当我们从API获取数据时,在将其发送回之前,我们将其存储在Redis中,以便下次将同一请求发送到Node服务器时,它可以使用存储在缓存中的数据进行响应,而不是从API请求它们。

注意我们如何使用该setex函数将数据存储在缓存中。setex专门使用该函数而不是常规set函数,我们可以为存储的键值对设置过期时间。因为我们为到期时间设置了一个值,所以当经过的时间到期时,Redis会自动从缓存中删除该键值对。


*完整的源代码

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

const redisPort = 6379
const client = redis.createClient(redisPort);

client.on("error", (err) => {
    console.log(err);
})

app.get("/jobs", (req, res) => {
    const searchTerm = req.query.search;
    try {
        client.get(searchTerm, async (err, jobs) => {
            if (err) throw err;

            if (jobs) {
                res.status(200).send({
                    jobs: JSON.parse(jobs),
                    message: "data retrieved from the cache"
                });
            }
            else {
                const jobs = await axios.get(`https://jobs.github.com/positions.json?search=${searchTerm}`);
                client.setex(searchTerm, 600, JSON.stringify(jobs.data));
                res.status(200).send({
                    jobs: jobs.data,
                    message: "cache miss"
                });
            }
        });
    } catch(err) {
        res.status(500).send({message: err.message});
    }
});

app.listen(process.env.PORT || 3000, () => {
    console.log("Node server started");
});

而已。我们为应用程序创建了一个简单的缓存。那不是那么难,不是吗?


*关键时刻:时间比较

我们将看到缓存的使用如何影响应用程序的性能。我使用Postman将请求发送到服务器,并衡量请求的完成时间。

img

性能

第一次使用新的搜索字词向服务器发送请求时,应用程序需要更长的响应时间(超过7秒),因为它必须从外部API获取数据。第二次您发出相同的请求时,由于结果已经存在于缓存中,因此服务器响应速度更快。

该请求在10毫秒内完成。与我们之前没有缓存的应用程序相比,这是一个巨大的性能提升。


*概要

在本教程中,我们为您快速介绍了Redis,并使用它为Node.js应用程序创建了一个简单的缓存。现在,您可以使用Redis在应用程序中缓存经常查询的数据,从而获得可观的性能提升。

您还可以研究在其他用例中如何利用Redis的最佳功能。

来源:https://livecodestream.dev/post/beginners-guide-to-redis-and-caching-with-nodejs/