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

目前在 weighted_upstreams.upstream 的配置中,不支持的字段有: service_name、discovery_type、checks、retries、retry_timeout、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、在 match 里,vars 中的表达式是 and 的关系,多个 vars 之间是 or 的关系。2、在插件的 weighted_upstreams 域中,如果存在只有 weight 的结构,表示 routeservice 上的 upstream 流量权重值。例如:

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

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

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

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

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

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

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

插件测试:

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

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

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

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

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

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

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

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

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

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

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

插件测试:

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

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

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

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

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

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

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

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

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

测试插件:

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

  1. $ 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
  2. HTTP/1.1 200 OK
  3. Content-Type: text/html; charset=utf-8
  4. ......
  5. world 1981

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

  1. $ 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
  2. HTTP/1.1 200 OK
  3. Content-Type: text/html; charset=utf-8
  4. ......
  5. world 1981
  1. $ 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
  2. HTTP/1.1 200 OK
  3. Content-Type: text/html; charset=utf-8
  4. ......
  5. hello 1980

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

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

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

通过配置多个 rules,我们可以实现不同的匹配规则与上游一一对应。

示例:

当请求头 x-api-id 等于 1 时,命中 1981 端口的上游;当 x-api-id 等于 2 时,命中 1982 端口的上游;否则,命中 1980 端口的上游(上游响应数据为对应的端口号)。

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

测试插件:

请求头 x-api-id 等于 1,命中带 1981 端口的上游。

  1. $ curl http://127.0.0.1:9080/hello -H 'x-api-id: 1'
  2. 1981

请求头 x-api-id 等于 2,命中带 1982 端口的上游。

  1. $ curl http://127.0.0.1:9080/hello -H 'x-api-id: 2'
  2. 1982

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

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