You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by sp...@apache.org on 2021/04/22 00:58:34 UTC

[apisix] branch master updated: fix(traffic-split): configure multiple "rules", the request will be confused between upstream (#4092)

This is an automated email from the ASF dual-hosted git repository.

spacewander 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 9456568  fix(traffic-split): configure multiple "rules", the request will be confused between upstream (#4092)
9456568 is described below

commit 94565689f728d12e0fa5eaf2c8909bb022a75448
Author: Yuelin Zheng <22...@qq.com>
AuthorDate: Thu Apr 22 08:58:23 2021 +0800

    fix(traffic-split): configure multiple "rules", the request will be confused between upstream (#4092)
---
 apisix/plugins/traffic-split.lua        |   3 +-
 docs/en/latest/plugins/traffic-split.md |  93 +++++++++
 docs/zh/latest/plugins/traffic-split.md |  93 +++++++++
 t/plugin/traffic-split2.t               | 324 ++++++++++++++++++++++++++++++++
 4 files changed, 511 insertions(+), 2 deletions(-)

diff --git a/apisix/plugins/traffic-split.lua b/apisix/plugins/traffic-split.lua
index 5364438..f7e75af 100644
--- a/apisix/plugins/traffic-split.lua
+++ b/apisix/plugins/traffic-split.lua
@@ -278,8 +278,7 @@ function _M.access(conf, ctx)
         return
     end
 
-    local rr_up, err = core.lrucache.plugin_ctx(lrucache, ctx, nil, new_rr_obj,
-                                                weighted_upstreams)
+    local rr_up, err = lrucache(weighted_upstreams, nil, new_rr_obj, weighted_upstreams)
     if not rr_up then
         core.log.error("lrucache roundrobin failed: ", err)
         return 500
diff --git a/docs/en/latest/plugins/traffic-split.md b/docs/en/latest/plugins/traffic-split.md
index 9189a81..4882da1 100644
--- a/docs/en/latest/plugins/traffic-split.md
+++ b/docs/en/latest/plugins/traffic-split.md
@@ -30,6 +30,7 @@ title: traffic-split
   - [Grayscale Release](#grayscale-release)
   - [Blue-green Release](#blue-green-release)
   - [Custom Release](#custom-release)
+  - [Matching rules correspond to upstream](#matching-rules-correspond-to-upstream)
 - [Disable Plugin](#disable-plugin)
 
 ## Name
@@ -482,6 +483,98 @@ Content-Type: text/html; charset=utf-8
 hello 1980
 ```
 
+### Matching rules correspond to upstream
+
+By configuring multiple `rules`, we can achieve one-to-one correspondence between different matching rules and upstream.
+
+**Example:**
+
+When the request header `x-api-id` is equal to 1, it hits the upstream with port 1981; when `x-api-id` is equal to 2, it hits the upstream with port 1982; otherwise, it hits the upstream with port 1980 (the upstream response data is the corresponding port number).
+
+```shell
+curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
+{
+    "uri": "/hello",
+    "plugins": {
+        "traffic-split": {
+            "rules": [
+                {
+                    "match": [
+                        {
+                            "vars": [
+                                ["http_x-api-id","==","1"]
+                            ]
+                        }
+                    ],
+                    "weighted_upstreams": [
+                        {
+                            "upstream": {
+                                "name": "upstream-A",
+                                "type": "roundrobin",
+                                "nodes": {
+                                    "127.0.0.1:1981":1
+                                }
+                            },
+                            "weight": 3
+                        }
+                    ]
+                },
+                {
+                    "match": [
+                        {
+                            "vars": [
+                                ["http_x-api-id","==","2"]
+                            ]
+                        }
+                    ],
+                    "weighted_upstreams": [
+                        {
+                            "upstream": {
+                                "name": "upstream-B",
+                                "type": "roundrobin",
+                                "nodes": {
+                                    "127.0.0.1:1982":1
+                                }
+                            },
+                            "weight": 3
+                        }
+                    ]
+                }
+            ]
+        }
+    },
+    "upstream": {
+            "type": "roundrobin",
+            "nodes": {
+                "127.0.0.1:1980": 1
+            }
+    }
+}'
+```
+
+**Test plugin:**
+
+The request header `x-api-id` is equal to 1, hitting the upstream with the 1981 port.
+
+```shell
+$ curl http://127.0.0.1:9080/hello -H 'x-api-id: 1'
+1981
+```
+
+The request header `x-api-id` is equal to 2, hitting the upstream with the 1982 port.
+
+```shell
+$ curl http://127.0.0.1:9080/hello -H 'x-api-id: 2'
+1982
+```
+
+The request header `x-api-id` is equal to 3, the rule does not match, and it hits the upstream with port 1980.
+
+```shell
+$ curl http://127.0.0.1:9080/hello -H 'x-api-id: 3'
+1980
+```
+
 ## Disable Plugin
 
 When you want to remove the traffic-split plugin, it's very simple, just delete the corresponding json configuration in the plugin configuration, no need to restart the service, it will take effect immediately:
diff --git a/docs/zh/latest/plugins/traffic-split.md b/docs/zh/latest/plugins/traffic-split.md
index 045ab54..86e576d 100644
--- a/docs/zh/latest/plugins/traffic-split.md
+++ b/docs/zh/latest/plugins/traffic-split.md
@@ -30,6 +30,7 @@ title: traffic-split
   - [灰度发布](#灰度发布)
   - [蓝绿发布](#蓝绿发布)
   - [自定义发布](#自定义发布)
+  - [匹配规则与上游对应](#匹配规则与上游对应)
 - [禁用插件](#禁用插件)
 
 ## 名字
@@ -493,6 +494,98 @@ Content-Type: text/html; charset=utf-8
 hello 1980
 ```
 
+### 匹配规则与上游对应
+
+通过配置多个 `rules`,我们可以实现不同的匹配规则与上游一一对应。
+
+**示例:**
+
+当请求头 `x-api-id` 等于 1 时,命中 1981 端口的上游;当 `x-api-id` 等于 2 时,命中 1982 端口的上游;否则,命中 1980 端口的上游(上游响应数据为对应的端口号)。
+
+```shell
+curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
+{
+    "uri": "/hello",
+    "plugins": {
+        "traffic-split": {
+            "rules": [
+                {
+                    "match": [
+                        {
+                            "vars": [
+                                ["http_x-api-id","==","1"]
+                            ]
+                        }
+                    ],
+                    "weighted_upstreams": [
+                        {
+                            "upstream": {
+                                "name": "upstream-A",
+                                "type": "roundrobin",
+                                "nodes": {
+                                    "127.0.0.1:1981":1
+                                }
+                            },
+                            "weight": 3
+                        }
+                    ]
+                },
+                {
+                    "match": [
+                        {
+                            "vars": [
+                                ["http_x-api-id","==","2"]
+                            ]
+                        }
+                    ],
+                    "weighted_upstreams": [
+                        {
+                            "upstream": {
+                                "name": "upstream-B",
+                                "type": "roundrobin",
+                                "nodes": {
+                                    "127.0.0.1:1982":1
+                                }
+                            },
+                            "weight": 3
+                        }
+                    ]
+                }
+            ]
+        }
+    },
+    "upstream": {
+            "type": "roundrobin",
+            "nodes": {
+                "127.0.0.1:1980": 1
+            }
+    }
+}'
+```
+
+**测试插件:**
+
+请求头 `x-api-id` 等于 1,命中带 1981 端口的上游。
+
+```shell
+$ curl http://127.0.0.1:9080/hello -H 'x-api-id: 1'
+1981
+```
+
+请求头 `x-api-id` 等于 2,命中带 1982 端口的上游。
+
+```shell
+$ curl http://127.0.0.1:9080/hello -H 'x-api-id: 2'
+1982
+```
+
+请求头 `x-api-id` 等于 3,规则不匹配,命中带 1980 端口的上游。
+
+```shell
+$ curl http://127.0.0.1:9080/hello -H 'x-api-id: 3'
+1980
+```
+
 ## 禁用插件
 
 当你想去掉 traffic-split 插件的时候,很简单,在插件的配置中把对应的 json 配置删除即可,无须重启服务,即刻生效:
diff --git a/t/plugin/traffic-split2.t b/t/plugin/traffic-split2.t
index 58df05f..9fe2752 100644
--- a/t/plugin/traffic-split2.t
+++ b/t/plugin/traffic-split2.t
@@ -408,3 +408,327 @@ hash_on: header
 chash_key: "world"
 hash_on: header
 chash_key: "hello"
+
+
+
+=== TEST 12: the plugin has multiple weighted_upstreams(upstream method)
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/routes/1',
+                ngx.HTTP_PATCH,
+                [=[{
+                    "uri": "/server_port",
+                    "plugins": {
+                        "traffic-split": {
+                            "rules": [
+                                {
+                                    "match": [
+                                        {
+                                            "vars": [["arg_id","==","1"]]
+                                        }
+                                    ],
+                                    "weighted_upstreams": [
+                                        {
+                                            "upstream": {
+                                                "name": "upstream_A",
+                                                "type": "roundrobin",
+                                                "nodes": {
+                                                    "127.0.0.1:1981":1
+                                                }
+                                            },
+                                            "weight": 1
+                                        }
+                                    ]
+                                },
+                                {
+                                    "match": [
+                                        {
+                                            "vars": [["arg_id","==","2"]]
+                                        }
+                                    ],
+                                    "weighted_upstreams": [
+                                        {
+                                            "upstream": {
+                                                "name": "upstream_B",
+                                                "type": "roundrobin",
+                                                "nodes": {
+                                                    "127.0.0.1:1982":1
+                                                }
+                                            },
+                                            "weight": 1
+                                        }
+                                    ]
+                                }
+                            ]
+                        }
+                    },
+                    "upstream": {
+                            "type": "roundrobin",
+                            "nodes": {
+                                "127.0.0.1:1980": 1
+                            }
+                    }
+                }]=]
+            )
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- response_body
+passed
+--- no_error_log
+[error]
+
+
+
+=== TEST 13: hit each upstream separately
+--- config
+location /t {
+    content_by_lua_block {
+        local t = require("lib.test_admin").test
+        local bodys = {}
+        for i = 1, 9, 3 do
+            local _, _, body = t('/server_port', ngx.HTTP_GET)
+            local _, _, body2 = t('/server_port?id=1', ngx.HTTP_GET)
+            local _, _, body3 = t('/server_port?id=2', ngx.HTTP_GET)
+            bodys[i] = body
+            bodys[i+1] = body2
+            bodys[i+2] = body3
+        end
+
+        ngx.say(table.concat(bodys, ", "))
+    }
+}
+--- response_body eval
+qr/1980, 1981, 1982, 1980, 1981, 1982, 1980, 1981, 1982/
+--- no_error_log
+[error]
+
+
+
+=== TEST 14: the plugin has multiple weighted_upstreams and has a default routing weight in weighted_upstreams
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/routes/1',
+                ngx.HTTP_PATCH,
+                [=[{
+                    "uri": "/server_port",
+                    "plugins": {
+                        "traffic-split": {
+                            "rules": [
+                                {
+                                    "match": [
+                                        {
+                                            "vars": [["arg_id","==","1"]]
+                                        }
+                                    ],
+                                    "weighted_upstreams": [
+                                        {
+                                            "upstream": {
+                                                "name": "upstream_A",
+                                                "type": "roundrobin",
+                                                "nodes": {
+                                                    "127.0.0.1:1981":1
+                                                }
+                                            },
+                                            "weight": 1
+                                        },
+                                        {
+                                            "weight": 1
+                                        }
+                                    ]
+                                },
+                                {
+                                    "match": [
+                                        {
+                                            "vars": [["arg_id","==","2"]]
+                                        }
+                                    ],
+                                    "weighted_upstreams": [
+                                        {
+                                            "upstream": {
+                                                "name": "upstream_B",
+                                                "type": "roundrobin",
+                                                "nodes": {
+                                                    "127.0.0.1:1982":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)
+        }
+    }
+--- response_body
+passed
+--- no_error_log
+[error]
+
+
+
+=== TEST 15: every weighted_upstreams in the plugin is hit
+--- config
+location /t {
+    content_by_lua_block {
+        local t = require("lib.test_admin").test
+        local bodys = {}
+        for i = 1, 8, 2 do
+            local _, _, body = t('/server_port?id=1', ngx.HTTP_GET)
+            local _, _, body2 = t('/server_port?id=2', ngx.HTTP_GET)
+            bodys[i] = body
+            bodys[i+1] = body2
+        end
+
+        table.sort(bodys)
+        ngx.say(table.concat(bodys, ", "))
+    }
+}
+--- response_body eval
+qr/1980, 1980, 1980, 1980, 1981, 1981, 1982, 1982/
+--- no_error_log
+[error]
+
+
+
+=== TEST 16: set upstream(upstream_id: 1, upstream_id: 2) and add route
+--- 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 A"
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+                ngx.say(body)
+            end
+
+            code, body = t('/apisix/admin/upstreams/2',
+                 ngx.HTTP_PUT,
+                 [[{
+                    "nodes": {
+                        "127.0.0.1:1982": 1
+                    },
+                    "type": "roundrobin",
+                    "desc": "new upstream B"
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+                ngx.say(body)
+            end
+
+            code, body = t('/apisix/admin/routes/1',
+                ngx.HTTP_PATCH,
+                [=[{
+                    "uri": "/server_port",
+                    "plugins": {
+                        "traffic-split": {
+                            "rules": [
+                                {
+                                    "match": [
+                                        {
+                                            "vars": [["arg_id","==","1"]]
+                                        }
+                                    ],
+                                    "weighted_upstreams": [
+                                        {
+                                            "upstream_id": 1,
+                                            "weight": 1
+                                        }
+                                    ]
+                                },
+                                {
+                                    "match": [
+                                        {
+                                            "vars": [["arg_id","==","2"]]
+                                        }
+                                    ],
+                                    "weighted_upstreams": [
+                                        {
+                                            "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 17: hit each upstream separately
+--- config
+location /t {
+    content_by_lua_block {
+        local t = require("lib.test_admin").test
+        local bodys = {}
+        for i = 1, 9, 3 do
+            local _, _, body = t('/server_port', ngx.HTTP_GET)
+            local _, _, body2 = t('/server_port?id=1', ngx.HTTP_GET)
+            local _, _, body3 = t('/server_port?id=2', ngx.HTTP_GET)
+            bodys[i] = body
+            bodys[i+1] = body2
+            bodys[i+2] = body3
+        end
+
+        ngx.say(table.concat(bodys, ", "))
+    }
+}
+--- response_body eval
+qr/1980, 1981, 1982, 1980, 1981, 1982, 1980, 1981, 1982/
+--- no_error_log
+[error]