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/01 12:57:19 UTC

[apisix] branch master updated: fix(traffic-split): upstream.type support chash configuration (#3955)

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 708d266  fix(traffic-split): upstream.type support chash configuration (#3955)
708d266 is described below

commit 708d266512b6cdd24a09a762cabf09839ee6df22
Author: Yuelin Zheng <22...@qq.com>
AuthorDate: Thu Apr 1 20:57:10 2021 +0800

    fix(traffic-split): upstream.type support chash configuration (#3955)
---
 apisix/plugins/traffic-split.lua        |  2 +
 docs/en/latest/plugins/traffic-split.md |  5 ++
 docs/zh/latest/plugins/traffic-split.md |  7 ++-
 t/plugin/traffic-split2.t               | 97 +++++++++++++++++++++++++++++++++
 4 files changed, 110 insertions(+), 1 deletion(-)

diff --git a/apisix/plugins/traffic-split.lua b/apisix/plugins/traffic-split.lua
index da44d3e..c8f22a2 100644
--- a/apisix/plugins/traffic-split.lua
+++ b/apisix/plugins/traffic-split.lua
@@ -192,6 +192,8 @@ local function set_upstream(upstream_info, ctx)
     local up_conf = {
         name = upstream_info.name,
         type = upstream_info.type,
+        hash_on = upstream_info.hash_on,
+        key = upstream_info.key,
         nodes = new_nodes,
         timeout = {
             send = upstream_info.timeout and upstream_info.timeout.send or 15,
diff --git a/docs/en/latest/plugins/traffic-split.md b/docs/en/latest/plugins/traffic-split.md
index fbd7408..df646fd 100644
--- a/docs/en/latest/plugins/traffic-split.md
+++ b/docs/en/latest/plugins/traffic-split.md
@@ -48,6 +48,8 @@ Note: The ratio between each upstream may not so accurate since the drawback of
 | 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.hash_on               | enum   | optional   | vars | | This option is only valid if the `type` is `chash`. Supported types `vars`(Nginx variables), `header`(custom header), `cookie`, `consumer`, `vars_combinations`, the default value is `vars`. For more details, please refer to [upstream](../admin-api.md#upstream) usage.|
+| upstream.key                   | string | optional   |      |    | This option is only valid if the `type` is `chash`. Find the corresponding node `id` according to `hash_on` and `key`. For more details, please refer to [upstream](../admin-api.md#upstream) usage.|
 | 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. |
 | upstream.timeout               | object        | optional    |  15     |   | Set the timeout period for connecting, sending and receiving messages (time unit: second, all default to 15 seconds).  |
 | upstream.pass_host             | enum          | optional    | "pass"  | ["pass", "node", "rewrite"]  | `pass`: Pass the client's host transparently to the upstream; `node`: Use the host configured in the node of `upstream`; `rewrite`: Use the value of the configuration `upstream_host`. |
@@ -55,6 +57,9 @@ Note: The ratio between each upstream may not so accurate since the drawback of
 | upstream.upstream_host         | string        | optional    |    |   | Only valid when pass_host is configured as rewrite.    |
 | weighted_upstreams.weight      | integer       | optional    | weight = 1   |  | The traffic is divided according to the `weight` value, and the roundrobin algorithm is used to divide multiple `weight`. |
 
+Currently, in the configuration of `weighted_upstreams.upstream`, the unsupported fields are:
+service_name, discovery_type, checks, retries, desc, scheme, labels, create_time and update_time. But you can use `weighted_upstreams.upstream_id` to bind the `upstream` object to achieve their functions.
+
 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 `upstre [...]
 
 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:
diff --git a/docs/zh/latest/plugins/traffic-split.md b/docs/zh/latest/plugins/traffic-split.md
index 1d13e1d..799d714 100644
--- a/docs/zh/latest/plugins/traffic-split.md
+++ b/docs/zh/latest/plugins/traffic-split.md
@@ -47,7 +47,9 @@ traffic-split 插件使用户可以逐步引导各个上游之间的流量百分
 | rules.weighted_upstreams       | array[object] | 可选   |        |        | 上游配置规则列表。 |
 | weighted_upstreams.upstream_id | string / integer | 可选   |        |        | 通过上游 id 绑定对应上游。 |
 | weighted_upstreams.upstream    | object | 可选   |        |        | 上游配置信息。 |
-| upstream.type                  | enum   | 可选   |   roundrobin |  [roundrobin, chash]      | roundrobin 支持权重的负载,chash 一致性哈希,两者是二选一的(目前只支持 `roundrobin`)。 |
+| upstream.type                  | enum   | 可选   |   roundrobin |  [roundrobin, chash]      | roundrobin 支持权重的负载,chash 一致性哈希,两者是二选一。 |
+| upstream.hash_on               | enum   | 可选   | vars | | `hash_on` 支持的类型有 `vars`(Nginx 内置变量),`header`(自定义 header),`cookie`,`consumer`,`vars_combinations`,默认值为 `vars`。更多详细信息请参考 [upstream](../admin-api.md#upstream) 用法。|
+| upstream.key                   | string | 可选   |      |    |  该选项只有类型是 `chash` 才有效。根据 `key` 来查找对应的 node `id`,相同的 `key` 在同一个对象中,永远返回相同 id。更多详细信息请参考 [upstream](../admin-api.md#upstream) 用法。 |
 | upstream.nodes                 | object | 可选   |        |        | 哈希表,内部元素的 key 是上游机器地址 列表,格式为地址 + Port,其中地址部 分可以是 IP 也可以是域名,⽐如 192.168.1.100:80、foo.com:80等。 value 则是节点的权重,特别的,当权重 值为 0 有特殊含义,通常代表该上游节点 失效,永远不希望被选中。 |
 | upstream.timeout               | object | 可选   |  15     |        | 设置连接、发送消息、接收消息的超时时间(时间单位:秒,都默认为 15 秒)。 |
 | upstream.pass_host             | enum   | 可选   | "pass"   | ["pass", "node", "rewrite"]  | `pass`: 将客户端的 host 透传给上游; `node`: 使用 `upstream`  node 中配置的 host; `rewrite`: 使用配置项 `upstream_host` 的值 |
@@ -55,6 +57,9 @@ traffic-split 插件使用户可以逐步引导各个上游之间的流量百分
 | upstream.upstream_host         | string | 可选   |        |        | 只在 pass_host 配置为 rewrite 时有效。 |
 | weighted_upstreams.weight      | integer | 可选   |   weight = 1     |        | 根据 `weight` 值做流量划分,多个 weight 之间使用 roundrobin 算法划分。|
 
+目前在 `weighted_upstreams.upstream` 的配置中,不支持的字段有:
+service_name、discovery_type、checks、retries、desc、scheme、labels、create_time 和 update_time。但是你可以通过 `weighted_upstreams.upstream_id` 绑定 `upstream` 对象来实现他们。
+
 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 流量权重值。例如:
diff --git a/t/plugin/traffic-split2.t b/t/plugin/traffic-split2.t
index 3a95c4a..58df05f 100644
--- a/t/plugin/traffic-split2.t
+++ b/t/plugin/traffic-split2.t
@@ -311,3 +311,100 @@ host: localhost
 x-real-ip: 127.0.0.1
 --- no_error_log
 [error]
+
+
+
+=== TEST 10: the upstream.type is `chash` and `key` is header
+--- 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": [
+                                {
+                                    "weighted_upstreams": [
+                                        {
+                                            "upstream": {
+                                                "name": "chash_test",
+                                                "type": "chash",
+                                                "hash_on": "header",
+                                                "key": "custom_header",
+                                                "nodes": {
+                                                    "127.0.0.1:1981":1,
+                                                    "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 11: hit routes, hash_on custom header
+--- config
+location /t {
+    content_by_lua_block {
+        local t = require("lib.test_admin").test
+        local bodys = {}
+        local headers = {}
+        local headers2 = {}
+        headers["custom_header"] = "hello"
+        headers2["custom_header"] = "world"
+        for i = 1, 8, 2 do
+            local _, _, body = t('/server_port', ngx.HTTP_GET, "", nil, headers2)
+            local _, _, body2 = t('/server_port', ngx.HTTP_GET, "", nil, headers)
+            bodys[i] = body
+            bodys[i+1] = body2
+        end
+
+        ngx.say(table.concat(bodys, ", "))
+    }
+}
+--- response_body eval
+qr/1981, 1982, 1981, 1982, 1981, 1982, 1981, 1982/
+--- grep_error_log eval
+qr/hash_on: header|chash_key: "hello"|chash_key: "world"/
+--- grep_error_log_out
+hash_on: header
+chash_key: "world"
+hash_on: header
+chash_key: "hello"
+hash_on: header
+chash_key: "world"
+hash_on: header
+chash_key: "hello"
+hash_on: header
+chash_key: "world"
+hash_on: header
+chash_key: "hello"
+hash_on: header
+chash_key: "world"
+hash_on: header
+chash_key: "hello"