This is an automated email from the ASF dual-hosted git repository.
leslie pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git
The following commit(s) were added to refs/heads/master by this push:
new 2494b1829 feat: proxy-mirror add grpc and grpcs support (#9388)
2494b1829 is described below
commit 2494b1829e5957840c14e02fb4960191f2163dd3
Author: Sn0rt <[email protected]>
AuthorDate: Thu May 11 13:53:23 2023 +0800
feat: proxy-mirror add grpc and grpcs support (#9388)
---
apisix/cli/ngx_tpl.lua | 31 ++++++++++++++
apisix/core/ctx.lua | 1 +
apisix/init.lua | 5 +++
apisix/plugins/proxy-mirror.lua | 14 ++++---
docs/en/latest/plugins/proxy-mirror.md | 6 +--
docs/zh/latest/plugins/proxy-mirror.md | 6 +--
t/APISIX.pm | 18 ++++++++
t/plugin/proxy-mirror.t | 72 ++++++++++++++++++++++++++++++++
t/plugin/proxy-mirror3.t | 76 ++++++++++++++++++++++++++++++++++
9 files changed, 218 insertions(+), 11 deletions(-)
diff --git a/apisix/cli/ngx_tpl.lua b/apisix/cli/ngx_tpl.lua
index b1580e1e8..74b14302b 100644
--- a/apisix/cli/ngx_tpl.lua
+++ b/apisix/cli/ngx_tpl.lua
@@ -664,6 +664,7 @@ http {
{% end %}
location / {
+ set $upstream_mirror_host '';
set $upstream_mirror_uri '';
set $upstream_upgrade '';
set $upstream_connection '';
@@ -770,6 +771,10 @@ http {
grpc_socket_keepalive on;
grpc_pass $upstream_scheme://apisix_backend;
+ {% if enabled_plugins["proxy-mirror"] then %}
+ mirror /proxy_mirror_grpc;
+ {% end %}
+
header_filter_by_lua_block {
apisix.http_header_filter_phase()
}
@@ -834,6 +839,32 @@ http {
proxy_pass $upstream_mirror_uri;
}
{% end %}
+
+ {% if enabled_plugins["proxy-mirror"] then %}
+ location = /proxy_mirror_grpc {
+ internal;
+
+ {% if not use_apisix_base then %}
+ if ($upstream_mirror_uri = "") {
+ return 200;
+ }
+ {% end %}
+
+
+ {% if proxy_mirror_timeouts then %}
+ {% if proxy_mirror_timeouts.connect then %}
+ grpc_connect_timeout {* proxy_mirror_timeouts.connect *};
+ {% end %}
+ {% if proxy_mirror_timeouts.read then %}
+ grpc_read_timeout {* proxy_mirror_timeouts.read *};
+ {% end %}
+ {% if proxy_mirror_timeouts.send then %}
+ grpc_send_timeout {* proxy_mirror_timeouts.send *};
+ {% end %}
+ {% end %}
+ grpc_pass $upstream_mirror_host;
+ }
+ {% end %}
}
{% end %}
diff --git a/apisix/core/ctx.lua b/apisix/core/ctx.lua
index d723f17cb..5128061d5 100644
--- a/apisix/core/ctx.lua
+++ b/apisix/core/ctx.lua
@@ -190,6 +190,7 @@ do
upstream_connection = true,
upstream_uri = true,
+ upstream_mirror_host = true,
upstream_mirror_uri = true,
upstream_cache_zone = true,
diff --git a/apisix/init.lua b/apisix/init.lua
index bf5644521..bff68dd5b 100644
--- a/apisix/init.lua
+++ b/apisix/init.lua
@@ -77,6 +77,7 @@ local load_balancer
local local_conf
local ver_header = "APISIX/" .. core.version.VERSION
+local has_mod, apisix_ngx_client = pcall(require, "resty.apisix.client")
local _M = {version = 0.4}
@@ -716,6 +717,10 @@ function _M.grpc_access_phase()
core.log.error("failed to set grpcs upstream param: ", err)
core.response.exit(code)
end
+
+ if api_ctx.enable_mirror == true and has_mod then
+ apisix_ngx_client.enable_mirror()
+ end
end
diff --git a/apisix/plugins/proxy-mirror.lua b/apisix/plugins/proxy-mirror.lua
index 312d3ec37..d6cede6e9 100644
--- a/apisix/plugins/proxy-mirror.lua
+++ b/apisix/plugins/proxy-mirror.lua
@@ -27,7 +27,7 @@ local schema = {
properties = {
host = {
type = "string",
- pattern =
[=[^http(s)?:\/\/([\da-zA-Z.-]+|\[[\da-fA-F:]+\])(:\d+)?$]=],
+ pattern =
[=[^(http(s)?|grpc(s)?):\/\/([\da-zA-Z.-]+|\[[\da-fA-F:]+\])(:\d+)?$]=],
},
path = {
type = "string",
@@ -76,15 +76,15 @@ local function resolver_host(prop_host)
if not ip then
core.log.error("dns resolver resolves domain: ", decoded_host,"
error: ", err,
" will continue to use the host: ", decoded_host)
- return prop_host
+ return url_decoded.scheme, prop_host
end
local host = url_decoded.scheme .. '://' .. ip ..
(url_decoded.port and ':' .. url_decoded.port or '')
core.log.info(prop_host, " is resolved to: ", host)
- return host
+ return url_decoded.scheme, host
end
- return prop_host
+ return url_decoded.scheme, prop_host
end
@@ -101,7 +101,9 @@ local function enable_mirror(ctx, conf)
end
end
- ctx.var.upstream_mirror_uri = resolver_host(conf.host) .. uri
+ local _, mirror_host = resolver_host(conf.host)
+ ctx.var.upstream_mirror_host = mirror_host
+ ctx.var.upstream_mirror_uri = mirror_host .. uri
if has_mod then
apisix_ngx_client.enable_mirror()
@@ -114,12 +116,14 @@ function _M.rewrite(conf, ctx)
if conf.sample_ratio == 1 then
enable_mirror(ctx, conf)
+ ctx.enable_mirror = true
else
local val = math_random()
core.log.info("mirror request sample_ratio conf: ", conf.sample_ratio,
", random value: ", val)
if val < conf.sample_ratio then
enable_mirror(ctx, conf)
+ ctx.enable_mirror = true
end
end
diff --git a/docs/en/latest/plugins/proxy-mirror.md
b/docs/en/latest/plugins/proxy-mirror.md
index 1b97daa5b..50b11e710 100644
--- a/docs/en/latest/plugins/proxy-mirror.md
+++ b/docs/en/latest/plugins/proxy-mirror.md
@@ -39,9 +39,9 @@ The response returned by the mirror request is ignored.
| Name | Type | Required | Default | Valid values | Description
|
|--------------|--------|----------|---------|--------------|---------------------------------------------------------------------------------------------------------------------------|
-| host | string | True | | | Address of the
mirror service. It needs to contain the scheme but without the path. For
example, `http://127.0.0.1:9797`. |
-| path | string | False | | | Path of the
mirror request. If unspecified, current path will be used.
|
-| path_concat_mode | string | False | replace | ["replace", "prefix"]
| If the path of a mirror request is specified, set the concatenation mode
of request paths. The `replace` mode will directly use `path` as the path of
the mirror request. The `prefix` mode will use the `path` + `source request
URI` as the path to the mirror request. |
+| host | string | True | | | Address of the
mirror service. It needs to contain the scheme (`http(s)` or `grpc(s)`) but
without the path. For example, `http://127.0.0.1:9797`. |
+| path | string | False | | | Path of the
mirror request. If unspecified, current path will be used. If it is for
mirroring grpc traffic, this option is no longer applicable.
|
+| path_concat_mode | string | False | replace | ["replace", "prefix"]
| If the path of a mirror request is specified, set the concatenation mode
of request paths. The `replace` mode will directly use `path` as the path of
the mirror request. The `prefix` mode will use the `path` + `source request
URI` as the path to the mirror request. If it is for mirroring grpc traffic,
this option is no longer applicable too. |
| sample_ratio | number | False | 1 | [0.00001, 1] | Ratio of the
requests that will be mirrored.
|
You can customize the proxy timeouts for the mirrored sub-requests by
configuring the `plugin_attr` key in your configuration file
(`conf/config.yaml`). This can be used for mirroring traffic to a slow backend.
diff --git a/docs/zh/latest/plugins/proxy-mirror.md
b/docs/zh/latest/plugins/proxy-mirror.md
index 365368d8b..e1c7af5e5 100644
--- a/docs/zh/latest/plugins/proxy-mirror.md
+++ b/docs/zh/latest/plugins/proxy-mirror.md
@@ -40,9 +40,9 @@ description: 本文介绍了 Apache APISIX proxy-mirror 插件的相关操作,
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述
|
| ---- | ------ | ------ | ------ | ------ |
-------------------------------------------------------------------------------------------------------
|
-| host | string | 是 | | | 指定镜像服务的地址,地址中需要包含 `schema`(`http` 或
`https`),但不能包含 `path` 部分。例如 `http://127.0.0.1:9797`。 |
-| path | string | 否 | | | 指定镜像请求的路径。如果不指定,则默认会使用当前路径。 |
-| path_concat_mode | string | 否 | replace | ["replace", "prefix"]
| 当指定镜像请求的路径时,设置请求路径的拼接模式。`replace` 模式将会直接使用 `path` 作为镜像请求的路径。`prefix` 模式将会使用
`path` + `来源请求 URI` 作为镜像请求的路径。 |
+| host | string | 是 | | | 指定镜像服务的地址,地址中需要包含 `schema`(`http(s)`
或 `grpc(s)`),但不能包含 `path` 部分。例如 `http://127.0.0.1:9797`。 |
+| path | string | 否 | | | 指定镜像请求的路径。如果不指定,则默认会使用当前路径。如果是为了镜像
grpc 流量,这个选项不再适用。|
+| path_concat_mode | string | 否 | replace | ["replace", "prefix"]
| 当指定镜像请求的路径时,设置请求路径的拼接模式。`replace` 模式将会直接使用 `path` 作为镜像请求的路径。`prefix` 模式将会使用
`path` + `来源请求 URI` 作为镜像请求的路径。当然如果是为了镜像 grpc 流量,这个选项也不再适用。|
| sample_ratio | number | 否 | 1 | [0.00001, 1] | 镜像请求的采样率。当设置为
`1` 时为全采样。 |
## 启用插件
diff --git a/t/APISIX.pm b/t/APISIX.pm
index 5ab486dc4..0c057b538 100644
--- a/t/APISIX.pm
+++ b/t/APISIX.pm
@@ -206,6 +206,7 @@ $grpc_location .= <<_EOC_;
grpc_set_header TE trailers;
grpc_socket_keepalive on;
grpc_pass \$upstream_scheme://apisix_backend;
+ mirror /proxy_mirror_grpc;
header_filter_by_lua_block {
apisix.http_header_filter_phase()
@@ -743,6 +744,7 @@ _EOC_
}
location / {
+ set \$upstream_mirror_host '';
set \$upstream_mirror_uri '';
set \$upstream_upgrade '';
set \$upstream_connection '';
@@ -828,6 +830,22 @@ _EOC_
proxy_set_header Host \$upstream_host;
proxy_pass \$upstream_mirror_uri;
}
+
+ location = /proxy_mirror_grpc {
+ internal;
+_EOC_
+
+ if ($version !~ m/\/apisix-nginx-module/) {
+ $config .= <<_EOC_;
+ if (\$upstream_mirror_uri = "") {
+ return 200;
+ }
+_EOC_
+ }
+
+ $config .= <<_EOC_;
+ grpc_pass \$upstream_mirror_host;
+ }
_EOC_
$block->set_value("config", $config);
diff --git a/t/plugin/proxy-mirror.t b/t/plugin/proxy-mirror.t
index 031737d50..458bcf342 100644
--- a/t/plugin/proxy-mirror.t
+++ b/t/plugin/proxy-mirror.t
@@ -838,3 +838,75 @@ GET /hello?a=1
hello world
--- error_log
uri: /a/hello?a=1
+
+
+
+=== TEST 30: (grpc) sanity check (normal case grpc)
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "plugins": {
+ "proxy-mirror": {
+ "host": "grpc://127.0.0.1:1986"
+ }
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "scheme": "grpc",
+ "type": "roundrobin"
+ },
+ "uri": "/hello"
+ }]]
+ )
+
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- error_code: 200
+--- response_body
+passed
+
+
+
+=== TEST 31: (grpcs) sanity check (normal case for grpcs)
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "plugins": {
+ "proxy-mirror": {
+ "host": "grpcs://127.0.0.1:1986"
+ }
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "scheme": "grpc",
+ "type": "roundrobin"
+ },
+ "uri": "/hello"
+ }]]
+ )
+
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- error_code: 200
+--- response_body
+passed
diff --git a/t/plugin/proxy-mirror3.t b/t/plugin/proxy-mirror3.t
new file mode 100644
index 000000000..65a23dc82
--- /dev/null
+++ b/t/plugin/proxy-mirror3.t
@@ -0,0 +1,76 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+use t::APISIX 'no_plan';
+
+repeat_each(1);
+log_level('info');
+no_root_location();
+no_shuffle();
+
+add_block_preprocessor(sub {
+ my ($block) = @_;
+
+ my $yaml_config = $block->yaml_config // <<_EOC_;
+apisix:
+ node_listen: 1984
+deployment:
+ role: data_plane
+ role_data_plane:
+ config_provider: yaml
+_EOC_
+
+ $block->set_value("yaml_config", $yaml_config);
+
+ if (!$block->request) {
+ $block->set_value("request", "POST /hello");
+ }
+});
+
+run_tests;
+
+__DATA__
+
+=== TEST 1: grpc mirror
+--- log_level: debug
+--- http2
+--- apisix_yaml
+routes:
+ -
+ id: 1
+ uris:
+ - /helloworld.Greeter/SayHello
+ methods: [
+ POST
+ ]
+ plugins:
+ proxy-mirror:
+ host: grpc://127.0.0.1:19797
+ sample_ratio: 1
+ upstream:
+ scheme: grpc
+ nodes:
+ "127.0.0.1:50051": 1
+ type: roundrobin
+#END
+--- exec
+grpcurl -import-path ./t/grpc_server_example/proto -proto helloworld.proto
-plaintext -d '{"name":"apisix"}' 127.0.0.1:1984 helloworld.Greeter.SayHello
+--- response_body
+{
+ "message": "Hello apisix"
+}
+--- error_log eval
+qr/Connection refused\) while connecting to upstream.*proxy_mirror_grpc/