优秀的编程知识分享平台

网站首页 > 技术文章 正文

只需4步使用Redis缓存优化Node.js应用

nanyue 2024-08-18 19:52:52 技术文章 7 ℃

介绍

通过API获取数据时,会向服务器发出网络请求,收到响应数据。但是,此过程可能非常耗时,并且可能会导致程序响应时间变慢。

我们使用缓存来解决这个问题,客户端程序首先向API发送请求,将返回的数据存储在缓存中,之后的请求都从缓存中查找数据,而不是向API发送请求。

在本文中,使用 Redis做为缓存, 在 Node.js 的程序中通过4步实现数据缓存的机制。

第 1 步 — 设置项目

在此步骤中,我们将安装该项目所需的依赖项并启动 Express 服务器。

首先,为项目创建目录:

mkdir app

进入目录:

cd app

初始化项目:

npm init -y

它将创建`package.json`包含以下内容的文件:

{

"name": "app",

"version": "1.0.0",

"description": "",

"main": "index.js",

"scripts": {

"test": ""

},

"keywords": [],

"author": "",

"license":"ISC"

}


接下来,使用以下命令安装express,redis,axios库:

npm install express redis axios

创建`index.js`文件,并输入以下代码:

const express = require("express");

const app = express();

const port = process.env.PORT || 3000;


app.listen(port, () => {

console.log(`App listening on port ${port}`);

});


保存并运行以下命令:

node index.js

输出如下:

步骤 2 — 通过API获取数据

在刚才的index.js中增加从API获取数据的部分:

const express = require("express");

const app = express();

const port = process.env.PORT || 3000;


async function fetchDataFromApi(userId) {

let apiUrl = 'https://xxxx/api';

if (characterId) {

apiUrl = `${apiUrl}/user/${userId}`;

} else {

apiUrl = `${apiUrl}/user`;

}


const apiResponse = await axios.get(apiUrl);

console.log("发送API请求");


return apiResponse.data;

}


app.get("/user/:id", async (req, res) => {

try {

const character = await fetchDataFromApi(req.params.id);

if (!character.length) {

throw new Error("请求异常");

}


return res.status(200).send({

fromCache: false,

data: character,

});

} catch (error) {

console.log(error);

res.status(404).send("请求异常");

}

});


app.get("/user", async (req, res) => {

try {

const characters = await fetchDataFromApi();

if (!characters.length) {

throw new Error("请求异常");

}


return res.status(200).send({

fromCache: false,

data: characters,

});

} catch (error) {

console.log(error);

res.status(404).send("请求异常");

}

});

app.listen(port, () => {

console.log(`App listening on port ${port}`);

});


运行 node index.js 启动服务器,之后打开 Postman 发送请求/user, 请求耗时 885 毫秒。为了加快请求速度,我们增加 Redis 缓存。

第 3 步 — 增加 Redis 缓存

增加缓存,只有初始访问才会从API请求数据,所有后续请求都从缓存中获取数据。

在项目中导入redis模块:

const redis = require ( "redis" );

添加以下代码连接到Redis:

let redisClient;

(async () => {

redisClient = redis.createClient();

redisClient.on("error", (error) => console.error(`Error : ${error}`));

await redisClient.connect();

})();


使用redisClient.get()从缓存中获取数据。如果数据存在,我们将isCached设置为 true 并分配cachedResult给result,如果cachedResult为空,则我们调用API获取数据,然后使用redisClient.set()设置到缓存中。

const redisKey = "user";

let results;

let isCached = false;

const cachedResult = await redisClient.get(redisKey);

if (cachedResult) {

isCached = true;

results = JSON.parse(cachedResult);

} else {

results = await fetchDataFromApi();

if (!results.length) {

throw new Error("请求异常");

}


await redisClient.set(redisKey, JSON.stringify(results));

}

保存并运行以下命令:

node index.js


服务启动后,我们通过Postman发送请求,发现第一次请求比较慢,后边的请求速度都变快了,从868毫秒缩短到14毫秒。

到目前为止,我们可以从 API 获取数据,并把数据设置到到缓存中,后续请求从缓存中取数据。

为了防止API端数据变化,但是缓存数据没变的情况,还需要设置缓存有效性。

第 4 步 — 设置缓存有效性

当缓存数据时,要设置合适的过期时间,具体时间可以根据业务情况决定。

在本文中,将缓存持续时间设置为120秒。

在index.js中增加以下内容:

await redisClient.set(redisKey, JSON.stringify(results), {

EX: 120,

NX: true,

});


  • EX:缓存有效时间(单位:秒)。
  • NX:当设置为时true,set()方法只设置 Redis 中不存在的键。

把以上代码添加到API接口中:

```

app.get("/user/:id", async (req, res) => {

try {

const redisKey = `user-${req.params.id}`;


results = await fetchDataFromApi(req.params.id);

if (!results.length) {

throw new Error("请求异常");

}


await redisClient.set(redisKey, JSON.stringify(results), {

EX: 120,

NX: true,

});


return res.status(200).send({

fromCache: isCached,

data: results,

});

} catch (error) {

console.log(error);

res.status(404).send("请求异常");

}

});


app.get("/user", async (req, res) => {

try {

const redisKey = "user";


results = await fetchDataFromApi();

if (!results.length) {

throw new Error("请求异常");

}


await redisClient.set(redisKey, JSON.stringify(results), {

EX: 120,

NX: true,

});


return res.status(200).send({

fromCache: isCached,

data: results,

});

} catch (error) {

console.log(error);

res.status(404).send("请求异常");

}

});


app.listen(port, () => {

console.log(`App listening on port ${port}`);

});

现在创建一个中间件,从缓存中获取数据:

async function cacheData(req, res, next) {

try {

const characterId = req.params.id;

let redisKey = "user";


if (characterId) {

redisKey = `user-${req.params.id}`;

}


const cacheResults = await redisClient.get(redisKey);

if (cacheResults) {

res.send({

fromCache: true,

data: JSON.parse(cacheResults),

});

} else {

next();

}

} catch (error) {

console.error(error);

res.status(404);

}

}

把cacheData加入到API调用中

app.get("/user/:id", cacheData, async (req, res) => {

try {

const redisKey = `user-${req.params.id}`;

results = await fetchDataFromApi(req.params.id);


if (!results.length) {

throw new Error("请求异常");

}


await redisClient.set(redisKey, JSON.stringify(results), {

EX: 120,

NX: true,

});


return res.status(200).send({

fromCache: false,

data: results,

});

} catch (error) {

console.log(error);

res.status(404).send("请求异常");

}

});


app.get("/user", cacheData, async (req, res) => {

try {

const redisKey = "user";

results = await fetchDataFromApi();

if (!results.length) {

throw new Error("请求异常");

}


await redisClient.set(redisKey, JSON.stringify(results), {

EX: 120,

NX: true,

});


return res.status(200).send({

fromCache: false,

data: results,

});

} catch (error) {

console.log(error);

res.status(404).send("请求异常");

}

});

当访问API时/user,cacheData()首先执行。如果数据被缓存,它将返回响应。如果在缓存中没有找到数据,则会从API请求数据,将其存储在缓存中,并返回响应。

再次利用Postman来验证接口,发现响应时间只有15毫秒左右。

总结

在本文中,我们构建了一个Node.js程序,该程序 API 获取数据并使用Redis进行缓存,只有初次请求和缓存过期后才从API获取数据,之后的请求都从缓存中获取数据,大大缩短请求所用的时间。

最近发表
标签列表