许多开发者都希望能够彻底搞清楚 API 的工作方式,以及如何利用缓存 API 请求来提升业务,但是当这个需求进入实现阶段时,许多人就会发现手头并没有合适的工具和恰当的方法,所以我们今天就为大家做一个全面的讲解:
① 几种不同的 API 缓存实现方式
② 上述方式的优缺点以及如何为每个 API 制定最适合的缓存策略
首先我们想要提出一个重要的结论:按照下文介绍的方法进行测试后 Akamai 发现,通过恰当的缓存技术,API 的交付速度可以实现21%的提升。
测试方法和基线的建立 —— 以喵星人为例
我们将使用一款名为 Siege 的负载测试和性能基准工具针对样本 API 创建请求。Siege 的运行界面类似下图所示,会列出针对特定 URL 发起的所有请求的响应情况:
在后续的测试中,我们使用了一个以 MongoDB 作为后端的 NodeJS API,这是一种基于 Express 的基本型 API,能够返回可供领养的小猫数据。毕竟人人都爱喵星人对吧!这个API的内容如下:
我们将用一个简单的 GET 请求进行测试,该请求可返回一个大小为6.59 KB的 JSON 响应,其中包含227行内容,所有内容均为可领养小猫的数据:
运行 GET 命令返回的标头数据如下所示。请注意,与服务器的连接将持续不中断,并且我们会使用 GZIP 来降低载荷大小:
在第一次测试中,我们用5分钟时间通过5个并发用户从本机运行 Siege,负责处理请求的 Express 服务器同样在本机运行,也就是说,完全不涉及网络通信。这是为了排除与网络有关的各种可能干扰,建立准确的基线。我们使用下列命令让 Siege 运行5分钟,并模拟5个并发用户发起 GET 请求:
$ siege -c 5 –time=5m –content-type “application/json” GET http://localhost:3000/cats
首次运行的结果如下,其中包含(事务)命中数、测试运行时长、测试传输的数据量、事务处理速率,以及成功和失败事务的数量等数据:
这些数据将用作后续测试和对比的基线。
不同场景的测试和结果
首先引入应用程序级缓存。我们将使用 apicache NPM 包为这个应用添加一种简单的内存驻留响应缓存。添加该包(运行“npm install apicache”命令)后,添加下列几行配置信息启用该包:
随后再次进行测试并运行“get_all_cats”。请注意,原先采用的命令已经被注释掉了,新运行的命令使用了 apicache,并会通过指令将该响应缓存5分钟:
下文的不同测试中,随着缓存的启用和禁用,我们会分别使用上述的一条命令,并会重启动 NodeJS 服务器以便清除内存中可能对测试结果产生影响的残留数据。如果向服务器发出请求,并且在得到的响应中包含“cache-control”,则意味着这是一个被缓存的响应。该标头的 max-age 值已设置为300秒(即应用中指定的5分钟):
此外还可以打开 apicache 模块的调试模式,已确认该模块是否正常运行:
从上图可以看到,第一个请求花了31毫秒才将数据返回给客户端,但后续请求所需的时间已经大幅缩短。因为第一个请求是完整请求,所有后续请求都是由内存中的缓存提供响应的,因此可在不到0.5毫秒的时间返回客户端。这正是缓存最核心的优势。
接下来再次运行和上文完全相同的 Siege 命令,看看在使用应用程序级缓存之后,结果会有何不同:
$ siege -c 5 –time=5m –content-type “application/json” GET http://localhost:3000/cats
看到了吧!仅仅应用程序级的缓存就产生了这么大的效果。同样五分钟里,启用缓存后命中数提高了60%。虽然数据传输量也更多,但每秒处理的事务数量高达449条,最初仅仅为每秒179条,同样提升了60%!仅仅为 API 设置缓存就获得这样的效果,这样的收益谁不喜欢。
接着将网络因素考虑在内。出于测试和展示等因素考虑,我在 Digital Ocean 纽约数据中心开通了一台1GB 内存,1颗虚拟处理器,一块25GB 容量 SSD 硬盘的 Droplet 服务器。这是 Digital Ocean 所能提供的最低硬件配置的虚拟机,而我们专门选择这一配置,是为了测试在硬件性能有限的情况下,API 缓存能实现的效果。将上文提到的 NodeJS cats API 部署到 Droplet 服务器,并在前端使用 Nginx 作为代理将来自80端口的请求发送至 NodeJS 的3000端口。此外同样在本地运行了一个 MongoDB 实例充当该 API 的后端。此外服务器上未运行任何其他软件。
向服务器发出请求并查看返回的响应标头,内容如下图所示,从中可以看到,“Nginx”字样意味着这次测试并非在本机上进行的:
接下来针对 Digital Ocean 的服务器,(使用IP地址)再次运行相同的 Siege 命令:
$ siege -c 5 –time=5m –content-type “application/json” GET http://206.81.0.14/cats
在不缓存 API 响应的情况下,针对 Digital Ocean VPS 运行 Siege 的结果如下:
本机运行,以及 IaaS 平台运行,两次对比的结果有如下差异:
◆ 命中数和事务处理数量降低了35%
◆ 首次开始出现失败的事务
降低35%,这个结果已经很严重了,不过考虑到这是在多租户云平台上运行的结果,似乎也不是那么出人意料。那么对于 Digital Ocean 的这个场景,启用 apicache 又能产生多大的效果?按照上文列出的方法启用 API 缓存,随后为了确认缓存已经启用,再次向 Digital Ocean 的服务器发出一个 API 请求,并查看其响应内容如下:
从中可以看到标头中包含“cache-control”,意味着缓存已经成功启用,且缓存寿命为5分钟(300秒)。接着再次针对 Digital Ocean 服务器运行相同的 Siege 命令:
$ siege -c 5 –time=5m –content-type “application/json” GET http://206.81.0.14/
哇!这次在启用缓存后,5分钟内处理的事务数量增加了4,932条,并且处理速度提升了21%(由每秒63条提高至每秒80条)。由于服务器不需要每次都重新生成响应,因此相同时间里可以提供更多数据。这个结果完美诠释了对 API 响应创建缓存这种做法的价值。
最后为了便于大家比较,我们将上述几次测试的结果统一放在一起。API 缓存的价值,您看到了吗?
↑↑↑本机测试,无缓存↑↑↑
↑↑↑本机测试,有缓存↑↑↑
↑↑↑网络测试,无缓存↑↑↑