
Apache APISIX proxy-cache 插件详解磁盘与内存双策略缓存 Upstream 响应【免费下载链接】apisixThe Cloud-Native API Gateway项目地址: https://gitcode.com/GitHub_Trending/ap/apisixproxy-cache是 Apache APISIX 内置的响应缓存插件用于将 Upstream 返回的响应按策略缓存到磁盘或共享内存中从而显著降低后端压力、缩短请求时延。本文以官方文档 docs/en/latest/plugins/proxy-cache.md 为主线结合插件源码 apisix/plugins/proxy-cache/init.lua 与测试用例 t/plugin/proxy-cache/disk.t、t/plugin/proxy-cache/memory.t完整讲解属性配置、缓存区定义、磁盘/内存两种策略的启用方式、缓存命中状态、PURGE 清理以及删除插件的方法帮助你在真实路由上快速落地响应缓存。功能概述proxy-cache插件负责把来自 Upstream 的响应缓存起来后续相同请求可直接从缓存返回无需再次穿透到后端服务。它具备以下能力两种存储策略磁盘缓存disk与内存缓存memory分别通过cache_strategy指定精细化过滤通过cache_http_status过滤响应码、cache_method过滤请求方法复杂条件控制通过no_cache不缓存与cache_bypass绕过缓存读取实现按请求参数等动态条件控制缓存行为与其他插件协同可作为普通插件挂载在 Route 上与认证、限流等其他插件组合使用。从插件源码 apisix/plugins/proxy-cache/init.lua 可以看到该插件priority 1085、version 0.2并定义了完整的 JSON Schema 校验规则在access、header_filter、body_filter三个阶段分别调用对应的磁盘或内存处理器完成缓存读取、响应头处理与响应体落缓存。属性说明下表完整列出插件的全部配置属性与文档 docs/en/latest/plugins/proxy-cache.md 属性表一致名称类型必填默认值合法值说明cache_strategystring否disk[disk,memory]缓存数据存放位置磁盘或内存cache_zonestring否disk_cache_one指定使用的缓存区名称。每个缓存区可配置不同的路径缓存区需在配置文件conf/config.yaml中预定义若指定的缓存区与配置文件中预定义的不一致缓存将失效cache_keyarray[string]否[$host, $request_uri]缓存使用的键例如[$host, $uri, -cache-id]cache_bypassarray[string]否绕过缓存读取的条件字符串数组中只要有一个值非空且不等于0就不从缓存取响应例如[$arg_bypass]cache_methodarray[string]否[GET, HEAD][GET, POST, HEAD]需要缓存响应的请求方法cache_http_statusarray[integer]否[200, 301, 404][200, 599]需要缓存响应的 Upstream 返回 HTTP 状态码hide_cache_headersboolean否false设为true时隐藏响应中的Expires与Cache-Control头cache_controlboolean否false设为true时遵循 HTTP 规范中的 Cache-Control 语义仅用于内存策略no_cachearray[string]否不缓存响应的条件字符串数组中只要有一个值非空且不等于0响应就不会被保存cache_ttlinteger否300秒响应被缓存直至删除或刷新的时间。在cache_control未启用或后端未返回缓存头时生效仅用于内存策略Schema 层面的约束细节从 apisix/plugins/proxy-cache/init.lua 的 Schema 定义可以确认更多边界条件cache_zone长度限制为 1~100 字符cache_key、cache_bypass、no_cache的每个元素必须匹配正则(^[^\$].$|^\$[0-9a-zA-Z_]$)即要么是普通字符串常量要么是$开头的合法变量名cache_http_status的每个状态码取值范围 200~599且数组元素唯一uniqueItems truecache_method仅允许GET、POST、HEAD三者且元素唯一cache_ttl最小值为 1。此外check_schemaapisix/plugins/proxy-cache/init.lua还有两条额外的运行期校验cache_key中不允许使用$request_method变量否则报错cache_key variable $request_method unsupported插件指定的cache_zone必须能在conf/config.yaml的apisix.proxy_cache.zones中找到同名缓存区否则报错cache_zone xxx not found同时会校验缓存策略与缓存区形态是否匹配——memory策略对应的缓存区不能配置disk_pathdisk策略对应的缓存区必须配置disk_path否则报错invalid or empty cache_zone for cache_strategy。对应测试 t/plugin/proxy-cache/disk.t 与 t/plugin/proxy-cache/memory.t 中验证了这些校验如cache_method传字符串而非数组、cache_key写成${uri}-cache-key、cache_strategy传network、cache_zone传不存在的invalid_cache_zone时Admin API 均返回 400 与failed to check the configuration of plugin proxy-cache错误。注意事项官方文档原注:::note缓存过期时间无法动态配置只能由 Upstream 响应头Expires或Cache-Control决定若 Upstream 响应头中没有Expires或Cache-Control默认过期时间为 10s。若 Upstream 服务不可用APISIX 返回502或504状态码时该响应也会被缓存 10s。cache_key、cache_bypass、no_cache中可以指定变量以$开头。需要说明的是变量不存在时其值会是空字符串。也可以将多个变量和字符串常量组合写入数组最终变量会被解析并与字符串拼接在一起。:::需要区分的是上述 10s 默认过期时间适用于磁盘策略而内存策略下若未启用cache_control且后端未返回缓存头则使用cache_ttl属性默认 300s作为过期时间。配置缓存区使用proxy-cache前需要先在 APISIX 配置文件conf/config.yaml中声明缓存区。以下配置示例声明了一个磁盘缓存区disk_cache_one、一个被注释的备用磁盘缓存区disk_cache_two以及一个内存缓存区memory_cacheapisix: proxy_cache: cache_ttl: 10s # default cache TTL for caching on disk zones: - name: disk_cache_one memory_size: 50m disk_size: 1G disk_path: /tmp/disk_cache_one cache_levels: 1:2 # - name: disk_cache_two # memory_size: 50m # disk_size: 1G # disk_path: /tmp/disk_cache_two # cache_levels: 1:2 - name: memory_cache memory_size: 50m各字段含义name缓存区名称需与插件配置中的cache_zone一一对应memory_size缓存区共享内存大小keys_zone / lua_shared_dict 大小磁盘缓存用于存放缓存键索引内存缓存则直接存放响应数据disk_size磁盘缓存最大容量disk_path磁盘缓存落盘路径只有配置了该字段的缓存区才能被disk策略使用cache_levels磁盘缓存的目录层级如1:2表示两级目录首层 1 个十六进制字符次层 2 个字符顶层cache_ttl: 10s磁盘缓存的默认 TTL。缓存区如何转化为 Nginx 配置从 Nginx 配置模板 apisix/cli/ngx_tpl.lua 可以看到当proxy-cache插件被启用时模板会遍历proxy_cache.zones对配置了disk_path、cache_levels、disk_size的缓存区生成proxy_cache_path disk_path levelscache_levels keys_zonename:memory_size inactive1d max_sizedisk_size use_temp_pathoff;对未配置磁盘字段的缓存区生成lua_shared_dict name memory_size;即内存缓存使用的共享字典同时生成map $upstream_cache_zone $upstream_cache_zone_info映射把缓存区名映射为磁盘路径,目录层级供磁盘处理器定位缓存文件。这解释了为什么插件配置的cache_zone与config.yaml不一致时缓存会失效——对应缓存区根本没有被转换为 Nginx 侧的proxy_cache_path或lua_shared_dict请求处理时无缓存可用。启用插件准备 admin_key下文所有 Admin API 调用都需要管理员密钥。可以从config.yaml中取出admin_key并保存为环境变量admin_key$(yq .deployment.admin.admin_key[0].key conf/config.yaml | sed s///g)使用磁盘缓存在 Route 上启用插件默认即使用磁盘策略cache_strategy: disk与disk_cache_one缓存区curl http://127.0.0.1:9180/apisix/admin/routes/1 \ -H X-API-KEY: $admin_key -X PUT -d { uri: /ip, plugins: { proxy-cache: { cache_key: [$uri, -cache-id], cache_bypass: [$arg_bypass], cache_method: [GET], cache_http_status: [200], hide_cache_headers: true, no_cache: [$arg_test] } }, upstream: { nodes: { httpbin.org: 1 }, type: roundrobin } }示例解读cache_key由$uri与字符串常量-cache-id拼接而成即/ip-cache-id不同 URI 会得到不同缓存键cache_bypass: [$arg_bypass]请求携带?bypass1任意非空且非0的值时绕过缓存读取cache_method: [GET]仅缓存 GET 请求的响应cache_http_status: [200]仅缓存状态码为 200 的响应hide_cache_headers: true隐藏Expires与Cache-Control响应头no_cache: [$arg_test]请求携带?test1时响应不写入缓存。使用内存缓存将cache_strategy设为memory并指定对应的内存缓存区memory_cache同时可显式设置cache_ttlcurl http://127.0.0.1:9180/apisix/admin/routes/1 \ -H X-API-KEY: $admin_key -X PUT -d { uri: /ip, plugins: { proxy-cache: { cache_strategy: memory, cache_zone: memory_cache, cache_ttl: 10 } }, upstream: { nodes: { httpbin.org: 1 }, type: roundrobin } }内存策略与磁盘策略在源码层面的分派位于 apisix/plugins/proxy-cache/init.luaaccess阶段根据cache_strategy选择memory_handler或disk_handlerheader_filter阶段同样按策略分派而body_filter阶段只对内存策略生效磁盘策略的响应体缓存由 Nginx 的proxy_cache模块完成。缓存键、绕过与不缓存的底层实现理解cache_key、cache_bypass、no_cache的行为可以看公共工具函数 apisix/plugins/proxy-cache/util.lua 的generate_complex_value遍历数组中的每个元素若元素以$开头则取出ctx.var[变量名]的值变量不存在时取空字符串与文档说明一致否则直接使用字符串常量最终将所有元素拼接为一个字符串。match_method与match_statusapisix/plugins/proxy-cache/util.lua分别遍历cache_method、cache_http_status判断当前请求方法、响应状态码是否命中。磁盘处理器 apisix/plugins/proxy-cache/disk_handler.lua 在access阶段把cache_bypass的计算结果写入upstream_cache_bypass变量并把请求方法不在cache_method中的请求强制标记为 bypass置为1header_filter阶段apisix/plugins/proxy-cache/disk_handler.lua综合cache_method命中、状态码命中以及no_cache计算结果生成upstream_no_cache并统一设置Cache-Control、Expires、Apisix-Cache-Status三个响应头。内存处理器 apisix/plugins/proxy-cache/memory_handler.lua 中的cacheable_request/cacheable_response则进一步实现了 HTTP Cache-Control 语义启用cache_control时no-store、no-cache请求侧以及private、no-store、no-cache响应侧都会阻止缓存s-maxage/max-age/Expires会被解析用于计算资源 TTLparse_resource_ttl支持的指令格式包括max-age3600、max-stale3600、min-fresh3600、private, max-age600等。缓存验证与状态码配置完成后发起首次请求curl http://127.0.0.1:9080/ip -iHTTP/1.1 200 OK ··· Apisix-Cache-Status: MISS hello响应中的Apisix-Cache-Status: MISS表示响应未被缓存符合预期首次请求需要回源。再次发起相同请求curl http://127.0.0.1:9080/ip -iHTTP/1.1 200 OK ··· Apisix-Cache-Status: HIT hello此时Apisix-Cache-Status: HIT表示命中缓存响应直接由缓存返回。如果把cache_zone设置为一个未在config.yaml中定义的无效值如invalid_disk_cache请求会返回404响应。各类缓存状态的含义结合 t/plugin/proxy-cache/memory.t 的测试用例与 apisix/plugins/proxy-cache/memory_handler.lua 的实现Apisix-Cache-Status可能出现的取值包括MISS缓存未命中如 TEST 4 首次请求GET /helloHIT缓存命中如 TEST 5 第二次请求BYPASS请求被绕过如 TEST 6 携带?bypass1或缓存格式与当前版本不匹配时强制绕过并清理旧缓存EXPIRED缓存项已过期get_stale返回 staleSTALE缓存数据已超过 TTL非过期删除内存处理器据此决定是否回源刷新携带?no_cache1的请求TEST 8会得到MISS且不写入缓存再次请求仍是MISSTEST 9 验证响应确实未落缓存。此外内存命中时处理器还会设置Age响应头floor(now - timestamp)并在cache_control启用时依据客户端请求中的max-age、max-stale、min-fresh、only-if-cached指令决定返回缓存还是回源only-if-cached且无缓存时直接返回 504。磁盘缓存的键文件定位磁盘缓存把缓存键经 MD5 哈希后按cache_levels分层存放。generate_cache_filenameapisix/plugins/proxy-cache/util.lua从 MD5 摘要末尾向前按各层长度切分目录名例如levels1:2时MD5 的最后 1 个字符与倒数第 2~3 个字符构成两级目录最终文件路径形如/tmp/disk_cache_one/a/bc/完整MD5。磁盘处理器access阶段的disk_cache_purgeapisix/plugins/proxy-cache/disk_handler.lua也是先按此规则拼出文件路径再判断文件是否存在。清理缓存PURGE要清除已缓存的数据可发送带PURGE方法的请求curl -i http://127.0.0.1:9080/ip -X PURGEHTTP/1.1 200 OK返回200表示删除成功如果缓存数据不存在则返回404。磁盘策略下PURGE 请求在access阶段被拦截处理apisix/plugins/proxy-cache/disk_handler.lua先计算缓存文件名若文件存在则os.remove删除并返回 200否则返回 404。内存策略下PURGE 在 apisix/plugins/proxy-cache/memory_handler.lua 中处理从共享字典查找缓存键not found时返回 404否则调用memory:purge底层为ngx.shared.DICT:delete见 apisix/plugins/proxy-cache/memory.lua删除后返回 200。对应测试见 t/plugin/proxy-cache/memory.t 的 TEST 7PURGE 返回 200。删除插件移除proxy-cache插件时只需删除插件配置中对应的 JSON 配置。APISIX 会自动重新加载无需重启即可生效curl http://127.0.0.1:9180/apisix/admin/routes/1 \ -H X-API-KEY: $admin_key -X PUT -d { uri: /ip, plugins: {}, upstream: { type: roundrobin, nodes: { httpbin.org: 1 } } }将plugins置为空对象{}后该 Route 将不再执行任何缓存逻辑已写入磁盘或内存的存量缓存数据不受影响可通过 PURGE 请求逐一清理或直接清理缓存目录/等待 TTL 自然过期。实战要点小结先定义缓存区再启用插件cache_zone必须在conf/config.yaml的apisix.proxy_cache.zones中预定义且磁盘策略对应带disk_path的缓存区、内存策略对应纯memory_size的缓存区否则配置校验失败或缓存无效根据响应特性选择策略磁盘缓存disk容量大、可跨进程持久适合大体积、高并发的静态资源内存缓存memory基于lua_shared_dict访问更快但受共享内存大小限制适合高频小响应善用条件控制cache_bypass控制是否从缓存读取no_cache控制是否写入缓存二者配合$arg_*等变量可实现按请求参数动态启停缓存cache_http_status与cache_method则从响应码、请求方法维度做粗粒度过滤理解过期语义磁盘策略的默认过期时间来自 Upstream 的Expires/Cache-Control缺省 10s内存策略在未启用cache_control时使用cache_ttl默认 300s启用后则遵循 HTTP 标准的 Cache-Control 指令s-maxage、max-age、private、no-store等用状态头排查问题通过Apisix-Cache-Status的MISS/HIT/BYPASS/EXPIRED/STALE快速定位缓存是否生效、为何失效再结合Age头判断命中数据的年龄。如果需要深入源码可从 apisix/plugins/proxy-cache/init.lua插件入口与 Schema、apisix/plugins/proxy-cache/disk_handler.lua磁盘处理器、apisix/plugins/proxy-cache/memory_handler.lua内存处理器与 Cache-Control 语义、apisix/plugins/proxy-cache/util.lua键生成与匹配工具以及 apisix/cli/ngx_tpl.lua缓存区到 Nginx 配置的转换入手测试用例 t/plugin/proxy-cache/disk.t 与 t/plugin/proxy-cache/memory.t 则提供了可复现的完整行为验证。【免费下载链接】apisixThe Cloud-Native API Gateway项目地址: https://gitcode.com/GitHub_Trending/ap/apisix创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考