|
| 1 | +--- |
| 2 | +title: API 响应缓存 |
| 3 | +keywords: |
| 4 | + - API 网关 |
| 5 | + - Apache APISIX |
| 6 | + - 缓存 |
| 7 | + - 性能 |
| 8 | +description: This tutorial will focus primarily on handling caching at the API Gateway level by using Apache APISIX API Gateway and you will learn how to use proxy-caching plugin to improve response efficiency for your Web or Microservices API. |
| 9 | +--- |
| 10 | + |
| 11 | +<!-- |
| 12 | +# |
| 13 | +# Licensed to the Apache Software Foundation (ASF) under one or more |
| 14 | +# contributor license agreements. See the NOTICE file distributed with |
| 15 | +# this work for additional information regarding copyright ownership. |
| 16 | +# The ASF licenses this file to You under the Apache License, Version 2.0 |
| 17 | +# (the "License"); you may not use this file except in compliance with |
| 18 | +# the License. You may obtain a copy of the License at |
| 19 | +# |
| 20 | +# http://www.apache.org/licenses/LICENSE-2.0 |
| 21 | +# |
| 22 | +# Unless required by applicable law or agreed to in writing, software |
| 23 | +# distributed under the License is distributed on an "AS IS" BASIS, |
| 24 | +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 25 | +# See the License for the specific language governing permissions and |
| 26 | +# limitations under the License. |
| 27 | +# |
| 28 | +--> |
| 29 | + |
| 30 | +本教程将主要介绍如何在 **API 网关** 级别进行缓存处理,使用 **Apache APISIX API 网关**,你将学习如何使用 **proxy-cache** 插件来提升 Web 或微服务 API 的响应效率。 |
| 31 | + |
| 32 | +**本次教程涵盖的内容概览:** |
| 33 | + |
| 34 | +* API 网关中的缓存 |
| 35 | +* 关于 [Apache APISIX API 网关](https://apisix.apache.org/zh/docs/apisix/getting-started/) |
| 36 | +* 运行演示项目 [apisix-dotnet-docker](https://github.com/Boburmirzo/apisix-dotnet-docker) |
| 37 | +* 配置 [Proxy Cache](https://apisix.apache.org/zh/docs/apisix/plugins/proxy-cache/) 插件 |
| 38 | +* 验证代理缓存功能 |
| 39 | + |
| 40 | +## 通过缓存提升性能 |
| 41 | + |
| 42 | +在构建 API 时,你希望保持其简单且高效。当并发请求需要访问相同数据量增加时,你可能会遇到一些问题,从而考虑引入 **缓存**: |
| 43 | + |
| 44 | +* 某些 API 请求存在延迟,明显影响用户体验。 |
| 45 | +* 从数据库获取数据响应时间过长。 |
| 46 | +* API 的高吞吐量可能威胁到其可用性。 |
| 47 | +* 网络故障导致频繁访问的 API 信息获取失败。 |
| 48 | + |
| 49 | +## API 网关中的缓存 |
| 50 | + |
| 51 | +[缓存](https://zh.wikipedia.org/wiki/%E7%BC%93%E5%AD%98)能够存储并获取网络请求及其对应的响应。在 Web 应用中,缓存可以发生在不同层级: |
| 52 | + |
| 53 | +* 边缘缓存或 CDN |
| 54 | +* 数据库缓存 |
| 55 | +* 服务器缓存(API 缓存) |
| 56 | +* 浏览器缓存 |
| 57 | + |
| 58 | +**反向代理缓存(Reverse Proxy Caching)** 是另一种缓存机制,通常在 **API 网关** 内部实现。它可以减少对后端接口的调用次数,并通过缓存上游响应来提高 API 请求的延迟表现。如果 API 网关缓存中存在请求资源的最新副本,它会直接使用该副本响应请求,而无需访问后端服务。如果未命中缓存,请求将转发到目标上游服务(后端服务)。 |
| 59 | + |
| 60 | +## Apache APISIX API 网关代理缓存 |
| 61 | + |
| 62 | +借助 **Apache APISIX**,你可以使用 [proxy-cache](https://apisix.apache.org/zh/docs/apisix/plugins/proxy-cache/) 插件为 API 启用缓存,从而缓存 API 端点的响应并提升性能。该插件可以与其他插件组合使用,目前支持基于磁盘的缓存。 |
| 63 | + |
| 64 | +要缓存的数据可以通过 **responseCodes**、**requestModes** 进行过滤,也可以使用 **noCache** 和 **cacheByPass** 属性进行更复杂的过滤。你还可以在插件配置中指定缓存的过期时间或内存容量。更多配置项请参考 `proxy-cache` 插件的 [属性说明](https://apisix.apache.org/zh/docs/apisix/plugins/proxy-cache/)。 |
| 65 | + |
| 66 | +有了这些基础,我们接下来将通过一个例子演示如何使用 **Apache APISIX** 的 `proxy-cache` 插件,并将其应用于 **ASP.NET Core Web API** 的单个端点。 |
| 67 | + |
| 68 | +## 运行演示项目 |
| 69 | + |
| 70 | +到目前为止,我假设你已经启动并运行了演示项目 [apisix-dotnet-docker](https://github.com/Boburmirzo/apisix-dotnet-docker)。你可以在 **GitHub** 上查看完整源码,以及如何通过 **Docker CLI** 构建多容器 **APISIX** 的说明。 |
| 71 | + |
| 72 | +在 **ASP.NET Core 项目** 中,有一个简单的 API,用于从服务层获取所有产品列表,位于 [ProductsController.cs](https://github.com/Boburmirzo/apisix-dotnet-docker/blob/main/ProductApi/Controllers/ProductsController.cs) 文件中。 |
| 73 | + |
| 74 | +假设这个产品列表通常每天只更新一次,而该端点每天需要处理数十亿次请求来部分或全部获取产品列表。在这种场景下,使用 `proxy-cache` 插件进行 API 缓存将非常有用。为了演示的目的,我们仅为 `GET` 方法启用缓存。 |
| 75 | + |
| 76 | +> 理想情况下,`GET` 请求应该默认是可缓存的——除非出现特殊条件。 |
| 77 | +
|
| 78 | +## 配置 Proxy Cache 插件 |
| 79 | + |
| 80 | +现在,让我们开始在项目的 **Apache APISIX 声明式配置文件 `config.yaml`** 中添加 `proxy-cache` 插件。由于在当前项目中,我们还没有注册本次演示要使用的插件,因此需要将 `proxy-cache` 插件名称添加到插件列表末尾: |
| 81 | + |
| 82 | +```yaml |
| 83 | +plugins: |
| 84 | + - http-logger |
| 85 | + - ip-restriction |
| 86 | + … |
| 87 | + - proxy-cache |
| 88 | +``` |
| 89 | + |
| 90 | +如果你需要指定缓存相关参数(如 **disk_size**、**memory_size**),也可以在同一个文件中添加缓存配置,例如: |
| 91 | + |
| 92 | +```yaml |
| 93 | +proxy_cache: |
| 94 | + cache_ttl: 10s # 如果上游未指定缓存时间,则使用默认缓存时间 |
| 95 | + zones: |
| 96 | + - name: disk_cache_one # 缓存名称。管理员可以在 Admin API 中按名称指定使用哪个缓存 |
| 97 | + memory_size: 50m # 用于存储缓存索引的共享内存大小 |
| 98 | + disk_size: 1G # 用于存储缓存数据的磁盘大小 |
| 99 | + disk_path: "/tmp/disk_cache_one" # 缓存数据存储路径 |
| 100 | + cache_levels: "1:2" # 缓存的层级结构 |
| 101 | +``` |
| 102 | +
|
| 103 | +接下来,我们可以直接运行 `apisix reload` 命令来重新加载最新的插件代码,而无需重启 Apache APISIX。重新加载新插件的命令如下: |
| 104 | + |
| 105 | +```shell |
| 106 | +curl http://127.0.0.1:9180/apisix/admin/plugins/reload -H "X-API-KEY: $admin_key" -X PUT |
| 107 | +``` |
| 108 | + |
| 109 | +然后,我们运行两个 curl 命令来为 `/api/products` 端点配置 **Upstream** 和 **Route**。首先,创建一个示例 Upstream(也就是我们的 API 服务器): |
| 110 | + |
| 111 | +```shell |
| 112 | +curl "http://127.0.0.1:9180/apisix/admin/upstreams/1" -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" -X PUT -d ' |
| 113 | +{ |
| 114 | + "type": "roundrobin", |
| 115 | + "nodes": { |
| 116 | + "productapi:80": 1 |
| 117 | + } |
| 118 | +}' |
| 119 | +``` |
| 120 | + |
| 121 | +接下来,我们为 `/api/products` 添加一个具备缓存能力的路由,通过在 `plugins` 属性中设置 `proxy-cache` 插件,并通过 **upstream_id** 引用上游服务,将请求转发到 API 服务器: |
| 122 | + |
| 123 | +```shell |
| 124 | +curl "http://127.0.0.1:9180/apisix/admin/routes/1" -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" -X PUT -d '{ |
| 125 | + "name": "Route for API Caching", |
| 126 | + "methods": [ |
| 127 | + "GET" |
| 128 | + ], |
| 129 | + "uri": "/api/products", |
| 130 | + "plugins": { |
| 131 | + "proxy-cache": { |
| 132 | + "cache_key": [ |
| 133 | + "$uri", |
| 134 | + "-cache-id" |
| 135 | + ], |
| 136 | + "cache_bypass": [ |
| 137 | + "$arg_bypass" |
| 138 | + ], |
| 139 | + "cache_method": [ |
| 140 | + "GET" |
| 141 | + ], |
| 142 | + "cache_http_status": [ |
| 143 | + 200 |
| 144 | + ], |
| 145 | + "hide_cache_headers": true, |
| 146 | + "no_cache": [ |
| 147 | + "$arg_test" |
| 148 | + ] |
| 149 | + } |
| 150 | + }, |
| 151 | + "upstream_id": 1 |
| 152 | +}' |
| 153 | +``` |
| 154 | + |
| 155 | +如上配置所示,我们定义了一些插件属性,表示只缓存 **GET 方法的成功响应(HTTP 200)**。 |
| 156 | + |
| 157 | +## 验证 Proxy Cache 功能 |
| 158 | + |
| 159 | +最后,我们可以测试代理缓存是否按预期工作。 |
| 160 | + |
| 161 | +我们将向 `/api/products` 路径发送多次请求,每次都应收到 `HTTP 200 OK` 响应。然而,响应头中的 `Apisix-Cache-Status` 会显示 **MISS**,表示当请求第一次访问路由时,该响应尚未缓存。此时,如果再次发送请求,你会看到响应已被缓存,`Apisix-Cache-Status` 显示 **HIT**。 |
| 162 | + |
| 163 | +首先,发送初始请求: |
| 164 | + |
| 165 | +```shell |
| 166 | +curl http://localhost:9080/api/products -i |
| 167 | +``` |
| 168 | + |
| 169 | +响应示例: |
| 170 | + |
| 171 | +```shell |
| 172 | +HTTP/1.1 200 OK |
| 173 | +… |
| 174 | +Apisix-Cache-Status: MISS |
| 175 | +``` |
| 176 | + |
| 177 | +当你再次调用该服务时,由于上一次请求已缓存,路由会返回缓存的响应: |
| 178 | + |
| 179 | +```shell |
| 180 | +HTTP/1.1 200 OK |
| 181 | +… |
| 182 | +Apisix-Cache-Status: HIT |
| 183 | +``` |
| 184 | + |
| 185 | +如果在缓存的 **TTL(生存时间)** 结束后再次访问端点,你将得到: |
| 186 | + |
| 187 | +```shell |
| 188 | +HTTP/1.1 200 OK |
| 189 | +… |
| 190 | +Apisix-Cache-Status: EXPIRED |
| 191 | +``` |
| 192 | + |
| 193 | +太棒了!我们已经为 API 端点启用了缓存。 |
| 194 | + |
| 195 | +### 额外测试案例 |
| 196 | + |
| 197 | +你也可以在 **Product Controller** 代码中添加一些延迟,并测量有缓存和无缓存情况下的响应时间: |
| 198 | + |
| 199 | +```c# |
| 200 | +[HttpGet] |
| 201 | +public IActionResult GetAll() |
| 202 | +{ |
| 203 | + Console.Write("The delay starts.\n"); |
| 204 | + System.Threading.Thread.Sleep(5000); |
| 205 | + Console.Write("The delay ends."); |
| 206 | + return Ok(_productsService.GetAll()); |
| 207 | +} |
| 208 | +``` |
| 209 | + |
| 210 | +使用 `curl` 命令测量响应时间: |
| 211 | + |
| 212 | +```shell |
| 213 | +curl -i 'http://localhost:9080/api/products' -s -o /dev/null -w "Response time: %{time_starttransfer} seconds\n" |
| 214 | +``` |
| 215 | + |
| 216 | +## 后续步骤 |
| 217 | + |
| 218 | +如我们所学,在 **Apache APISIX** 的帮助下,为 **ASP.NET Core Web API** 配置 API 响应缓存既简单又快速。它可以显著减少对端点的调用次数,并改善 API 请求的延迟表现。Apache APISIX 还提供了众多内置插件,你可以在 [插件中心](https://apisix.apache.org/plugins) 查看并根据需要使用。 |
| 219 | + |
| 220 | +## 推荐阅读 |
| 221 | + |
| 222 | +* 你可以参考 [Expose API](./protect-api.md) 学习如何发布你的第一个 API。 |
| 223 | +* 你可以参考 [Protect API](./protect-api.md) 学习如何保护你的 API。 |
0 commit comments