From 7d4ecc0068aebd2fc21537cfd147c19c0162dcdf Mon Sep 17 00:00:00 2001 From: root <2226815922@qq.com> Date: Thu, 4 Feb 2021 09:24:28 +0800 Subject: [PATCH 1/9] feat: the traffic-split plugin supports health check and retry mechanism close ##3094 --- apisix/plugins/traffic-split.lua | 22 +++-- t/plugin/traffic-split.t | 137 +++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+), 6 deletions(-) diff --git a/apisix/plugins/traffic-split.lua b/apisix/plugins/traffic-split.lua index bf348ccaa161..73d8a367e7c5 100644 --- a/apisix/plugins/traffic-split.lua +++ b/apisix/plugins/traffic-split.lua @@ -258,18 +258,23 @@ end local function new_rr_obj(weighted_upstreams) local server_list = {} for i, upstream_obj in ipairs(weighted_upstreams) do - if not upstream_obj.upstream then + if not upstream_obj.upstream and not upstream_obj.upstream_id then -- If the `upstream` object has only the `weight` value, it means -- that the `upstream` weight value on the default `route` has been reached. -- Need to set an identifier to mark the empty upstream. upstream_obj.upstream = "empty_upstream" + server_list[upstream_obj.upstream] = upstream_obj.weight end - if type(upstream_obj.upstream) == "table" then - -- Add a virtual id field to uniquely identify the upstream `key`. - upstream_obj.upstream.vid = i + if upstream_obj.upstream_id then + server_list[upstream_obj.upstream_id] = upstream_obj.weight + else + if type(upstream_obj.upstream) == "table" then + -- Add a virtual id field to uniquely identify the upstream `key`. + upstream_obj.upstream.vid = i + end + server_list[upstream_obj.upstream] = upstream_obj.weight end - server_list[upstream_obj.upstream] = upstream_obj.weight end return roundrobin:new(server_list) @@ -315,11 +320,16 @@ function _M.access(conf, ctx) end local upstream = rr_up:find() - if upstream and upstream ~= "empty_upstream" then + if upstream and type(upstream) == "table" then core.log.info("upstream: ", core.json.encode(upstream)) return set_upstream(upstream, ctx) + elseif upstream and upstream ~= "empty_upstream" then + ctx.matched_route.value.upstream_id = upstream + core.log.info("upstream_id: ", upstream) + return end + ctx.matched_route.value.upstream_id = nil return end diff --git a/t/plugin/traffic-split.t b/t/plugin/traffic-split.t index 7c38b6831e5d..a1d6a50e7c2b 100644 --- a/t/plugin/traffic-split.t +++ b/t/plugin/traffic-split.t @@ -1550,3 +1550,140 @@ GET /t 1980, 1981, 1981, 1982, 1982 --- no_error_log [error] + + + +=== TEST 44: set upstream(id: 1) +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/upstreams/1', + ngx.HTTP_PUT, + [[{ + "nodes": { + "127.0.0.1:1981": 1 + }, + "type": "roundrobin", + "desc": "new upstream" + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 45: set upstream(id: 2) +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/upstreams/2', + ngx.HTTP_PUT, + [[{ + "nodes": { + "127.0.0.1:1982": 1 + }, + "type": "roundrobin", + "desc": "new upstream" + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 46: the upstream is bound by upstream_id +--- 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, + [=[{ + "uri": "/server_port", + "plugins": { + "traffic-split": { + "rules": [ + { + "match": [ + { + "vars": [["arg_x-api-name", "==", "jack"], ["arg_x-api-age", ">", "23"],["http_x-api-appkey", "~~", "[a-z]{1,5}"]] + } + ], + "weighted_upstreams": [ + {"upstream_id": 2, "weight": 2}, + {"upstream_id": 1, "weight": 2}, + {"weight": 1} + ] + } + ] + } + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "127.0.0.1:1980": 1 + } + } + }]=] + ) + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 47: `match` rule passed +--- config +location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local bodys = {} + local headers = {} + headers["x-api-appkey"] = "hello" + for i = 1, 5 do + local _, _, body = t('/server_port?x-api-name=jack&x-api-age=36', ngx.HTTP_GET, "", nil, headers) + bodys[i] = body + end + table.sort(bodys) + ngx.say(table.concat(bodys, ", ")) + } +} +--- request +GET /t +--- response_body +1980, 1981, 1981, 1982, 1982 +--- no_error_log +[error] From 57c7fcd103e08099f4501d796787516b8cba242a Mon Sep 17 00:00:00 2001 From: root <2226815922@qq.com> Date: Thu, 4 Feb 2021 19:35:02 +0800 Subject: [PATCH 2/9] add docs and test cases. --- apisix/plugins/traffic-split.lua | 12 +- doc/plugins/traffic-split.md | 56 ++++- doc/zh-cn/plugins/traffic-split.md | 56 ++++- t/plugin/traffic-split.t | 324 ++++++++++++++++++++++++++++- 4 files changed, 414 insertions(+), 34 deletions(-) diff --git a/apisix/plugins/traffic-split.lua b/apisix/plugins/traffic-split.lua index 73d8a367e7c5..c2b2b6a72abf 100644 --- a/apisix/plugins/traffic-split.lua +++ b/apisix/plugins/traffic-split.lua @@ -262,17 +262,15 @@ local function new_rr_obj(weighted_upstreams) -- If the `upstream` object has only the `weight` value, it means -- that the `upstream` weight value on the default `route` has been reached. -- Need to set an identifier to mark the empty upstream. - upstream_obj.upstream = "empty_upstream" + upstream_obj.upstream = "plugin#upstream#is#empty" server_list[upstream_obj.upstream] = upstream_obj.weight end if upstream_obj.upstream_id then server_list[upstream_obj.upstream_id] = upstream_obj.weight - else - if type(upstream_obj.upstream) == "table" then - -- Add a virtual id field to uniquely identify the upstream `key`. - upstream_obj.upstream.vid = i - end + elseif type(upstream_obj.upstream) == "table" then + -- Add a virtual id field to uniquely identify the upstream `key`. + upstream_obj.upstream.vid = i server_list[upstream_obj.upstream] = upstream_obj.weight end end @@ -323,7 +321,7 @@ function _M.access(conf, ctx) if upstream and type(upstream) == "table" then core.log.info("upstream: ", core.json.encode(upstream)) return set_upstream(upstream, ctx) - elseif upstream and upstream ~= "empty_upstream" then + elseif upstream and upstream ~= "plugin#upstream#is#empty" then ctx.matched_route.value.upstream_id = upstream core.log.info("upstream_id: ", upstream) return diff --git a/doc/plugins/traffic-split.md b/doc/plugins/traffic-split.md index 1d90aa714bad..8c8b7b1555b4 100644 --- a/doc/plugins/traffic-split.md +++ b/doc/plugins/traffic-split.md @@ -21,14 +21,14 @@ # Summary -- [**Name**](#name) -- [**Attributes**](#attributes) -- [**How To Enable**](#how-to-enable) -- [**Example**](#example) - - [**Grayscale Release**](#grayscale-release) - - [**Blue-green Release**](#blue-green-release) - - [**Custom Release**](#custom-release) -- [**Disable Plugin**](#disable-plugin) + - [**Name**](#name) + - [**Attributes**](#attributes) + - [**How To Enable**](#how-to-enable) + - [**Example**](#example) + - [**Grayscale Release**](#grayscale-release) + - [**Blue-green Release**](#blue-green-release) + - [**Custom Release**](#custom-release) + - [**Disable Plugin**](#disable-plugin) ## Name @@ -43,7 +43,7 @@ Note: The ratio between each upstream may not so accurate since the drawback of | rules.match | array[object] | optional | | | List of matching rules. | | rules.match.vars | array[array] | optional | | | A list consisting of one or more {var, operator, val} elements, like this: {{var, operator, val}, {var, operator, val}, ...}}. For example: {"arg_name", "==", "json"}, which means that the current request parameter name is json. The var here is consistent with the naming of Nginx internal variables, so request_uri, host, etc. can also be used; for the operator part, the currently supported operators are ==, ~=, ~~, >, <, in, has and !. For specific usage of operators, please see the `operator-list` part of [lua-resty-expr](https://github.com/api7/lua-resty-expr#operator-list). | | rules.weighted_upstreams | array[object] | optional | | | List of upstream configuration rules. | -| weighted_upstreams.upstream_id | string/integer| optional | | | The upstream id is bound to the corresponding upstream(not currently supported). | +| weighted_upstreams.upstream_id | string/integer| optional | | | The upstream id is bound to the corresponding upstream. | | weighted_upstreams.upstream | object | optional | | | Upstream configuration information. | | upstream.type | enum | optional | roundrobin | [roundrobin, chash] | roundrobin supports weighted load, chash consistent hashing, the two are alternatives. | | upstream.nodes | object | optional | | | In the hash table, the key of the internal element is the list of upstream machine addresses, in the format of address + Port, where the address part can be an IP or a domain name, such as 192.168.1.100:80, foo.com:80, etc. value is the weight of the node. In particular, when the weight value is 0, it has special meaning, which usually means that the upstream node is invalid and never wants to be selected. | @@ -68,7 +68,9 @@ The traffic-split plugin is mainly composed of two parts: `match` and `weighted_ ## How To Enable -Create a route and enable the `traffic-split` plugin: +Create a route and enable the `traffic-split` plugin. When configuring the upstream information of the plugin, there are two ways: + +1. Configure upstream information through the `upstream` attribute in the plugin. ```shell curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' @@ -111,6 +113,40 @@ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f13 }' ``` +2. Binding upstream services through the `upstream_id` attribute in the plugin. + +```shell +curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' +{ + "uri": "/index.html", + "plugins": { + "traffic-split": { + "rules": [ + { + "weighted_upstreams": [ + { + "upstream_id": 1, + "weight": 1 + }, + { + "weight": 1 + } + ] + } + ] + } + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "127.0.0.1:1980": 1 + } + } +}' +``` + +>Note: **1.** Binding upstream services via `upstream_id`. It can reuse functions such as health detection and retry mechanism of upstream services. **2.** Support the two configuration methods of `upstream` and `upstream_id` to be used together. + ## Example ### Grayscale Release diff --git a/doc/zh-cn/plugins/traffic-split.md b/doc/zh-cn/plugins/traffic-split.md index ddf66fcaea9b..54c0e048c416 100644 --- a/doc/zh-cn/plugins/traffic-split.md +++ b/doc/zh-cn/plugins/traffic-split.md @@ -21,14 +21,14 @@ # 目录 -- [名字](#名字) -- [属性](#属性) -- [如何启用](#如何启用) -- [示例](#示例) - - [灰度发布](#灰度发布) - - [蓝绿发布](#蓝绿发布) - - [自定义发布](#自定义发布) -- [禁用插件](#禁用插件) + - [名字](#名字) + - [属性](#属性) + - [如何启用](#如何启用) + - [示例](#示例) + - [灰度发布](#灰度发布) + - [蓝绿发布](#蓝绿发布) + - [自定义发布](#自定义发布) + - [禁用插件](#禁用插件) ## 名字 @@ -43,7 +43,7 @@ traffic-split 插件使用户可以逐步引导各个上游之间的流量百分 | rules.match | array[object] | 可选 | | | 匹配规则列表 | | rules.match.vars | array[array] | 可选 | | | 由一个或多个{var, operator, val}元素组成的列表,类似这样:{{var, operator, val}, {var, operator, val}, ...}}。例如:{"arg_name", "==", "json"},表示当前请求参数 name 是 json。这里的 var 与 Nginx 内部自身变量命名是保持一致,所以也可以使用 request_uri、host 等;对于 operator 部分,目前已支持的运算符有 ==、~=、~~、>、<、in、has 和 ! 。操作符的具体用法请看 [lua-resty-expr](https://github.com/api7/lua-resty-expr#operator-list) 的 `operator-list` 部分。 | | rules.weighted_upstreams | array[object] | 可选 | | | 上游配置规则列表。 | -| weighted_upstreams.upstream_id | string / integer | 可选 | | | 通过上游 id 绑定对应上游(暂不支持)。 | +| weighted_upstreams.upstream_id | string / integer | 可选 | | | 通过上游 id 绑定对应上游。 | | weighted_upstreams.upstream | object | 可选 | | | 上游配置信息。 | | upstream.type | enum | 可选 | roundrobin | [roundrobin, chash] | roundrobin 支持权重的负载,chash 一致性哈希,两者是二选一的(目前只支持 `roundrobin`)。 | | upstream.nodes | object | 可选 | | | 哈希表,内部元素的 key 是上游机器地址 列表,格式为地址 + Port,其中地址部 分可以是 IP 也可以是域名,⽐如 192.168.1.100:80、foo.com:80等。 value 则是节点的权重,特别的,当权重 值为 0 有特殊含义,通常代表该上游节点 失效,永远不希望被选中。 | @@ -68,7 +68,9 @@ traffic-split 插件主要由 `match` 和 `weighted_upstreams` 两部分组成 ## 如何启用 -创建一个路由并启用 `traffic-split` 插件: +创建一个路由并启用 `traffic-split` 插件,在配置插件上游信息时,有以下两种方式: + +1、通过插件中的 `upstream` 属性配置上游信息。 ```shell curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' @@ -111,6 +113,40 @@ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f13 }' ``` +2、通过插件中的 `upstream_id` 属性绑定上游服务。 + +```shell +curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' +{ + "uri": "/index.html", + "plugins": { + "traffic-split": { + "rules": [ + { + "weighted_upstreams": [ + { + "upstream_id": 1, + "weight": 1 + }, + { + "weight": 1 + } + ] + } + ] + } + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "127.0.0.1:1980": 1 + } + } +}' +``` + +>注:1、通过 `upstream_id` 方式绑定上游服务,可以复用上游服务具有的健康检测、重试机制等功能。2、支持 `upstream` 和 `upstream_id` 的两种配置方式一起使用。 + ## 示例 ### 灰度发布 diff --git a/t/plugin/traffic-split.t b/t/plugin/traffic-split.t index a1d6a50e7c2b..3ca07f4a2404 100644 --- a/t/plugin/traffic-split.t +++ b/t/plugin/traffic-split.t @@ -1615,7 +1615,7 @@ passed -=== TEST 46: the upstream is bound by upstream_id +=== TEST 46: the upstream_id is used in the plugin --- config location /t { content_by_lua_block { @@ -1630,13 +1630,13 @@ passed { "match": [ { - "vars": [["arg_x-api-name", "==", "jack"], ["arg_x-api-age", ">", "23"],["http_x-api-appkey", "~~", "[a-z]{1,5}"]] + "vars": [["arg_x-api-name", "==", "jack"]] } ], "weighted_upstreams": [ - {"upstream_id": 2, "weight": 2}, {"upstream_id": 1, "weight": 2}, - {"weight": 1} + {"upstream_id": 2, "weight": 1}, + {"weight": 2} ] } ] @@ -1665,7 +1665,7 @@ passed -=== TEST 47: `match` rule passed +=== TEST 47: `match` rule passed(upstream_id) --- config location /t { content_by_lua_block { @@ -1674,7 +1674,7 @@ location /t { local headers = {} headers["x-api-appkey"] = "hello" for i = 1, 5 do - local _, _, body = t('/server_port?x-api-name=jack&x-api-age=36', ngx.HTTP_GET, "", nil, headers) + local _, _, body = t('/server_port?x-api-name=jack', ngx.HTTP_GET, "", nil, headers) bodys[i] = body end table.sort(bodys) @@ -1684,6 +1684,316 @@ location /t { --- request GET /t --- response_body -1980, 1981, 1981, 1982, 1982 +1980, 1980, 1981, 1981, 1982 +--- no_error_log +[error] + + + +=== TEST 48: use upstream and upstream_id in the plugin +--- 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, + [=[{ + "uri": "/server_port", + "plugins": { + "traffic-split": { + "rules": [ + { + "match": [ + { + "vars": [["arg_x-api-name", "==", "jack"]] + } + ], + "weighted_upstreams": [ + {"upstream_id": 1, "weight": 2}, + {"upstream": {"type": "roundrobin", "nodes": [{"host":"127.0.0.1", "port":1982, "weight": 1}]}, "weight": 1}, + {"weight": 2} + ] + } + ] + } + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "127.0.0.1:1980": 1 + } + } + }]=] + ) + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 49: `match` rule passed(upstream + upstream_id) +--- config +location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local bodys = {} + local headers = {} + headers["x-api-appkey"] = "hello" + for i = 1, 5 do + local _, _, body = t('/server_port?x-api-name=jack', ngx.HTTP_GET, "", nil, headers) + bodys[i] = body + end + table.sort(bodys) + ngx.say(table.concat(bodys, ", ")) + } +} +--- request +GET /t +--- response_body +1980, 1980, 1981, 1981, 1982 +--- no_error_log +[error] + + + +=== TEST 50: set route + upstream (two upstream node: one healthy + one unhealthy) +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/upstreams/1', + ngx.HTTP_PUT, + [[{ + "type": "roundrobin", + "nodes": { + "127.0.0.1:1981": 1, + "127.0.0.1:1970": 1 + }, + "checks": { + "active": { + "http_path": "/status", + "host": "foo.com", + "healthy": { + "interval": 1, + "successes": 1 + }, + "unhealthy": { + "interval": 1, + "http_failures": 2 + } + } + } + }]] + ) + + if code >= 300 then + ngx.status = code + ngx.say(body) + return + end + + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [=[{ + "uri": "/server_port", + "plugins": { + "traffic-split": { + "rules": [ + { + "weighted_upstreams": [ + {"upstream_id": 1, "weight": 1}, + {"weight": 1} + ] + } + ] + } + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "127.0.0.1:1980": 1 + } + } + }]=] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed +--- grep_error_log eval +qr/^.*?\[error\](?!.*process exiting).*/ +--- grep_error_log_out + + + +=== TEST 51: hit routes, ensure the checker is bound to the upstream +--- config + location /t { + content_by_lua_block { + local http = require "resty.http" + local uri = "http://127.0.0.1:" .. ngx.var.server_port + .. "/server_port" + + do + local httpc = http.new() + local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false}) + end + + ngx.sleep(2.5) + + local ports_count = {} + for i = 1, 12 do + local httpc = http.new() + local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false}) + if not res then + ngx.say(err) + return + end + + ports_count[res.body] = (ports_count[res.body] or 0) + 1 + end + + local ports_arr = {} + for port, count in pairs(ports_count) do + table.insert(ports_arr, {port = port, count = count}) + end + + local function cmd(a, b) + return a.port > b.port + end + table.sort(ports_arr, cmd) + + ngx.say(require("toolkit.json").encode(ports_arr)) + ngx.exit(200) + } + } +--- request +GET /t +--- response_body +[{"count":6,"port":"1981"},{"count":6,"port":"1980"}] +--- grep_error_log eval +qr/\([^)]+\) unhealthy .* for '.*'/ +--- grep_error_log_out +(upstream#/apisix/upstreams/1) unhealthy TCP increment (1/2) for 'foo.com(127.0.0.1:1970)' +(upstream#/apisix/upstreams/1) unhealthy TCP increment (2/2) for 'foo.com(127.0.0.1:1970)' +--- timeout: 10 + + + +=== TEST 52: set upstream(id: 1), by default retries count = number of nodes +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/upstreams/1', + ngx.HTTP_PUT, + [[{ + "nodes": { + "127.0.0.1:1": 1, + "127.0.0.2:1": 1, + "127.0.0.3:1": 1 + }, + "type": "roundrobin" + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed --- no_error_log [error] + + + +=== TEST 53: set route(id: 1) +--- 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, + [=[{ + "uri": "/server_port", + "plugins": { + "traffic-split": { + "rules": [ + { + "weighted_upstreams": [ + {"upstream_id": 1, "weight": 1} + ] + } + ] + } + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "127.0.0.1:1982": 1 + } + } + }]=] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 54: /not_found +--- request +GET /not_found +--- error_code: 404 +--- response_body +{"error_msg":"404 Route Not Found"} +--- no_error_log +[error] +--- LAST + + +=== TEST 55: hit routes +--- pipelined_requests eval +["GET /server_port", "GET /server_port"] +--- error_code eval +[200, 502] +--- grep_error_log eval +qr/\[error\]/ +--- grep_error_log_out +[error] +[error] +[error] +[error] + + From fbfe900a38c73b306fa37f5d4bcae87e522458dd Mon Sep 17 00:00:00 2001 From: root <2226815922@qq.com> Date: Fri, 5 Feb 2021 01:08:04 +0800 Subject: [PATCH 3/9] update test cases. --- apisix/plugins/traffic-split.lua | 1 + t/plugin/traffic-split.t | 55 +++++++++++++------------------- 2 files changed, 24 insertions(+), 32 deletions(-) diff --git a/apisix/plugins/traffic-split.lua b/apisix/plugins/traffic-split.lua index c2b2b6a72abf..39273dee068e 100644 --- a/apisix/plugins/traffic-split.lua +++ b/apisix/plugins/traffic-split.lua @@ -327,6 +327,7 @@ function _M.access(conf, ctx) return end + core.log.info("default_up: ", upstream) ctx.matched_route.value.upstream_id = nil return end diff --git a/t/plugin/traffic-split.t b/t/plugin/traffic-split.t index 3ca07f4a2404..a9c146b26fc5 100644 --- a/t/plugin/traffic-split.t +++ b/t/plugin/traffic-split.t @@ -1850,22 +1850,14 @@ qr/^.*?\[error\](?!.*process exiting).*/ local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/server_port" - do - local httpc = http.new() - local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false}) - end - - ngx.sleep(2.5) - local ports_count = {} - for i = 1, 12 do + for i = 1, 10 do local httpc = http.new() local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false}) if not res then ngx.say(err) return end - ports_count[res.body] = (ports_count[res.body] or 0) + 1 end @@ -1886,13 +1878,13 @@ qr/^.*?\[error\](?!.*process exiting).*/ --- request GET /t --- response_body -[{"count":6,"port":"1981"},{"count":6,"port":"1980"}] +[{"count":5,"port":"1981"},{"count":5,"port":"1980"}] --- grep_error_log eval qr/\([^)]+\) unhealthy .* for '.*'/ --- grep_error_log_out (upstream#/apisix/upstreams/1) unhealthy TCP increment (1/2) for 'foo.com(127.0.0.1:1970)' (upstream#/apisix/upstreams/1) unhealthy TCP increment (2/2) for 'foo.com(127.0.0.1:1970)' ---- timeout: 10 +--- timeout: 12 @@ -1928,7 +1920,7 @@ passed -=== TEST 53: set route(id: 1) +=== TEST 53: set route(id: 1, upstream_id: 1) --- config location /t { content_by_lua_block { @@ -1936,7 +1928,7 @@ passed local code, body = t('/apisix/admin/routes/1', ngx.HTTP_PUT, [=[{ - "uri": "/server_port", + "uri": "/hello", "plugins": { "traffic-split": { "rules": [ @@ -1951,7 +1943,7 @@ passed "upstream": { "type": "roundrobin", "nodes": { - "127.0.0.1:1982": 1 + "127.0.0.1:1980": 1 } } }]=] @@ -1972,28 +1964,27 @@ passed -=== TEST 54: /not_found ---- request -GET /not_found ---- error_code: 404 ---- response_body -{"error_msg":"404 Route Not Found"} ---- no_error_log -[error] ---- LAST - +=== TEST 54: hit routes +--- config +location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + do + local code, _ = t('/hello', ngx.HTTP_GET) + end -=== TEST 55: hit routes ---- pipelined_requests eval -["GET /server_port", "GET /server_port"] ---- error_code eval -[200, 502] + local code, _ = t('/hello', ngx.HTTP_GET) + if code >= 300 then + ngx.status = code + end + } +} +--- request +GET /t +--- error_code: 502 --- grep_error_log eval qr/\[error\]/ --- grep_error_log_out [error] [error] [error] -[error] - - From d24047ebe1bb70faddffc53037c5c072515e24ca Mon Sep 17 00:00:00 2001 From: root <2226815922@qq.com> Date: Fri, 5 Feb 2021 01:26:23 +0800 Subject: [PATCH 4/9] update docs. --- apisix/plugins/traffic-split.lua | 5 ++++- doc/plugins/traffic-split.md | 16 ++++++++-------- doc/zh-cn/plugins/traffic-split.md | 16 ++++++++-------- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/apisix/plugins/traffic-split.lua b/apisix/plugins/traffic-split.lua index 39273dee068e..f492c7200200 100644 --- a/apisix/plugins/traffic-split.lua +++ b/apisix/plugins/traffic-split.lua @@ -261,7 +261,7 @@ local function new_rr_obj(weighted_upstreams) if not upstream_obj.upstream and not upstream_obj.upstream_id then -- If the `upstream` object has only the `weight` value, it means -- that the `upstream` weight value on the default `route` has been reached. - -- Need to set an identifier to mark the empty upstream. + -- Mark empty upstream services in the plugin, but with weight. upstream_obj.upstream = "plugin#upstream#is#empty" server_list[upstream_obj.upstream] = upstream_obj.weight end @@ -322,6 +322,9 @@ function _M.access(conf, ctx) core.log.info("upstream: ", core.json.encode(upstream)) return set_upstream(upstream, ctx) elseif upstream and upstream ~= "plugin#upstream#is#empty" then + -- There is a problem here. When the plugin only binds upstream + -- services through upstream_id, by default the first request + -- will access the upstream service configured on the route. ctx.matched_route.value.upstream_id = upstream core.log.info("upstream_id: ", upstream) return diff --git a/doc/plugins/traffic-split.md b/doc/plugins/traffic-split.md index 8c8b7b1555b4..630cdd28fc9b 100644 --- a/doc/plugins/traffic-split.md +++ b/doc/plugins/traffic-split.md @@ -21,14 +21,14 @@ # Summary - - [**Name**](#name) - - [**Attributes**](#attributes) - - [**How To Enable**](#how-to-enable) - - [**Example**](#example) - - [**Grayscale Release**](#grayscale-release) - - [**Blue-green Release**](#blue-green-release) - - [**Custom Release**](#custom-release) - - [**Disable Plugin**](#disable-plugin) +- [**Name**](#name) +- [**Attributes**](#attributes) +- [**How To Enable**](#how-to-enable) +- [**Example**](#example) + - [**Grayscale Release**](#grayscale-release) + - [**Blue-green Release**](#blue-green-release) + - [**Custom Release**](#custom-release) +- [**Disable Plugin**](#disable-plugin) ## Name diff --git a/doc/zh-cn/plugins/traffic-split.md b/doc/zh-cn/plugins/traffic-split.md index 54c0e048c416..6b6340d3edd1 100644 --- a/doc/zh-cn/plugins/traffic-split.md +++ b/doc/zh-cn/plugins/traffic-split.md @@ -21,14 +21,14 @@ # 目录 - - [名字](#名字) - - [属性](#属性) - - [如何启用](#如何启用) - - [示例](#示例) - - [灰度发布](#灰度发布) - - [蓝绿发布](#蓝绿发布) - - [自定义发布](#自定义发布) - - [禁用插件](#禁用插件) +- [名字](#名字) +- [属性](#属性) +- [如何启用](#如何启用) +- [示例](#示例) + - [灰度发布](#灰度发布) + - [蓝绿发布](#蓝绿发布) + - [自定义发布](#自定义发布) +- [禁用插件](#禁用插件) ## 名字 From 60ad01b94d809b17c5df7562e010b19e1ce1a6ca Mon Sep 17 00:00:00 2001 From: root <2226815922@qq.com> Date: Sat, 6 Feb 2021 17:37:31 +0800 Subject: [PATCH 5/9] update test case --- apisix/init.lua | 54 +++++----- apisix/plugins/traffic-split.lua | 5 +- t/plugin/traffic-split.t | 171 +++++++++++++++++++++---------- 3 files changed, 147 insertions(+), 83 deletions(-) diff --git a/apisix/init.lua b/apisix/init.lua index f1ec7a6601e2..e100e41fb91d 100644 --- a/apisix/init.lua +++ b/apisix/init.lua @@ -338,6 +338,33 @@ function _M.http_access_phase() api_ctx.route_id = route.value.id api_ctx.route_name = route.value.name + if route.value.script then + script.load(route, api_ctx) + script.run("access", api_ctx) + else + local plugins = plugin.filter(route) + api_ctx.plugins = plugins + + plugin.run_plugin("rewrite", plugins, api_ctx) + if api_ctx.consumer then + local changed + route, changed = plugin.merge_consumer_route( + route, + api_ctx.consumer, + api_ctx + ) + + core.log.info("find consumer ", api_ctx.consumer.username, + ", config changed: ", changed) + + if changed then + core.table.clear(api_ctx.plugins) + api_ctx.plugins = plugin.filter(route, api_ctx.plugins) + end + end + plugin.run_plugin("access", plugins, api_ctx) + end + local up_id = route.value.upstream_id if up_id then local upstreams = core.config.fetch_created_obj("/upstreams") @@ -405,33 +432,6 @@ function _M.http_access_phase() core.log.info("enabled websocket for route: ", route.value.id) end - if route.value.script then - script.load(route, api_ctx) - script.run("access", api_ctx) - else - local plugins = plugin.filter(route) - api_ctx.plugins = plugins - - plugin.run_plugin("rewrite", plugins, api_ctx) - if api_ctx.consumer then - local changed - route, changed = plugin.merge_consumer_route( - route, - api_ctx.consumer, - api_ctx - ) - - core.log.info("find consumer ", api_ctx.consumer.username, - ", config changed: ", changed) - - if changed then - core.table.clear(api_ctx.plugins) - api_ctx.plugins = plugin.filter(route, api_ctx.plugins) - end - end - plugin.run_plugin("access", plugins, api_ctx) - end - if route.value.service_protocol == "grpc" then api_ctx.upstream_scheme = "grpc" end diff --git a/apisix/plugins/traffic-split.lua b/apisix/plugins/traffic-split.lua index f492c7200200..8826dbca435f 100644 --- a/apisix/plugins/traffic-split.lua +++ b/apisix/plugins/traffic-split.lua @@ -322,15 +322,12 @@ function _M.access(conf, ctx) core.log.info("upstream: ", core.json.encode(upstream)) return set_upstream(upstream, ctx) elseif upstream and upstream ~= "plugin#upstream#is#empty" then - -- There is a problem here. When the plugin only binds upstream - -- services through upstream_id, by default the first request - -- will access the upstream service configured on the route. ctx.matched_route.value.upstream_id = upstream core.log.info("upstream_id: ", upstream) return end - core.log.info("default_up: ", upstream) + core.log.info("route_up: ", upstream) ctx.matched_route.value.upstream_id = nil return end diff --git a/t/plugin/traffic-split.t b/t/plugin/traffic-split.t index a9c146b26fc5..435c04bf768e 100644 --- a/t/plugin/traffic-split.t +++ b/t/plugin/traffic-split.t @@ -1690,7 +1690,81 @@ GET /t -=== TEST 48: use upstream and upstream_id in the plugin +=== TEST 48: only use upstream_id in the plugin +--- 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, + [=[{ + "uri": "/server_port", + "plugins": { + "traffic-split": { + "rules": [ + { + "match": [ + { + "vars": [["arg_x-api-name", "==", "jack"]] + } + ], + "weighted_upstreams": [ + {"upstream_id": 1, "weight": 1}, + {"upstream_id": 2, "weight": 1} + ] + } + ] + } + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "127.0.0.1:1980": 1 + } + } + }]=] + ) + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 49: `match` rule passed(only use upstream_id) +--- config +location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local bodys = {} + local headers = {} + headers["x-api-appkey"] = "hello" + for i = 1, 4 do + local _, _, body = t('/server_port?x-api-name=jack', ngx.HTTP_GET, "", nil, headers) + bodys[i] = body + end + table.sort(bodys) + ngx.say(table.concat(bodys, ", ")) + } +} +--- request +GET /t +--- response_body +1981, 1981, 1982, 1982 +--- no_error_log +[error] + + + +=== TEST 50: use upstream and upstream_id in the plugin --- config location /t { content_by_lua_block { @@ -1740,7 +1814,7 @@ passed -=== TEST 49: `match` rule passed(upstream + upstream_id) +=== TEST 51: `match` rule passed(upstream + upstream_id) --- config location /t { content_by_lua_block { @@ -1765,7 +1839,7 @@ GET /t -=== TEST 50: set route + upstream (two upstream node: one healthy + one unhealthy) +=== TEST 52: set route + upstream (two upstream node: one healthy + one unhealthy) --- config location /t { content_by_lua_block { @@ -1810,8 +1884,7 @@ GET /t "rules": [ { "weighted_upstreams": [ - {"upstream_id": 1, "weight": 1}, - {"weight": 1} + {"upstream_id": 1, "weight": 1} ] } ] @@ -1842,53 +1915,61 @@ qr/^.*?\[error\](?!.*process exiting).*/ -=== TEST 51: hit routes, ensure the checker is bound to the upstream +=== TEST 53: hit routes, ensure the checker is bound to the upstream --- config - location /t { - content_by_lua_block { - local http = require "resty.http" - local uri = "http://127.0.0.1:" .. ngx.var.server_port - .. "/server_port" - - local ports_count = {} - for i = 1, 10 do - local httpc = http.new() - local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false}) - if not res then - ngx.say(err) - return - end - ports_count[res.body] = (ports_count[res.body] or 0) + 1 - end +location /t { + content_by_lua_block { + local http = require "resty.http" + local uri = "http://127.0.0.1:" .. ngx.var.server_port + .. "/server_port" - local ports_arr = {} - for port, count in pairs(ports_count) do - table.insert(ports_arr, {port = port, count = count}) - end + do + local httpc = http.new() + local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false}) + end - local function cmd(a, b) - return a.port > b.port + ngx.sleep(2.5) + + local ports_count = {} + for i = 1, 6 do + local httpc = http.new() + local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false}) + if not res then + ngx.say(err) + return end - table.sort(ports_arr, cmd) - ngx.say(require("toolkit.json").encode(ports_arr)) - ngx.exit(200) - } + ports_count[res.body] = (ports_count[res.body] or 0) + 1 + end + + local ports_arr = {} + for port, count in pairs(ports_count) do + table.insert(ports_arr, {port = port, count = count}) + end + + local function cmd(a, b) + return a.port > b.port + end + table.sort(ports_arr, cmd) + + ngx.say(require("toolkit.json").encode(ports_arr)) + ngx.exit(200) } +} --- request GET /t --- response_body -[{"count":5,"port":"1981"},{"count":5,"port":"1980"}] +[{"count":6,"port":"1981"}] --- grep_error_log eval qr/\([^)]+\) unhealthy .* for '.*'/ --- grep_error_log_out (upstream#/apisix/upstreams/1) unhealthy TCP increment (1/2) for 'foo.com(127.0.0.1:1970)' (upstream#/apisix/upstreams/1) unhealthy TCP increment (2/2) for 'foo.com(127.0.0.1:1970)' ---- timeout: 12 +--- timeout: 10 -=== TEST 52: set upstream(id: 1), by default retries count = number of nodes +=== TEST 54: set upstream(id: 1), by default retries count = number of nodes --- config location /t { content_by_lua_block { @@ -1920,7 +2001,7 @@ passed -=== TEST 53: set route(id: 1, upstream_id: 1) +=== TEST 55: set route(id: 1, upstream_id: 1) --- config location /t { content_by_lua_block { @@ -1964,23 +2045,9 @@ passed -=== TEST 54: hit routes ---- config -location /t { - content_by_lua_block { - local t = require("lib.test_admin").test - do - local code, _ = t('/hello', ngx.HTTP_GET) - end - - local code, _ = t('/hello', ngx.HTTP_GET) - if code >= 300 then - ngx.status = code - end - } -} +=== TEST 56: hit routes --- request -GET /t +GET /hello --- error_code: 502 --- grep_error_log eval qr/\[error\]/ From 701897f4bd5787171002b57a9116b5e44357fc8b Mon Sep 17 00:00:00 2001 From: root <2226815922@qq.com> Date: Sat, 6 Feb 2021 18:35:38 +0800 Subject: [PATCH 6/9] update test case. --- t/plugin/traffic-split.t | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/t/plugin/traffic-split.t b/t/plugin/traffic-split.t index 435c04bf768e..8478ff88756c 100644 --- a/t/plugin/traffic-split.t +++ b/t/plugin/traffic-split.t @@ -2050,8 +2050,8 @@ passed GET /hello --- error_code: 502 --- grep_error_log eval -qr/\[error\]/ +qr/\([^)]+\) while connecting to upstream/ --- grep_error_log_out -[error] -[error] -[error] +(111: Connection refused) while connecting to upstream +(111: Connection refused) while connecting to upstream +(111: Connection refused) while connecting to upstream From 076b7316ed2b9a61b407359e5dd01e5932c4b7fd Mon Sep 17 00:00:00 2001 From: root <2226815922@qq.com> Date: Sun, 7 Feb 2021 13:58:21 +0800 Subject: [PATCH 7/9] fix review. --- apisix/plugins/traffic-split.lua | 18 ++++++++---------- doc/plugins/traffic-split.md | 4 ++-- doc/zh-cn/plugins/traffic-split.md | 2 +- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/apisix/plugins/traffic-split.lua b/apisix/plugins/traffic-split.lua index 8826dbca435f..4385677b0481 100644 --- a/apisix/plugins/traffic-split.lua +++ b/apisix/plugins/traffic-split.lua @@ -258,20 +258,18 @@ end local function new_rr_obj(weighted_upstreams) local server_list = {} for i, upstream_obj in ipairs(weighted_upstreams) do - if not upstream_obj.upstream and not upstream_obj.upstream_id then - -- If the `upstream` object has only the `weight` value, it means - -- that the `upstream` weight value on the default `route` has been reached. - -- Mark empty upstream services in the plugin, but with weight. - upstream_obj.upstream = "plugin#upstream#is#empty" - server_list[upstream_obj.upstream] = upstream_obj.weight - end - if upstream_obj.upstream_id then server_list[upstream_obj.upstream_id] = upstream_obj.weight - elseif type(upstream_obj.upstream) == "table" then - -- Add a virtual id field to uniquely identify the upstream `key`. + elseif upstream_obj.upstream then + -- Add a virtual id field to uniquely identify the upstream key. upstream_obj.upstream.vid = i server_list[upstream_obj.upstream] = upstream_obj.weight + else + -- If the upstream object has only the weight value, it means + -- that the upstream weight value on the default route has been reached. + -- Mark empty upstream services in the plugin. + upstream_obj.upstream = "plugin#upstream#is#empty" + server_list[upstream_obj.upstream] = upstream_obj.weight end end diff --git a/doc/plugins/traffic-split.md b/doc/plugins/traffic-split.md index 630cdd28fc9b..02c0a5c8ac3d 100644 --- a/doc/plugins/traffic-split.md +++ b/doc/plugins/traffic-split.md @@ -113,7 +113,7 @@ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f13 }' ``` -2. Binding upstream services through the `upstream_id` attribute in the plugin. +2. Use the `upstream_id` attribute in the plugin to bind upstream. ```shell curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' @@ -145,7 +145,7 @@ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f13 }' ``` ->Note: **1.** Binding upstream services via `upstream_id`. It can reuse functions such as health detection and retry mechanism of upstream services. **2.** Support the two configuration methods of `upstream` and `upstream_id` to be used together. +>Note: **1.** Use the `upstream_id` to bind the defined upstream, it can reuse upstream health detection, retry and other functions. **2.** Support the two configuration methods of `upstream` and `upstream_id` to be used together. ## Example diff --git a/doc/zh-cn/plugins/traffic-split.md b/doc/zh-cn/plugins/traffic-split.md index 6b6340d3edd1..4d0c48b7fb93 100644 --- a/doc/zh-cn/plugins/traffic-split.md +++ b/doc/zh-cn/plugins/traffic-split.md @@ -145,7 +145,7 @@ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f13 }' ``` ->注:1、通过 `upstream_id` 方式绑定上游服务,可以复用上游服务具有的健康检测、重试机制等功能。2、支持 `upstream` 和 `upstream_id` 的两种配置方式一起使用。 +>注:1、通过 `upstream_id` 方式来绑定已定义的上游,它可以复用上游具有的健康检测、重试等功能。2、支持 `upstream` 和 `upstream_id` 的两种配置方式一起使用。 ## 示例 From fd3f4c7dc049a84af6ac3d80cce51509cb015470 Mon Sep 17 00:00:00 2001 From: root <2226815922@qq.com> Date: Sun, 7 Feb 2021 14:04:27 +0800 Subject: [PATCH 8/9] update schema --- apisix/plugins/traffic-split.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apisix/plugins/traffic-split.lua b/apisix/plugins/traffic-split.lua index 4385677b0481..c070865c716b 100644 --- a/apisix/plugins/traffic-split.lua +++ b/apisix/plugins/traffic-split.lua @@ -97,7 +97,7 @@ local upstreams_schema = { items = { type = "object", properties = { - upstream_id = schema_def.id_schema, -- todo: support upstream_id method + upstream_id = schema_def.id_schema, upstream = schema_def.upstream, weight = { description = "used to split traffic between different" .. From ff5c112d799874038f15d20d1ac4e827aa89e777 Mon Sep 17 00:00:00 2001 From: Firstsawyou <2226815922@qq.com> Date: Mon, 22 Feb 2021 19:18:02 +0800 Subject: [PATCH 9/9] update docs and test case --- doc/plugins/traffic-split.md | 2 +- doc/zh-cn/plugins/traffic-split.md | 2 +- t/plugin/traffic-split.t | 8 ++------ 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/doc/plugins/traffic-split.md b/doc/plugins/traffic-split.md index 02c0a5c8ac3d..b7723ec89a4a 100644 --- a/doc/plugins/traffic-split.md +++ b/doc/plugins/traffic-split.md @@ -55,7 +55,7 @@ Note: The ratio between each upstream may not so accurate since the drawback of The traffic-split plugin is mainly composed of two parts: `match` and `weighted_upstreams`. `match` is a custom conditional rule, and `weighted_upstreams` is upstream configuration information. If you configure `match` and `weighted_upstreams` information, then after the `match` rule is verified, it will be based on the `weight` value in `weighted_upstreams`; the ratio of traffic between each upstream in the plugin will be guided, otherwise, all traffic will be directly Reach the `upstream` configured on `route` or `service`. Of course, you can also configure only the `weighted_upstreams` part, which will directly guide the traffic ratio between each upstream in the plugin based on the `weight` value in `weighted_upstreams`. ->Note: 1. In `match`, the expression in vars is the relationship of `and`, and the relationship between multiple `vars` is the relationship of `or`. 2. In the weighted_upstreams field of the plugin, if there is a structure with only `weight`, it means the upstream traffic weight value on `route` or `service`. Such as: +Note: 1. In `match`, the expression in vars is the relationship of `and`, and the relationship between multiple `vars` is the relationship of `or`. 2. In the weighted_upstreams field of the plugin, if there is a structure with only `weight`, it means the upstream traffic weight value on `route` or `service`. Such as: ```json "weighted_upstreams": [ diff --git a/doc/zh-cn/plugins/traffic-split.md b/doc/zh-cn/plugins/traffic-split.md index 4d0c48b7fb93..b2542f0e4a38 100644 --- a/doc/zh-cn/plugins/traffic-split.md +++ b/doc/zh-cn/plugins/traffic-split.md @@ -55,7 +55,7 @@ traffic-split 插件使用户可以逐步引导各个上游之间的流量百分 traffic-split 插件主要由 `match` 和 `weighted_upstreams` 两部分组成,`match` 是自定义的条件规则,`weighted_upstreams` 是 upstream 的配置信息。如果配置 `match` 和 `weighted_upstreams` 信息,那么在 `match` 规则校验通过后,会根据 `weighted_upstreams` 中的 `weight` 值;引导插件中各个 upstream 之间的流量比例,否则,所有流量直接到达 `route` 或 `service` 上配置的 `upstream`。当然你也可以只配置 `weighted_upstreams` 部分,这样会直接根据 `weighted_upstreams` 中的 `weight` 值,引导插件中各个 upstream 之间的流量比例。 ->注:1、在 `match` 里,vars 中的表达式是 `and` 的关系,多个 `vars` 之间是 `or` 的关系。2、在插件的 weighted_upstreams 域中,如果存在只有 `weight` 的结构,表示 `route` 或 `service` 上的 upstream 流量权重值。例如: +注:1、在 `match` 里,vars 中的表达式是 `and` 的关系,多个 `vars` 之间是 `or` 的关系。2、在插件的 weighted_upstreams 域中,如果存在只有 `weight` 的结构,表示 `route` 或 `service` 上的 upstream 流量权重值。例如: ```json "weighted_upstreams": [ diff --git a/t/plugin/traffic-split.t b/t/plugin/traffic-split.t index 8478ff88756c..dc58c60170e6 100644 --- a/t/plugin/traffic-split.t +++ b/t/plugin/traffic-split.t @@ -1672,7 +1672,6 @@ location /t { local t = require("lib.test_admin").test local bodys = {} local headers = {} - headers["x-api-appkey"] = "hello" for i = 1, 5 do local _, _, body = t('/server_port?x-api-name=jack', ngx.HTTP_GET, "", nil, headers) bodys[i] = body @@ -1745,8 +1744,6 @@ location /t { content_by_lua_block { local t = require("lib.test_admin").test local bodys = {} - local headers = {} - headers["x-api-appkey"] = "hello" for i = 1, 4 do local _, _, body = t('/server_port?x-api-name=jack', ngx.HTTP_GET, "", nil, headers) bodys[i] = body @@ -1909,9 +1906,8 @@ GET /t GET /t --- response_body passed ---- grep_error_log eval -qr/^.*?\[error\](?!.*process exiting).*/ ---- grep_error_log_out +--- no_error_log +[error]