使用Redis在Node.js中实现缓存
缓存是指将数据存储在一个临时的位置,以便用最少的资源来访问这些数据。缓存的目的是减少通过网络发送数据的带宽成本和应用程序的响应时间。实施缓存的应用程序速度更快,对用户更友好。
前提条件
要跟上这篇文章,最好能有以下条件。
- 在你的电脑上安装[Node.js]。
- 对JavaScript的工作知识。
- 对Node.js和[Express.js]的工作知识。
- 在你的电脑上安装[Postman]。
- 基于Linux或macOS的操作系统。
应用概述
在这篇文章中,我们将通过在Node.js应用中使用redis作为缓存的步骤来实现缓存。我们将使用Express.js框架实现一个REST API。我们将向recipe labs api发出请求。这是一个公共API,用于访问不同食品的食谱。
设置应用程序
该仓库有两个目录,开始和最终目录。在整个文章中,我们将在开始目录下工作,但如果你遇到错误,请随时查看最终目录。
为了安装必要的依赖,在你克隆的文件夹中执行以下命令。
cd ./start && npm install
我们的主要重点将是实现位于controllers/recipe.js 文件中的fetchFoodItem 函数。它处理recipe/:foodItem 路线的逻辑。
从配方实验室的API中获取数据
为了从API中获取数据,我们。
- 在
controllers/recipe.js文件中导入axios模块。
const axios = require("axios");
- 修改
fetchFoodItem函数,如下所示。
const fetchFoodItem = async (req, res, next) => {
try {
//destructure the foodItem from params.
let { foodItem } = req.params;
//fetch the data.
const recipe = await axios
.get(`http://www.recipepuppy.com/api/?q=${foodItem}`)
.catch(console.log);
//return a response.
return res.send({
success: true,
message: recipe.data.results,
});
} catch (err) {
//return the error
return res.send({
success: false,
message: err,
});
}
};
从上面开始。
- 从请求对象中获取食物项目。
- 从公共API中获取数据。
- 发送数据给客户端。
为了测试这个,请按照以下步骤进行。
-
通过运行:
npm run dev,从你的终端启动开发服务器。 -
前往Postman,向路由发送一个请求。不要包括分号。该请求应该类似于。
http://localhost:3000/recipe/coffee.随意用你的喜好来替换咖啡。 -
等待响应,然后检查右上角的时间。通常情况下,它将需要大约600毫秒或更多。这个时间量意味着我们的应用程序正在消耗大量的用户网络带宽。为了尽量减少这一成本,我们必须设置
caching。
在这篇文章中,我们将使用redis.
安装redis
如果你已经安装了redis ,请随意进入下一个步骤。否则,请按照下面的步骤进行。
- 在你的终端中打开一个单独的标签,并运行以下命令,转移到你的主目录。
cd
- 在你的主目录下,逐一运行以下命令。
wget http://download.redis.io/redis-stable.tar.gz
tar xvzf redis-stable.tar.gz
cd redis-stable
make
sudo make install
- 为了确认安装,运行以下命令,启动
redis server。
redis-server
- 如果服务器启动成功,继续进行下一步。
导入和配置redis
按照下面的步骤进行。
- 在
controllers/recipe.js文件中导入redis模块。
const redis = require("redis");
- 在
controllers/recipe.js文件中配置redis端口和错误处理。
const client = redis.createClient({
port: 6379,
});
client.on("error", (error) => console.error(error));
设置redis
在我们的函数中纳入redis ,应涉及。
-
检查从参数中发送的食品记录是否存在于缓存中,因为它将被视为一个关键。
-
如果记录存在,从缓存中向客户端发送数据。
-
如果数据不存在于缓存中,则从API中获取数据,在缓存中保存数据,并将数据发送给客户端。
为了设置redis ,我们修改了fetchFoodItem 函数,如下所示。
const fetchFoodItem = async (req, res, next) => {
try {
//get the food item.
let { foodItem } = req.params;
//check the data on redis store.
client.get(foodItem, async (_, recipe) => {
if (recipe) {
//send the response from cache
return res.send({
success: true,
message: JSON.parse(recipe),
meta_data: "from cache",
});
} else {
//fetch the data.
const recipe = await axios
.get(`http://www.recipepuppy.com/api/?q=${foodItem}`)
.catch(console.log);
//set the data on cache
client.set(foodItem, JSON.stringify(recipe.data.results));
//send the response
return res.send({
success: true,
message: recipe.data.results,
meta_data: "from server",
});
}
});
} catch (err) {
return res.send({
success: false,
message: err,
});
}
};
从上面的片段中。
-
从请求对象中获取食物项目。
-
检查它的记录是否存在于缓存中,如果存在,我们从那里将数据发送到客户端。如果不存在,我们从API中获取数据,将其设置为缓存,然后将其发送给客户端。
-
这里的一个重要启示是,当把数据设置到缓存中时,我们必须把它转换为
string。当从缓存中获取数据时,我们必须parse,把它转换为原始形式。
为了测试上述代码。
-
确保开发服务器已经启动并运行。
-
前往Postman并发送一个类似于以下的请求。
http://localhost:3000/food/coffee.随意用你的喜好来替换咖啡。 -
等待响应,并观察它获得响应所需的时间。在这个过程中,它已经将数据保存在缓存中,因为它没有被保存。
-
再次发送同样的请求。这一次,获得响应的时间将大大减少。这是因为响应是从缓存中访问的。使用的网络带宽也会减少。
实施缓存时的考虑因素
以下是在实施缓存时需要考虑的重要因素。
- 数据更新的频率:如果数据没有被定期更新,那么你使用之前的实现是安全的。否则,如果数据经常更新,你将需要设置数据在缓存中的可用时间。
考虑到我们的实现,我们可以将数据设置为只缓存24分钟。你必须将你的时间转换为秒。
在你设置缓存数据的那一行,用下面这行代码来代替它。
client.setex(foodItem, 1440, JSON.stringify(recipe.data.results));
- 键的唯一性:当键值相似时,缓存将存储不合适的数据。为了保证不得到类似的键,你必须对它们进行哈希处理。
在我们的fetchFoodItem 函数中做如下修改,以支持键的散列。
const fetchFoodItem = async (req, res, next) => {
try {
//get the food item.
let { foodItem } = req.params;
//hash the key.
let hashKey = new Buffer.from(`${foodItem}`).toString("base64");
//check the data on redis store.
client.hget(hashKey, foodItem, async (_, recipe) => {
if (recipe) {
//send the response from cache
return res.send({
success: true,
message: JSON.parse(recipe),
meta_data: "from cache",
});
} else {
//fetch the data.
const recipe = await axios
.get(`http://www.recipepuppy.com/api/?q=${foodItem}`)
.catch(console.log);
//set the data on cache
client.hset(hashKey, foodItem, JSON.stringify(recipe.data.results));
//set the duration of cache.
client.expire(hashKey, 1440);
//send the response
return res.send({
success: true,
message: recipe.data.results,
meta_data: "from server",
});
}
});
} catch (err) {
return res.send({
success: false,
message: err,
});
}
};
从上面。
-
从请求对象中获取食物项目。
-
对作为键的食品项目进行散列。
-
检查其记录是否存在于缓存中。如果它存在,我们从缓存中把它发送给客户端。如果不存在,我们从API中获取它,将其保存到缓存中,然后将其发送给客户端。
要测试这个。
-
确保开发服务器正在运行。
-
前往Postman并发送一个类似于以下的请求。
http://localhost:3000/recipe/coffee.可以根据你的喜好随意改变咖啡。 -
发送该请求。
-
由于这是你在散列后的第一个请求,它将保存数据,然后当你再次发送相同的请求时,它将从缓存中获取数据。数据被配置为在缓存中停留24分钟。
-
缓存在每个查询中:在某些情况下,如授权,缓存可能是不可取的,因为数据会迅速更新。实时通信机制也不需要缓存。
总结
缓存在改善应用程序的用户体验方面有很大作用。它使用户能够在较短的响应时间内,用较少的网络带宽访问数据。在实施缓存时,软件开发者应该牢记上面讨论的关键因素。
在这篇文章中,我们介绍了如何在Node.js REST API上实现缓存,使用recipe labs API作为我们的数据源,Redis作为缓存。