traffic-split
match
属性是用于引导流量的自定义规则,weighted_upstreams
属性则用于引导流量的上游服务。当一个请求被 match
属性匹配时,它将根据配置的 weights
属性被引导至上游服务。你也可以不使用 match
属性,只根据 weighted_upstreams
属性来引导所有流量。
注意
由于该插件使用了加权循环算法(特别是在重置 wrr
状态时),因此在使用该插件时,可能会存在上游服务之间的流量比例不精准现象。
注意
目前 weighted_upstreams.upstream
的配置不支持 service_name
、discovery_type
、checks
、retries
、retry_timeout
、desc
、scheme
、labels
、create_time
和 update_time
等字段。如果你需要使用这些字段,可以在创建上游对象时指定这些字段,然后在该插件中配置 weighted_upstreams.upstream_id
属性即可。
重要
在 match
属性中,变量中的表达式以 AND 方式关联,多个变量以 OR 方式关联。
如果你仅配置了 weight
属性,那么它将会使用该 Route 或 Service 中的上游服务的权重。
以下示例展示了如何在指定路由上启用 traffic-split
插件,并通过插件中的 upstream
属性配置上游信息:
如果你已经配置了一个上游对象,你可以通过插件中的 upstream_id
属性来绑定上游服务:
curl http://127.0.0.1:9180/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
}
}
}'
提示
通过 upstream_id
方式来绑定已定义的上游,可以复用上游已存在的健康检查、重试等功能。
注意
weighted_upstreams
属性支持同时使用 upstream
和 upstream_id
两种配置方式。
以下示例展示了如何通过配置 weighted_upstreams
的 weight
属性来实现流量分流。按 3:2 的权重流量比例进行划分,其中 60% 的流量到达运行在 1981
端口上的上游服务,40% 的流量到达运行在 1980
端口上的上游服务:
curl http://127.0.0.1:9180/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
端口的插件上游服务,2 次命中运行在 1980
端口的路由上游服务:
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
...
在蓝绿发布场景中,你需要维护两个环境,一旦新的变化在蓝色环境(staging)中被测试和接受,用户流量就会从绿色环境(production)转移到蓝色环境。
以下示例展示了如何基于请求头来配置 match
规则:
curl http://127.0.0.1:9180/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
}
}
}'
测试
- 通过
curl
命令发出请求,如果请求带有一个值为new_release
的 release header,它就会被引导至在插件上配置的新的上游服务:
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
- 否则请求会被引导至在路由上配置的另一个上游服务:
curl http://127.0.0.1:9080/index.html -H 'release: old_release' -i
你也可以通过配置规则和权重来实现自定义发布。
示例 1
下面的示例只配置了一个 vars
规则,流量按 3:2 的权重比例进行划分,不匹配 vars
的流量将被重定向到在路由上配置的上游服务:
curl http://127.0.0.1:9180/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
}
}
}'
- 通过
curl
命令发出请求,在match
规则校验通过后,将会有 60% 的请求被引导至插件1981
端口的上游服务,40% 的请求被引导至路由1980
端口的上游服务:
curl 'http://127.0.0.1:9080/index.html?name=jack' \
-H 'user-id:30' -H 'apisix-key: hello' -i
在请求 5 次后,其中会有 3 次命中 1981
端口的服务,2 次命中 1980
端口的服务:
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
...
world 1981
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
...
hello 1980
- 如果
match
规则校验失败(如缺少请求头apisix-key
), 那么请求将被引导至路由的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
规则,流量按 3:2 的权重比例进行划分,不匹配 vars
的流量将被重定向到在路由上配置的上游服务:
curl http://127.0.0.1:9180/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
}
},
},
{
}
]
}
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
测试
- 通过
curl
命令发出请求,如果两个vars
表达式均匹配成功,match
规则校验通过后,将会有 60% 的请求被引导至插件1981
端口的上游服务,40% 的请求命中到路由的1980
端口的上游服务:
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
在请求 5 次后,其中会有 3 次命中 1981
端口的服务,2 次命中 1980
端口的服务:
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
...
world 1981
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
...
hello 1980
- 如果第二个
vars
的表达式匹配失败(例如缺少name2
请求参数),match
规则校验通过后,效果将会与上一种相同。即有 60% 的请求被引导至插件1981
端口的上游服务,40% 的请求命中到路由的1980
端口的上游服务:
在请求 5 次后,其中会有 3 次命中 1981
端口的服务,2 次命中 1980
端口的服务:
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
...
world 1981
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
...
hello 1980
- 如果两个
vars
的表达式均匹配失败(如缺少name
和name2
请求参数),match
规则会校验失败,请求将被引导至路由的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
以下示例展示了如何配置多个 rules
属性,实现不同的匹配规则与上游一一对应。当请求头 x-api-id
为 1
时,请求会被引导至 1981
端口的上游服务;当 x-api-id
为 2
时,请求会被引导至 1982
端口的上游服务;否则请求会被引导至 1980
端口的上游服务:
curl http://127.0.0.1:9180/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
}
}
}'
测试
- 通过
curl
命令发出请求,请求头x-api-id
为1
,则会命中1980
端口的服务:
curl http://127.0.0.1:9080/hello -H 'x-api-id: 1'
1981
- 如果请求头
x-api-id
为2
,则会命中1982
端口的服务:
curl http://127.0.0.1:9080/hello -H 'x-api-id: 2'
1982
- 如果请求头
x-api-id
为3
,规则不匹配,则会命中带1980
端口的服务:
curl http://127.0.0.1:9080/hello -H 'x-api-id: 3'
当你需要禁用该插件时,可以通过以下命令删除相应的 JSON 配置,APISIX 将会自动重新加载相关配置,无需重启服务:
curl http://127.0.0.1:9180/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
}