如何使用Adonis.js 5实现缓存
网络应用程序的性能是应用程序的一个组成部分。统计数据显示,缓慢的网络应用会以多种方式导致流量、销售和收入的损失。
在本教程中,我们将学习如何在我们用Adonis.js(简称Adonis)开发的论坛API上实现一个缓存系统,以提高API请求的性能和加载时间。我们还将把它与新的Adonis 5的新创建的缓存包结合起来,以获得最佳的缓存体验。
这篇文章打算通过实施最佳的缓存策略来改善我们之前的论坛API的性能,从而扩展和提升我们API的性能。
前提条件
在继续学习本教程之前,你应该具备以下条件。
- 对[TypeScript]和[Node.js]有一定了解。
- [对Adonis有一定了解]。
- 对[使用Adonis构建API有一定了解]。
- [一些关于缓存的知识]。
本教程的目标
我将向你展示使用Adonis处理缓存时使用的最佳实践。为了展示如何提升API的性能,我们将使用一个真实世界的论坛应用来演示,并学习如何选择一个好的缓存策略来提升性能。
在本教程中,你将学习。
- 缓存系统如何在Adonis restful API中工作。
- 关于缓存的概念以及用它来扩展一个大型企业应用。
- 使用Adonis构建面向性能的网络应用的最佳实践。
- 如何用Adonis 5开发高性能的API。
安装Adonis
开始使用Adonis 5是很简单的,因为它有很好的文档。
要开始使用,阅读Adonis.js 5终极指南和用Adonis 5开发RESTFUL API可以让你快速上手。
运行下面的命令,让Adonis 5安装在你的机器上。
npm init adonis-ts-app@latest forum-api
上面的命令将创建一个新的Adonis 5项目,正确配置并准备使用。
我们将使用前面提到的文章中开发的论坛API。克隆资源库以方便设置。
设置Adonis缓存
从Github repo中克隆项目后,运行以下命令来设置所需的一切。
npm install
接下来,我们将安装和配置我们的缓存包。这将简化我们在论坛API上实施缓存策略,以提高API的性能和响应时间。
这个包是一个类似于Laravel cache的缓存驱动实现,但与Adonis 5一起使用,它抽象了不同的缓存驱动实现和缓存策略,只公开了需要的方法。
要安装Adonis cache包,请运行以下命令。
npm i @kaperskyguru/adonis-cache
接下来,要设置和配置该包,运行该命令。
node ace configure @kaperskyguru/adonis-cache
# or
node ace invoke @kaperskyguru/adonis-cache
接下来,打开.env 文件,通知缓存包使用redis 作为缓存驱动。
CACHE_DRIVER = redis;
让我们继续配置我们的Redis服务器,以便我们的缓存包能够与Redis服务器成功通信。
默认的驱动被设置为file 。文档中包含了不同的驱动以及如何根据你的项目需求来配置每个驱动。
在使用Redis作为你的驱动程序之前,请确保在你的机器上安装了Redis,并正确配置,以便与Adonis 5一起工作。
要在你的本地机器上安装Redis社区服务器,根据你的操作系统下载二进制文件,并按照说明操作。
缓存包使用Adonis 5提供的默认Redis配置,因此,你必须配置Adonis Redis。
下面的步骤显示如何安装和配置Adonis 5的Redis服务器。
安装Adonis Redis
要使用redis 作为你的缓存驱动程序,你需要在你的服务器上安装它,同时在你的Adonis 5项目中安装和配置。
要做到这一点,运行以下命令。
npm i @adonisjs/redis
用这个命令配置@adonisjs/redis 。
node ace configure @adonisjs/redis
# Or
node ace invoke @adonisjs/redis
除了我们刚刚接受的默认选项外,还有更多的配置和调整,以便更好地使用Redis。
预先测试性能
让我们使用Postman运行一个性能测试,看看实施缓存后的性能变化。

如上图所示,我们的API请求的响应时间为643ms。这个结果是相当快的。
在Adonis 5中处理缓存
你现在应该已经克隆了论坛API项目。你还应该安装和配置了Redis服务器、Adonis Redis和我们将在这个项目中使用的缓存包。
如果你已经检查了所有这些,让我们直接进入代码。
在缓存的世界里,有许多缓存策略和方法可用,这取决于你的数据结构和对数据进行的不同操作。你可以根据项目的特点和类型来选择其他的缓存策略。
你可以阅读Adonis 5的最佳缓存策略,它将向你展示不同的缓存策略,并帮助你根据项目的特点或类型选择使用哪一种。
我们将在所有的读操作中使用缓存策略,在写操作中混合使用绕写和穿写策略。
你可以在我们以前的项目的app/Controllers/Http 文件夹中找到ForumsController 文件。
首先,我们将从读操作开始。
更新ForumsController ,使其看起来像下面的片段。
import Cache from '@ioc:Kaperskyguru/Adonis-Cache'
import Forum from 'App/Models/Forum';
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
export default class ForumsController {
// Reading all Forums available
public async index({}: HttpContextContract) {
const forums = await Cache.remember('forums', 60, async function () {
// This code is only executed when there is a MISS
return await Forum.query().preload('user').preload('posts');
})
return forums
}
// Retrieving a Single Forum by ID
public async update({request, params}: HttpContextContract){
try {
const forum = await Cache.remember('forum_id_' + params.id, 60, async function () {
// This code is only executed if there was a MISS
return await Forum.find(params.id);
})
if (forum) {
forum.title = request.input('title');
forum.description = request.input('description');
if (await forum.save()) {
await forum.preload('user')
await forum.preload('posts')
return forum
}
}
} catch (error) {
console.log(error)
}
}
}
读取操作主要显示在index() 方法中,用于通过ID检索所有论坛和单个论坛。
Cache.remember() 已经实现了Laravel Cache包中的Cache Aside Strategy out of the box。
从上面的代码中可以看出,我们首先尝试从缓存服务器中读取内容,如果找到了(HIT),我们返回forum 。但如果没有找到(MISS),我们继续用闭合函数检索forum 。
接下来是写操作。
更新ForumsController ,使其看起来像下面的片段。
public async update({ request, params }: HttpContextContract) {
// Tries to find a Forum from Cache, if found returns the Forum
const forum = await Cache.remember('forum_id_' + params.id, 60, async function () {
// If not found, Retrieves from Database and Save to Cache.
return await Forum.find(params.id)
})
if (forum && await forum.save()) {
// On successfully updates in database, then updates the Cache Server
await Cache.update('forum_id_' + params.id, forum, 60)
forum.title = request.input('title');
forum.description = request.input('description');
if (await forum.save()) {
await forum.preload('user')
await forum.preload('posts')
return forum
}
return // 422
}
}
public async store({ auth, request}: HttpContextContract)
{
const user = await auth.authenticate();
const forum = new Forum();
forum.title = request.input('title');
forum.description = request.input('description');
await user.related('forums').save(forum)
// Stores a new forum to Cache
await Cache.set('forum_id_' + forum.id, forum, 60)
return forum
}
写操作首先访问数据库(绕写),只在读操作时更新缓存服务器,以随后加快读操作的速度。
性能的后期测试
现在我们已经在我们的项目上实现了一个缓存系统,让我们用Postman来运行一些测试,看看API的性能改进。

一目了然,你会发现响应时间有了明显的改善,从没有缓存的643ms响应时间到实施了缓存系统的12ms响应时间。
总结
在每一个面向性能的应用程序中,如果你需要在你的项目中实现良好的性能和速度,缓存应该是应用程序开发过程中不可或缺的一部分。
在本教程中,我们已经研究了如何在你的Adonis项目中实现缓存并提高响应时间。