traffic-split

match 属性是用于引导流量的自定义规则,weighted_upstreams 属性则用于引导流量的上游服务。当一个请求被 match 属性匹配时,它将根据配置的 weights 属性被引导至上游服务。你也可以不使用 match 属性,只根据 weighted_upstreams 属性来引导所有流量。

注意

由于该插件使用了加权循环算法(特别是在重置 wrr 状态时),因此在使用该插件时,可能会存在上游服务之间的流量比例不精准现象。

traffic-split - 图2注意

目前 weighted_upstreams.upstream 的配置不支持 service_namediscovery_typechecksretriesretry_timeoutdescschemelabelscreate_timeupdate_time 等字段。如果你需要使用这些字段,可以在创建上游对象时指定这些字段,然后在该插件中配置 weighted_upstreams.upstream_id 属性即可。

重要

match 属性中,变量中的表达式以 AND 方式关联,多个变量以 OR 方式关联。

如果你仅配置了 weight 属性,那么它将会使用该 Route 或 Service 中的上游服务的权重。

以下示例展示了如何在指定路由上启用 traffic-split 插件,并通过插件中的 upstream 属性配置上游信息:

如果你已经配置了一个上游对象,你可以通过插件中的 upstream_id 属性来绑定上游服务:

  1. curl http://127.0.0.1:9180/apisix/admin/routes/1 \
  2. -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
  3. {
  4. "uri": "/index.html",
  5. "plugins": {
  6. "traffic-split": {
  7. "rules": [
  8. {
  9. "weighted_upstreams": [
  10. {
  11. "upstream_id": 1,
  12. "weight": 1
  13. },
  14. {
  15. "weight": 1
  16. }
  17. ]
  18. }
  19. ]
  20. }
  21. },
  22. "upstream": {
  23. "type": "roundrobin",
  24. "nodes": {
  25. "127.0.0.1:1980": 1
  26. }
  27. }
  28. }'
traffic-split - 图4提示

通过 upstream_id 方式来绑定已定义的上游,可以复用上游已存在的健康检查、重试等功能。

注意

weighted_upstreams 属性支持同时使用 upstreamupstream_id 两种配置方式。

以下示例展示了如何通过配置 weighted_upstreamsweight 属性来实现流量分流。按 3:2 的权重流量比例进行划分,其中 60% 的流量到达运行在 1981 端口上的上游服务,40% 的流量到达运行在 1980 端口上的上游服务:

  1. curl http://127.0.0.1:9180/apisix/admin/routes/1 \
  2. -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
  3. {
  4. "uri": "/index.html",
  5. "plugins": {
  6. "traffic-split": {
  7. "rules": [
  8. {
  9. "weighted_upstreams": [
  10. {
  11. "upstream": {
  12. "name": "upstream_A",
  13. "type": "roundrobin",
  14. "nodes": {
  15. "127.0.0.1:1981":10
  16. },
  17. "timeout": {
  18. "connect": 15,
  19. "send": 15,
  20. "read": 15
  21. }
  22. },
  23. "weight": 3
  24. },
  25. {
  26. "weight": 2
  27. }
  28. ]
  29. }
  30. ]
  31. }
  32. },
  33. "upstream": {
  34. "type": "roundrobin",
  35. "nodes": {
  36. "127.0.0.1:1980": 1
  37. }
  38. }
  39. }'

测试

在请求 5 次后,其中会有 3 次命中运行在 1981 端口的插件上游服务,2 次命中运行在 1980 端口的路由上游服务:

  1. curl http://127.0.0.1:9080/index.html -i
  1. HTTP/1.1 200 OK
  2. Content-Type: text/html; charset=utf-8
  3. ...
  4. hello 1980
  1. curl http://127.0.0.1:9080/index.html -i
  1. HTTP/1.1 200 OK
  2. Content-Type: text/html; charset=utf-8
  3. ...

在蓝绿发布场景中,你需要维护两个环境,一旦新的变化在蓝色环境(staging)中被测试和接受,用户流量就会从绿色环境(production)转移到蓝色环境。

以下示例展示了如何基于请求头来配置 match 规则:

  1. curl http://127.0.0.1:9180/apisix/admin/routes/1 \
  2. -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
  3. {
  4. "uri": "/index.html",
  5. "plugins": {
  6. "traffic-split": {
  7. "rules": [
  8. {
  9. "match": [
  10. {
  11. "vars": [
  12. ["http_release","==","new_release"]
  13. ]
  14. }
  15. ],
  16. "weighted_upstreams": [
  17. {
  18. "upstream": {
  19. "name": "upstream_A",
  20. "type": "roundrobin",
  21. "nodes": {
  22. "127.0.0.1:1981":10
  23. }
  24. }
  25. }
  26. }
  27. ]
  28. }
  29. },
  30. "upstream": {
  31. "type": "roundrobin",
  32. "nodes": {
  33. "127.0.0.1:1980": 1
  34. }
  35. }
  36. }'

测试

  1. 通过 curl 命令发出请求,如果请求带有一个值为 new_release 的 release header,它就会被引导至在插件上配置的新的上游服务:
  1. curl http://127.0.0.1:9080/index.html -H 'release: new_release' -i
  1. HTTP/1.1 200 OK
  2. Content-Type: text/html; charset=utf-8
  3. ...
  4. world 1981
  1. 否则请求会被引导至在路由上配置的另一个上游服务:
  1. curl http://127.0.0.1:9080/index.html -H 'release: old_release' -i

你也可以通过配置规则和权重来实现自定义发布。

示例 1

下面的示例只配置了一个 vars 规则,流量按 3:2 的权重比例进行划分,不匹配 vars 的流量将被重定向到在路由上配置的上游服务:

  1. curl http://127.0.0.1:9180/apisix/admin/routes/1 \
  2. -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
  3. {
  4. "uri": "/index.html",
  5. "plugins": {
  6. "traffic-split": {
  7. "rules": [
  8. {
  9. "match": [
  10. {
  11. "vars": [
  12. ["arg_name","==","jack"],
  13. ["http_user-id",">","23"],
  14. ["http_apisix-key","~~","[a-z]+"]
  15. ]
  16. }
  17. ],
  18. "weighted_upstreams": [
  19. {
  20. "upstream": {
  21. "name": "upstream_A",
  22. "type": "roundrobin",
  23. "nodes": {
  24. "127.0.0.1:1981":10
  25. }
  26. },
  27. "weight": 3
  28. },
  29. {
  30. "weight": 2
  31. }
  32. ]
  33. }
  34. ]
  35. }
  36. },
  37. "upstream": {
  38. "type": "roundrobin",
  39. "nodes": {
  40. "127.0.0.1:1980": 1
  41. }
  42. }
  43. }'
  1. 通过 curl 命令发出请求,在 match 规则校验通过后,将会有 60% 的请求被引导至插件 1981 端口的上游服务,40% 的请求被引导至路由 1980 端口的上游服务:
  1. curl 'http://127.0.0.1:9080/index.html?name=jack' \
  2. -H 'user-id:30' -H 'apisix-key: hello' -i

在请求 5 次后,其中会有 3 次命中 1981 端口的服务,2 次命中 1980 端口的服务:

  1. HTTP/1.1 200 OK
  2. Content-Type: text/html; charset=utf-8
  3. ...
  4. world 1981
  1. HTTP/1.1 200 OK
  2. Content-Type: text/html; charset=utf-8
  3. ...
  4. hello 1980
  1. 如果 match 规则校验失败(如缺少请求头 apisix-key), 那么请求将被引导至路由的 1980 端口的上游服务:
  1. curl 'http://127.0.0.1:9080/index.html?name=jack' \
  2. -H 'user-id:30' -i
  1. HTTP/1.1 200 OK
  2. Content-Type: text/html; charset=utf-8
  3. ...
  4. hello 1980

示例 2

下面的示例配置了多个 vars 规则,流量按 3:2 的权重比例进行划分,不匹配 vars 的流量将被重定向到在路由上配置的上游服务:

  1. curl http://127.0.0.1:9180/apisix/admin/routes/1 \
  2. -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
  3. {
  4. "uri": "/index.html",
  5. "plugins": {
  6. "traffic-split": {
  7. "rules": [
  8. {
  9. "match": [
  10. {
  11. "vars": [
  12. ["arg_name","==","jack"],
  13. ["http_user-id",">","23"],
  14. ["http_apisix-key","~~","[a-z]+"]
  15. ]
  16. },
  17. {
  18. "vars": [
  19. ["arg_name2","==","rose"],
  20. ["http_user-id2","!",">","33"],
  21. ["http_apisix-key2","~~","[a-z]+"]
  22. ]
  23. }
  24. ],
  25. "weighted_upstreams": [
  26. {
  27. "upstream": {
  28. "name": "upstream_A",
  29. "type": "roundrobin",
  30. "nodes": {
  31. "127.0.0.1:1981":10
  32. }
  33. },
  34. },
  35. {
  36. }
  37. ]
  38. }
  39. ]
  40. }
  41. },
  42. "upstream": {
  43. "type": "roundrobin",
  44. "nodes": {
  45. "127.0.0.1:1980": 1
  46. }
  47. }
  48. }'

测试

  1. 通过 curl 命令发出请求,如果两个 vars 表达式均匹配成功,match 规则校验通过后,将会有 60% 的请求被引导至插件 1981 端口的上游服务,40% 的请求命中到路由的 1980 端口的上游服务:
  1. curl 'http://127.0.0.1:9080/index.html?name=jack&name2=rose' \
  2. -H 'user-id:30' -H 'user-id2:22' -H 'apisix-key: hello' -H 'apisix-key2: world' -i

在请求 5 次后,其中会有 3 次命中 1981 端口的服务,2 次命中 1980 端口的服务:

  1. HTTP/1.1 200 OK
  2. Content-Type: text/html; charset=utf-8
  3. ...
  4. world 1981
  1. HTTP/1.1 200 OK
  2. Content-Type: text/html; charset=utf-8
  3. ...
  4. hello 1980
  1. 如果第二个 vars 的表达式匹配失败(例如缺少 name2 请求参数),match 规则校验通过后,效果将会与上一种相同。即有 60% 的请求被引导至插件 1981 端口的上游服务,40% 的请求命中到路由的 1980 端口的上游服务:

在请求 5 次后,其中会有 3 次命中 1981 端口的服务,2 次命中 1980 端口的服务:

  1. HTTP/1.1 200 OK
  2. Content-Type: text/html; charset=utf-8
  3. ...
  4. world 1981
  1. HTTP/1.1 200 OK
  2. Content-Type: text/html; charset=utf-8
  3. ...
  4. hello 1980
  1. 如果两个 vars 的表达式均匹配失败(如缺少 namename2 请求参数),match 规则会校验失败,请求将被引导至路由的 1980 端口的上游服务:
  1. curl 'http://127.0.0.1:9080/index.html?name=jack' -i
  1. HTTP/1.1 200 OK
  2. Content-Type: text/html; charset=utf-8
  3. ...
  4. hello 1980

以下示例展示了如何配置多个 rules 属性,实现不同的匹配规则与上游一一对应。当请求头 x-api-id1 时,请求会被引导至 1981 端口的上游服务;当 x-api-id2 时,请求会被引导至 1982 端口的上游服务;否则请求会被引导至 1980 端口的上游服务:

  1. curl http://127.0.0.1:9180/apisix/admin/routes/1 \
  2. -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
  3. {
  4. "uri": "/hello",
  5. "plugins": {
  6. "traffic-split": {
  7. "rules": [
  8. {
  9. "match": [
  10. {
  11. "vars": [
  12. ["http_x-api-id","==","1"]
  13. ]
  14. }
  15. ],
  16. "weighted_upstreams": [
  17. {
  18. "upstream": {
  19. "name": "upstream-A",
  20. "type": "roundrobin",
  21. "nodes": {
  22. "127.0.0.1:1981":1
  23. }
  24. },
  25. "weight": 3
  26. }
  27. ]
  28. },
  29. {
  30. "match": [
  31. {
  32. "vars": [
  33. ["http_x-api-id","==","2"]
  34. ]
  35. }
  36. ],
  37. "weighted_upstreams": [
  38. {
  39. "upstream": {
  40. "name": "upstream-B",
  41. "type": "roundrobin",
  42. "nodes": {
  43. "127.0.0.1:1982":1
  44. }
  45. },
  46. "weight": 3
  47. }
  48. ]
  49. }
  50. ]
  51. }
  52. },
  53. "upstream": {
  54. "type": "roundrobin",
  55. "nodes": {
  56. "127.0.0.1:1980": 1
  57. }
  58. }
  59. }'

测试

  1. 通过 curl 命令发出请求,请求头 x-api-id1,则会命中 1980 端口的服务:
  1. curl http://127.0.0.1:9080/hello -H 'x-api-id: 1'
  1. 1981
  1. 如果请求头 x-api-id2,则会命中 1982 端口的服务:
  1. curl http://127.0.0.1:9080/hello -H 'x-api-id: 2'
  1. 1982
  1. 如果请求头 x-api-id3,规则不匹配,则会命中带 1980 端口的服务:
  1. curl http://127.0.0.1:9080/hello -H 'x-api-id: 3'

当你需要禁用该插件时,可以通过以下命令删除相应的 JSON 配置,APISIX 将会自动重新加载相关配置,无需重启服务:

  1. curl http://127.0.0.1:9180/apisix/admin/routes/1 \
  2. -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
  3. {
  4. "uri": "/index.html",
  5. "plugins": {},
  6. "upstream": {
  7. "type": "roundrobin",
  8. "nodes": {
  9. "127.0.0.1:1980": 1
  10. }