
Apache APISIX proxy-mirror 插件详解流量镜像的配置、采样与超时控制实战【免费下载链接】apisixThe Cloud-Native API Gateway项目地址: https://gitcode.com/GitHub_Trending/ap/apisix流量镜像是将线上真实请求复制一份转发到镜像服务用于在不影响线上业务的前提下进行请求分析、回归验证、灰度观测等场景。本文以 Apache APISIX 的proxy-mirror插件为核心完整讲解其参数模型、路由启用方式、镜像子请求的超时控制机制并结合当前仓库的源码实现插件主体、nginx 模板与测试用例proxy-mirror.t说明其底层工作方式。读完本文你将能够独立完成流量镜像的配置、采样率调优与超时防护并理解镜像请求的实现原理。功能概述proxy-mirror插件为 APISIX 提供镜像客户端请求的能力网关在正常转发请求到真实上游的同时会将同一份请求含请求头、URI、参数复制一份发送到配置的镜像服务地址。典型应用场景包括将线上真实流量拷贝到预发或测试环境验证新版本服务的兼容性对线上请求内容做抽样分析、审计或数据采集而不影响线上服务在压测、演练时复用真实流量特征。需要特别注意的是镜像请求返回的响应会被 APISIX 忽略镜像结果不会回传给客户端因此镜像服务的可用性不会影响主链路但镜像子请求的延迟会影响主请求详见下文「超时控制」章节。参数详解插件支持四个配置项其中仅host为必填完整参数如下表所示名称类型必选项默认值有效值描述hoststring是指定镜像服务的地址地址中需要包含schemahttp(s)或grpc(s)但不能包含path部分。例如http://127.0.0.1:9797。pathstring否指定镜像请求的路径。如果不指定则默认会使用当前路径。如果是为了镜像 grpc 流量这个选项不再适用。path_concat_modestring否replace[replace, prefix]当指定镜像请求的路径时设置请求路径的拼接模式。replace模式将会直接使用path作为镜像请求的路径。prefix模式将会使用path来源请求 URI作为镜像请求的路径。如果是为了镜像 grpc 流量这个选项也不再适用。sample_rationumber否1[0.00001, 1]镜像请求的采样率。当设置为1时为全采样。从源码看参数约束在 apisix/plugins/proxy-mirror.lua 中插件的 JSON Schema 对参数做了严格约束理解这些约束有助于避免配置报错host必须匹配正则^(http(s)?|grpc(s)?):\/\/([\da-zA-Z.-]|\[[\da-fA-F:]\])(:\d)?$即必须携带http、https、grpc或grpcs协议前缀主机部分支持域名、IPv4 以及[::1]形式的 IPv6 字面量端口为可选项。由 proxy-mirror.t 的 TEST 1/2/3 可见使用ftp://前缀、http://127.0.0.1::1999这类非法端口格式、或完全不带schema的127.0.0.1:1999都会被 schema 校验拒绝并返回 400而不带端口号的http://127.0.0.1是合法配置TEST 4返回 200passed在host中携带路径如http://127.0.0.1:1999/invalid_uri也会校验失败TEST 5这正是文档中「host 不能包含 path 部分」的源码依据。path必须匹配正则^/[^?]$即必须以/开头且不能包含?与字符——参数query string需要由 APISIX 自动附加不能写在path中TEST 21 验证了a与/a?ac均为非法取值。sample_ratio取值范围为[0.00001, 1]最小采样率不能低于十万分之一超过 1 会被拒绝TEST 13 中sample_ratio: 10报错expected 10 to be at most 1。此外插件的priority为1010见 config.yaml.example 中的插件列表注释version为0.1在插件执行链中处于较高优先级保证镜像逻辑在路由匹配后尽早生效。在路由上启用插件以下示例演示如何在指定路由上启用proxy-mirror插件。示例中真实上游为127.0.0.1:1999镜像服务地址为http://127.0.0.1:9797当客户端请求/hello时两份请求会分别发往这两个地址。首先可以从config.yaml中获取admin_key并存入环境变量用于调用 Admin APIadmin_key$(yq .deployment.admin.admin_key[0].key conf/config.yaml | sed s///g)然后通过 Admin API 创建或更新路由并挂载插件curl http://127.0.0.1:9180/apisix/admin/routes/1 \ -H X-API-KEY: $admin_key -X PUT -d { plugins: { proxy-mirror: { host: http://127.0.0.1:9797 } }, upstream: { nodes: { 127.0.0.1:1999: 1 }, type: roundrobin }, uri: /hello }配置中的关键点host为镜像服务地址必须携带协议前缀且不能包含路径插件挂载在路由的plugins下APISIX 会通过 schema 校验后写入配置中心默认 etcd并热加载无需重启网关。镜像子请求的超时控制为什么需要超时控制镜像请求在 APISIX 内部是以Nginx 子请求subrequest的方式实现的。由于子请求与主请求共享事件循环子请求的延迟会阻塞原始请求——如果镜像服务响应缓慢主请求必须等到子请求完成或超时后才能正常返回。因此为镜像请求配置合理的超时时间可以避免镜像服务故障拖垮线上主链路。从 nginx 模板 apisix/cli/ngx_tpl.lua 可以看到镜像子请求的 location 会依据plugin_attr中的配置生成对应的超时指令HTTP 镜像使用proxy_connect_timeout、proxy_read_timeout、proxy_send_timeoutgRPC 镜像location /proxy_mirror_grpc则对应生成grpc_connect_timeout、grpc_read_timeout、grpc_send_timeout。在 plugin_attr 中配置超时我们可以在conf/config.yaml文件的plugin_attr中指定镜像子请求的超时时间名称类型默认值描述connectstring60s镜像请求到上游的连接超时时间。readstring60sAPISIX 与镜像服务器维持连接的时间如果在该时间内APISIX 没有收到镜像服务器的响应则关闭连接。sendstring60sAPISIX 与镜像服务器维持连接的时间如果在该时间内APISIX 没有发送请求则关闭连接。配置示例conf/config.yamlplugin_attr: proxy-mirror: timeout: connect: 2000ms read: 2000ms send: 2000ms在 conf/config.yaml.example 中同样保留了该配置的默认形态三个超时均为60s说明这是插件出厂默认的防护基线。修改该配置后需要重新生成 nginx 配置并 reload APISIX 才会生效t/cli/test_proxy_mirror_timeout.sh 这个测试脚本验证了connect: 2000ms、read: 2s、send: 2000ms会被正确渲染为 nginx.conf 中的proxy_connect_timeout 2000ms;、proxy_read_timeout 2s;指令可用作配置正确性的回归验证参考。测试插件是否生效因为上面示例指定的镜像地址是127.0.0.1:9797验证插件是否正常工作需要在端口为9797的服务上确认。可以通过python快速启动一个简单的 HTTP 服务作为镜像接收端python -m http.server 9797按上述配置启用插件后使用curl命令请求该路由请求将被镜像到所配置的主机上curl http://127.0.0.1:9080/hello -i返回的 HTTP 响应头中如果带有200状态码则表示插件生效HTTP/1.1 200 OK ... hello world从测试用例看验证要点仓库中的 t/plugin/proxy-mirror.t 提供了完整的行为级验证可作为理解插件行为与排查问题的依据请求头原样透传TEST 9镜像请求会保留原始请求的host、api-key等请求头并自动附加x-real-ip等网关头说明镜像请求与原始请求的头部语义一致镜像子请求使用 HTTP/1.1TEST 11镜像子请求发往上游时upstream_http_version为1.1采样率行为TEST 14-17sample_ratio为 1 时全采样为 0.5 时并发发送 200 个请求镜像命中数落在[75, 125]区间TEST 17验证了随机采样的统计特性自定义路径拼接TEST 18-20、27-29replace模式下镜像 URI 直接变为自定义路径/hello?a1镜像为/a?a1prefix模式下镜像 URI 为path 原始 URI/hello?a1镜像为/a/hello?a1gRPC 镜像TEST 30-31host支持grpc://与grpcs://协议验证了文档中「支持 grpc 流量镜像」的说明。采样率与镜像路径的进阶用法按比例采样镜像sample_ratio默认值为1全采样。在流量较大的场景下全量镜像会成倍放大对镜像服务的压力此时可以按比例抽样curl http://127.0.0.1:9180/apisix/admin/routes/1 \ -H X-API-KEY: $admin_key -X PUT -d { plugins: { proxy-mirror: { host: http://127.0.0.1:9797, sample_ratio: 0.5 } }, upstream: { nodes: { 127.0.0.1:1999: 1 }, type: roundrobin }, uri: /hello }从源码看采样实现位于 rewrite 阶段当sample_ratio为 1 时直接开启镜像否则生成math.random()随机值仅当随机值小于sample_ratio时才开启镜像。也就是说采样判断在每个请求上独立进行整体镜像比例在统计学上趋近于配置值。自定义镜像路径当镜像服务需要将请求收敛到固定端点或需要对原始 URI 加统一前缀时可以配合path与path_concat_mode使用replace模式默认镜像请求直接使用path作为完整路径原始 URI 被替换prefix模式镜像请求路径为path 来源请求 URI原始路径被保留在自定义前缀之后。对应的镜像 URI 构造逻辑在 enable_mirror 函数 中实现未配置path时使用upstream_uri或uri 参数作为镜像路径配置后按path_concat_mode拼接并自动附加原始查询参数。同时该函数会将解析后的镜像地址写入ctx.var.upstream_mirror_host与ctx.var.upstream_mirror_uri供 nginx 模板中的proxy_pass $upstream_mirror_uri使用。需要留意的是grpc 流量镜像不适用path与path_concat_modegRPC 镜像仅通过host决定镜像目标见 nginx 模板中grpc_pass $upstream_mirror_host的实现。域名型镜像地址的解析逻辑host除了支持 IP 直连也支持填写域名。在 resolver_host 函数 中插件会先解析host中的域名若主机部分是 IPv4 / IPv6则直接使用若为域名则调用core.resolver.parse_domain进行 DNS 解析并将域名替换为解析出的 IP保留原端口后写入镜像变量若 DNS 解析失败则记录 error 日志并继续使用原始host由 Nginx 在转发时自行解析不会导致主请求失败。对应测试为 TEST 23-26http://test.com:1980会被解析为具体 IP日志中出现test.com is resolved to: http://1.2.3.4形式而无法解析的域名not-find-domian.notfind则记录dns resolver resolves domain: ... error:日志主请求仍正常返回。删除插件当需要移除该插件时通过 Admin API 将路由配置中plugins置空即可。APISIX 会自动重新加载相关配置无需重启服务curl http://127.0.0.1:9180/apisix/admin/routes/1 \ -H X-API-KEY: $admin_key -X PUT -d { uri: /hello, plugins: {}, upstream: { type: roundrobin, nodes: { 127.0.0.1:1999: 1 } } }删除后nginx 模板中的mirror /proxy_mirror;指令也会随插件禁用而从生成的 nginx.conf 中移除模板中该指令受enabled_plugins[proxy-mirror]条件控制镜像流量随即停止。小结proxy-mirror插件以「子请求」机制实现了对线上请求的低侵入复制主请求照常转发镜像请求携带原始请求头与 URI 发往独立目标响应被丢弃。配置上只需一个必填的host辅以path、path_concat_mode、sample_ratio即可覆盖固定路径替换、前缀拼接、按比例采样等常见镜像策略通过plugin_attr中的connect/read/send超时配置可以防止慢镜像服务阻塞主链路。结合 插件源码、nginx 模板 与 行为测试可以清晰地理解其参数校验、域名解析、采样判断与超时渲染的完整实现链路为生产环境的流量镜像方案提供可靠的配置与排障依据。【免费下载链接】apisixThe Cloud-Native API Gateway项目地址: https://gitcode.com/GitHub_Trending/ap/apisix创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考