apisix/docs/zh/latest/plugins/traffic-split.md

19 KiB
Raw Blame History

title
traffic-split

目录

名字

traffic-split 插件使用户可以逐步引导各个上游之间的流量百分比。

由于加权循环算法特别是在重置wrr状态时的缺点因此每个上游之间的比率可能不太准确。

属性

参数名 类型 可选项 默认值 有效值 描述
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-exproperator-list 部分。
rules.weighted_upstreams array[object] 可选 上游配置规则列表。
weighted_upstreams.upstream_id string / integer 可选 通过上游 id 绑定对应上游。
weighted_upstreams.upstream object 可选 上游配置信息。
upstream.type enum 可选 roundrobin [roundrobin, chash] roundrobin 支持权重的负载chash 一致性哈希,两者是二选一。
upstream.hash_on enum 可选 vars hash_on 支持的类型有 varsNginx 内置变量),header(自定义 headercookieconsumervars_combinations,默认值为 vars。更多详细信息请参考 upstream 用法。
upstream.key string 可选 该选项只有类型是 chash 才有效。根据 key 来查找对应的 node id,相同的 key 在同一个对象中,永远返回相同 id。更多详细信息请参考 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 的值
upstream.name string 可选 标识上游服务名称、使⽤场景等。
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 插件主要由 matchweighted_upstreams 两部分组成,match 是自定义的条件规则,weighted_upstreams 是 upstream 的配置信息。如果配置 matchweighted_upstreams 信息,那么在 match 规则校验通过后,会根据 weighted_upstreams 中的 weight 值;引导插件中各个 upstream 之间的流量比例,否则,所有流量直接到达 routeservice 上配置的 upstream。当然你也可以只配置 weighted_upstreams 部分,这样会直接根据 weighted_upstreams 中的 weight 值,引导插件中各个 upstream 之间的流量比例。

1、在 matchvars 中的表达式是 and 的关系,多个 vars 之间是 or 的关系。2、在插件的 weighted_upstreams 域中,如果存在只有 weight 的结构,表示 routeservice 上的 upstream 流量权重值。例如:

"weighted_upstreams": [
    ......
    {
        "weight": 2
    }
]

如何启用

创建一个路由并启用 traffic-split 插件,在配置插件上游信息时,有以下两种方式:

1、通过插件中的 upstream 属性配置上游信息。

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": {
                                "name": "upstream_A",
                                "type": "roundrobin",
                                "nodes": {
                                    "127.0.0.1:1981":10
                                },
                                "timeout": {
                                    "connect": 15,
                                    "send": 15,
                                    "read": 15
                                }
                            },
                            "weight": 1
                        },
                        {
                            "weight": 1
                        }
                    ]
                }
            ]
        }
    },
    "upstream": {
            "type": "roundrobin",
            "nodes": {
                "127.0.0.1:1980": 1
            }
    }
}'

2、通过插件中的 upstream_id 属性绑定上游服务。

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、支持 upstreamupstream_id 的两种配置方式一起使用。

示例

灰度发布

缺少 match 规则部分,根据插件中 weighted_upstreams 配置的 weight 值做流量分流。将 插件的 upstreamroute 的 upstream 按 3:2 的流量比例进行划分,其中 60% 的流量到达插件中的 1981 端口的 upstream 40% 的流量到达 route 上默认 1980 端口的 upstream。

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": {
                                "name": "upstream_A",
                                "type": "roundrobin",
                                "nodes": {
                                    "127.0.0.1:1981":10
                                },
                                "timeout": {
                                    "connect": 15,
                                    "send": 15,
                                    "read": 15
                                }
                            },
                            "weight": 3
                        },
                        {
                            "weight": 2
                        }
                    ]
                }
            ]
        }
    },
    "upstream": {
            "type": "roundrobin",
            "nodes": {
                "127.0.0.1:1980": 1
            }
    }
}'

插件测试:

请求5次3次请求命中插件1981端口的 upstream, 2次请求命中 route 的1980端口 upstream。

$ curl http://127.0.0.1:9080/index.html -i
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8

hello 1980

$ curl http://127.0.0.1:9080/index.html -i
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8

world 1981

......

蓝绿发布

通过请求头获取 match 规则参数(也可以通过请求参数获取或NGINX变量),在 match 规则匹配通过后,表示所有请求都命中到插件配置的 upstream ,否则所以请求只命中 route 上配置的 upstream 。

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": [
                {
                    "match": [
                        {
                            "vars": [
                                ["http_release","==","new_release"]
                            ]
                        }
                    ],
                    "weighted_upstreams": [
                        {
                            "upstream": {
                                "name": "upstream_A",
                                "type": "roundrobin",
                                "nodes": {
                                    "127.0.0.1:1981":10
                                }
                            }
                        }
                    ]
                }
            ]
        }
    },
    "upstream": {
            "type": "roundrobin",
            "nodes": {
                "127.0.0.1:1980": 1
            }
    }
}'

插件测试:

match 规则匹配通过所有请求都命中插件配置的1981端口 upstream

$ curl http://127.0.0.1:9080/index.html -H 'release: new_release' -i
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
......

world 1981

match 规则匹配失败,所有请求都命中 route 上配置的 1980端口 upstream

$ curl http://127.0.0.1:9080/index.html -H 'release: old_release' -i
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
......

hello 1980

自定义发布

match 中可以设置多个 vars 规则,vars 中的多个表达式之间是 add 的关系, 多个 vars 规则之间是 or 的关系;只要其中一个 vars 规则通过,则整个 match 通过。

示例1只配置了一个 vars 规则, vars 中的多个表达式是 add 的关系。在 weighted_upstreams 中根据 weight 值将流量按 3:2 划分,其中只有 weight 值的部分表示 route 上的 upstream 所占的比例。 当 match 匹配不通过时,所有的流量只会命中 route 上的 upstream 。

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": [
                {
                    "match": [
                        {
                            "vars": [
                                ["arg_name","==","jack"],
                                ["http_user-id",">","23"],
                                ["http_apisix-key","~~","[a-z]+"]
                            ]
                        }
                    ],
                    "weighted_upstreams": [
                        {
                            "upstream": {
                                "name": "upstream_A",
                                "type": "roundrobin",
                                "nodes": {
                                    "127.0.0.1:1981":10
                                }
                            },
                            "weight": 3
                        },
                        {
                            "weight": 2
                        }
                    ]
                }
            ]
        }
    },
    "upstream": {
            "type": "roundrobin",
            "nodes": {
                "127.0.0.1:1980": 1
            }
    }
}'

插件设置了请求的 match 规则及端口为1981的 upstreamroute 上具有端口为1980的 upstream。

插件测试:

1、在 match 规则校验通过后, 60% 的请求命中到插件的1981端口的 upstream, 40% 的请求命中到 route 的1980端口的 upstream。

match 规则校验成功, 命中端口为1981的 upstream。

$ curl 'http://127.0.0.1:9080/index.html?name=jack' -H 'user-id:30' -H 'apisix-key: hello' -i
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
......

world 1981

match 规则校验失败,,命中默认端口为1980的 upstream。

$ curl 'http://127.0.0.1:9080/index.html?name=jack' -H 'user-id:30' -H 'apisix-key: hello' -i
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
......

hello 1980

在请求5次后3次命中 1981 端口的服务2次命中 1980 端口的服务。

2、match 规则校验失败(缺少请求头 apisix-key ), 响应都为默认 upstream 的数据 hello 1980

$ curl 'http://127.0.0.1:9080/index.html?name=jack' -H 'user-id:30' -i
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
......

hello 1980

示例2配置多个 vars 规则, vars 中的多个表达式是 add 的关系, 多个 vars 之间是 or 的关系。根据 weighted_upstreams 中的 weight 值将流量按 3:2 划分,其中只有 weight 值的部分表示 route 上的 upstream 所占的比例。 当 match 匹配不通过时,所有的流量只会命中 route 上的 upstream 。

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": [
                {
                    "match": [
                        {
                            "vars": [
                                ["arg_name","==","jack"],
                                ["http_user-id",">","23"],
                                ["http_apisix-key","~~","[a-z]+"]
                            ]
                        },
                        {
                            "vars": [
                                ["arg_name2","==","rose"],
                                ["http_user-id2","!",">","33"],
                                ["http_apisix-key2","~~","[a-z]+"]
                            ]
                        }
                    ],
                    "weighted_upstreams": [
                        {
                            "upstream": {
                                "name": "upstream_A",
                                "type": "roundrobin",
                                "nodes": {
                                    "127.0.0.1:1981":10
                                }
                            },
                            "weight": 3
                        },
                        {
                            "weight": 2
                        }
                    ]
                }
            ]
        }
    },
    "upstream": {
            "type": "roundrobin",
            "nodes": {
                "127.0.0.1:1980": 1
            }
    }
}'

插件设置了请求的 match 规则及端口为1981的 upstreamroute 上具有端口为1980的 upstream 。

测试插件:

1、两个 vars 的表达式匹配成功, match 规则校验通过后, 60% 的请求命中到插件的1981端口 upstream, 40% 的请求命中到 route 的1980端口upstream。

$ curl 'http://127.0.0.1:9080/index.html?name=jack&name2=rose' -H 'user-id:30' -H 'user-id2:22' -H 'apisix-key: hello' -H 'apisix-key2: world' -i
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
......

world 1981
$ curl 'http://127.0.0.1:9080/index.html?name=jack&name2=rose' -H 'user-id:30' -H 'user-id2:22' -H 'apisix-key: hello' -H 'apisix-key2: world' -i
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
......

hello 1980

在请求5次后3次命中 1981 端口的服务2次命中 1980 端口的服务。

2、第二个 vars 的表达式匹配失败(缺少 name2 请求参数),match 规则校验通过后, 60% 的请求命中到插件的1981端口 upstream, 40% 的请求流量命中到 route 的1980端口 upstream。

$ curl 'http://127.0.0.1:9080/index.html?name=jack' -H 'user-id:30' -H 'user-id2:22' -H 'apisix-key: hello' -H 'apisix-key2: world' -i
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
......

world 1981
$ curl 'http://127.0.0.1:9080/index.html?name=jack' -H 'user-id:30' -H 'user-id2:22' -H 'apisix-key: hello' -H 'apisix-key2: world' -i
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
......

hello 1980

在请求5次后3次命中 1981 端口的服务2次命中 1980 端口的服务。

3、两个 vars 的表达式校验失败(缺少 namename2 请求参数),match 规则校验失败, 响应都为默认 route 的 upstream 数据 hello 1980

$ curl 'http://127.0.0.1:9080/index.html?name=jack' -i
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
......

hello 1980

禁用插件

当你想去掉 traffic-split 插件的时候,很简单,在插件的配置中把对应的 json 配置删除即可,无须重启服务,即刻生效:

$ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
    "uri": "/index.html",
    "plugins": {},
    "upstream": {
        "type": "roundrobin",
        "nodes": {
            "127.0.0.1:1980": 1
        }
    }
}'