1)在你的Node.js应用程序中实现缓存
通过这篇简短的介绍性文章,我想提到如何使用Redis在Node.js应用程序中实现缓存,以及我们的应用程序如何从性能中受益。
2)什么是缓存及其对我们有何帮助?
简而言之,我们可以说高速缓存是将数据临时存储在存储组件区域以便更快地用于未来的过程。 例如。 如果我们有一些来自第三方API的数据,并且这些数据不会在“不久的将来”更改,则可以在检索到数据后将它们存储在缓存中,并避免不必要的服务调用。 这样,我们就不必等待API调用完成了,因为我们已经有了它们,我们可以从缓存中检索它们。 这将使我们的应用程序更快,性能更高。什么是Redis?
Redis是一个高性能的开源NoSQL数据库,主要用作各种类型的应用程序的缓存解决方案。 令人惊讶的是,它将所有数据存储在RAM中,并保证了高度优化的数据读写。 在开始描述如何在Node.js应用程序中实现缓存之前,让我们首先看看http://Redis.io如何定义其数据库。
Redis是一个开放源代码(BSD许可)的内存中数据结构存储,用作数据库,缓存和消息代理。 它支持数据结构,例如字符串,哈希,列表,集合,带范围查询的排序集合,位图,超日志,带有半径查询和流的地理空间索引。 Redis具有内置的复制,Lua脚本,LRU逐出,事务和不同级别的磁盘持久性,并通过Redis Sentinel和Redis Cluster自动分区提供了高可用性。
3)我们将执行什么
今天,我将在向第三方API请求数据的Node.js应用程序上实现一种非常简单的缓存机制。 更具体地说,我将使用GitHub的API来获取用户的公共存储库的数量。 因此,让我们开始吧。
Redis设置
如果你的本地计算机上已经安装了Redis,或者你正在使用Redis云解决方案,则可以跳过此步骤。
在Windows上安装Redis
如果你是Windows用户,则可以从http://redislabs.com查看此简短指南,以便在Windows上开始使用Redis。 Redis的安装过程不是本文的目的,因此在此我将不再赘述。
在Mac上安装Redis
可以使用Homebrew在Mac上安装Redis。 如果Mac上未安装Homebrew,则可以在终端上运行以下命令进行安装。
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
安装Homebrew后,可以使用此命令安装Redis。
brew install redis
在Linux上安装Redis
Starting Redis Server and Redis CLI
还可以从http://digitalocean.com上获得关于如何在Linux机器上安装Redis的简短指南,该指南非常容易理解,请查看。
redis-server
使用第二个命令启动Redis CLI也是如此简单。
redis-cli
4)项目设置
如前所述,我们将创建一个简单的Node.js应用程序,该应用程序将通过GitHub API检索GitHub用户的公共存储库数量。
首先,我们需要为Node.js应用程序创建一个新文件夹。 之后,我们可以通过在命令提示符下键入以下命令来初始化应用程序,以创建默认的package.json文件。
npm init -y
或者,我们可以运行npm init并按照指南根据需要初始化package.json文件。
之后,我们将生成一个package.json文件,该文件将类似于以下文件。
{
"name": "nodejs-redis-cache-example",
"version": "1.0.0",
"description": "A demo application showing how to use redis to cache node.js web application",
"main": "index.js",
"scripts": {
"start": "nodemon index.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/atheodosiou/nodejs-redis-cache-example.git"
},
"keywords": [
"node.js",
"redis",
"cache",
"tutorial"
],
"author": "Anastasios Theodosiou",
"license": "MIT",
"bugs": {
"url": "https://github.com/atheodosiou/nodejs-redis-cache-example/issues"
},
"homepage": "https://github.com/atheodosiou/nodejs-redis-cache-example#readme",
}
5)安装依赖项
我们将继续通过运行npm i安装所有必需的依赖项。 在本文中,我将使用三个依赖项,并使用下一个命令安装它们。
npm i --save express node-fetch redis
· ·Express:如npm所述,express是Node的一种快速,不受质疑的,极简的Web框架。 你可以在这里找到更多。
· ·Node-fetch:一个轻量级的模块,将Node.js的window.fetch引入。 你还可以在npm上找到更多信息。
·Redis:同样,来自npm,Redis是Node的完整且功能丰富的Redis客户端。 它支持所有Redis命令,并专注于高性能。
6)安装开发依赖
为了不必手动刷新我们的开发服务器,我们将为开发安装一个额外的依赖项。 它称为nodemon。
npm i -D nodemon
· Nodemon:每年,Nodemon是一个工具,可在检测到目录中的文件更改时通过自动重新启动应用程序来帮助开发Node应用程序,在这里找到更多
6)创建一个启动脚本
安装完所有必需的依赖项后,我们可以在pacakge.json文件中创建一个启动脚本,以帮助我们使用nodemon启动应用程序。 因此,在package.json文件中,创建一个如下所示的新脚本。
"start": "nodemon index.js"
index.js文件是我们应用程序的起点。 下一步是通过运行touch index.js在与package.json文件相同的文件夹中创建此文件。 之后,我们的package.json文件应如下所示:
{
"name": "nodejs-redis-cache-example",
"version": "1.0.0",
"description": "A demo application showing how to use redis to cache node.js",
"main": "index.js",
"scripts": {
"start": "nodemon index.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/atheodosiou/nodejs-redis-cache-example.git"
},
"keywords": [
"node.js",
"redis",
"cache",
"tutorial"
],
"author": "Anastasios Theodosiou",
"license": "MIT",
"bugs": {
"url": "https://github.com/atheodosiou/nodejs-redis-cache-example/issues"
},
"homepage": "https://github.com/atheodosiou/nodejs-redis-cache-example#readme",
"dependencies": {
"express": "^4.17.1",
"node-fetch": "^2.6.0",
"redis": "^2.8.0"
},
"devDependencies": {
"nodemon": "^1.19.4"
}
}
7)添加应用逻辑
此时,我们可以开始实现我们的应用程序了。 我们首先为程序包声明三个变量并导入它们。
//Import packages
const express = require("express");
const fetch = require("node-fetch");
const redis = require("redis");
下一步是创建一个.env文件,其中将包含我们的服务器和Redis客户端的端口号。
//Declare express server port and redis client port
const PORT = process.env.PORT || 3000;
const REDIS_PORT = process.env.REDIS_PORT || 6379;
上面的代码检查环境变量是否存在。 否则,它将设置默认值。 要使用这些变量而无需更多服务器自定义,我们可以使用另一个名为dotenv的dev依赖项。 从那里,我们可以使用以下命令安装它:
npm i -D dotenv
现在,我们可以将服务器设置为侦听所需的端口,如下所示。
app.listen(PORT, () => {
console.log(`App listening on port ${PORT}...`);
});
此时,我们的index.js文件应类似于以下代码块:
//Import packages
const express = require("express");
const fetch = require("node-fetch");
const redis = require("redis");
//Declare express server port and redis client port
const PORT = process.env.PORT || 3000;
const REDIS_PORT = process.env.REDIS_PORT || 6379;
app.listen(PORT, () => {
console.log(`App listening on port ${PORT}...`);
});
我们可以通过执行npm run start命令来验证我们的应用程序是否正常运行; 我们应该在终端中看到以下输出。
开发服务器输出
8)创建一个Redis客户端和Express应用
创建开发服务器之后,必须创建Redis客户端和Express应用程序。 我们可以使用以下代码来实现。
//Create Redis client on Redis port
const redisClient = redis.createClient(REDIS_PORT);
//Create an app const by excecuting express like a function
const app = express();
注册路由和添加处理程序
接下来,我们需要创建一条路由,服务器将在该路由中侦听并响应GitHub用户的公共存储库总数。 为此,我们将添加一些新的代码行。
app.get("/repos/:username", cache, getPublicReposNumber);
这意味着当我们定位到http:// localhost:3000 / repos / atheodosiou时,服务器将触发关联的处理程序向我们发送响应。 该处理程序是一个名为getPublicReposNumber的回调函数。
8)回调功能
在这一点上,我们将尝试请求GitHub的公共API来获取数据
//Make request to GitHub for data
async function getPublicReposNumber(req, res, next) {
try {
console.log("Fetching data...");
const { username } = req.params;
const response = await fetch(`https://api.github.com/users/${username}`);
const data = await response.json();
//set to redis
redisClient.setex(username, 3600, data);
res.status(200).send(setResponse(username, data));
} catch (error) {
console.error(error);
req.status(500).json({ error: error });
}
}
如你所见,我们正在获取数据,并将其作为响应发送回客户端。 在这一点上,我们没有使用缓存机制,而是在使用Redis客户端来存储检索到的数据。 这是在上述代码块的第11行上实现的。
我们使用Redis驱动程序的setx方法,该方法允许我们为存储的数据设置过期时间。 在我们的例子中,我们将其设置为3600 /秒,即一小时。
9)实施缓存机制
为了最大化我们的应用程序性能,我们将实现一个缓存中间件,该中间件将在请求新数据之前在Redis本地服务器上搜索密钥。 这就是我们在Node.js应用程序中创建缓存的方式。
我想提一下,这不是实现缓存的唯一方法。 它可能取决于其他应用程序逻辑或你的首选项,但是,本教程是向你展示Redis如何在Node.js应用程序上工作的好方法。
在添加缓存中间件之前,让我们运行我们的应用程序并检查服务请求所花费的总时间。
没有缓存的总执行时间
在不使用高速缓存的情况下,这是一秒钟的正常响应时间。 让我们看看如果添加Redis缓存中间件将会如何。
正如我们已经提到的,下一步是创建一个缓存机制,以将检索到的数据存储“一会儿”,并避免不必要的API调用。
注意! 仅当我们将要接收的数据频繁更改时,才建议使用缓存。 例如,如果我们调用的API的调用数据可能会发生变化,那么使用缓存就不合适了。
在我们的示例中,我们的缓存中间件将是在请求数据之前调用的函数。
//Cache midleware
function cache(req, res, next) {
const { username } = req.params;
redisClient.get(username, (error, cachedData) => {
if (error) throw error;
if (cachedData != null) {
res.send(setResponse(username, cachedData));
} else {
next();
}
});
}
该函数正在从Redis服务器中请求一个密钥(在我们的示例中为GitHub用户名),以获取该密钥的缓存数据。 如果找不到密钥,则通过从GitHub API询问数据来继续请求。
为了启用此机制,我们必须将其添加到如下所示的请求处理程序之前的路由中。
app.get("/repos/:username", cache, getPublicReposNumber);
现在,让我们使用npm run start命令再次运行该应用程序。 (请注意请求的总时间。)
10)实施缓存后的请求时间
我们可以看到使用缓存时有很大的不同。 仅花费了4毫秒,而没有它则花费了1秒。 原因是我们之前已经检索过此数据,并且已将它们以Redis作为键值对存储在内存中。 每次我们调用此终结点直到1小时,服务器都不会向GitHub API发出真正的请求,而是会为我们提供它在内存中的数据。
我们用于Redis密钥的到期时间因一个应用程序而异于另一个应用程序,并且它包含多个条件。 随意尝试一下。
从上面的示例可以看出,使用缓存可能对我们的应用程序有益。 Redis速度非常快; 它是一个NoSQL数据库,为了节省你的云数据库调用并最终节省一些费用,你当然可以选择缓存。 但是,除了高性能之外,还有其他一些原因可以使用Redis。
1.高可用性
2.水平和垂直可伸缩性
3.本地解决方案
使用Redis也有一些缺点,其中包括:
1.需要客户支持。
2.有限的多键操作支持。
3.仅支持一个数据库。
换句话说,Redis既酷又快,它取决于你的使用偏好!
结论
重要的是要注意,我只是在本文上进行了介绍,Redis还提供了更多其他功能! 我强烈建议你查看其官方文档. 如有任何疑问,请随时发表评论
> 喜欢这篇文章的可以点个赞,欢迎大家留言评论,记得关注我,每天持续更新技术干货、职场趣事、海量面试资料等等
> 如果你对java技术很感兴趣也可以交流学习,共同学习进步。
> 不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代
文章写道这里,欢迎完善交流。最后奉上近期整理出来的一套完整的java架构思维导图,分享给大家对照知识点参考学习。有更多JVM、Mysql、Tomcat、Spring Boot、Spring Cloud、Zookeeper、Kafka、RabbitMQ、RockerMQ、Redis、ELK、Git等Java干货