a6-plugin-traffic-split
概览
traffic-split 插件会根据自定义 规则(match)和加权分配(weighted_upstreams),将部分流量动态转发到不同的上游服务。它适用于灰度发布、蓝绿发布和 A/B 测试,且无需修改 DNS 或负载均衡器配置。
适用场景
- 灰度发布:逐步将流量切换到新版本(10% → 50% → 100%)。
- 蓝绿发布:根据请求头或 Cookie 切换流量。
- A/B 测试:根据用户属性(请求头、查询参数或 Cookie)拆分流量。
- 功能开关:将特定用户路由到功能分支。
- 多版本 API:同时运行多个后端版本。
插件配置参考(路由/服务)
顶层配置
| 字段 | 类型 | 是否必填 | 默认值 | 说明 |
|---|---|---|---|---|
rules | array[object] | 是 | — | 流量拆分规则列表。每条规则都可以包含可选的 match,并且必须包含 weighted_upstreams。 |
rules[].match
| 字段 | 类型 | 是否必填 | 默认值 | 说明 |
|---|---|---|---|---|
match | array[object] | 否 | [] | 激活此规则的条件。为空表示无条件匹配(所有流量都按权重分配)。 |
match[].vars | array[array] | 否 | — | 变量表达式:["variable", "operator", "value"]。使用 NGINX 变量。同一对象中的多个变量表示 AND,match 中的多个对象表示 OR。 |
运算符:==、~=、>、<、>=、<=、~~(正则匹配)、!~~、in、has、!。详见 lua-resty-expr。
常用变量:arg_name(查询参数)、http_header-name(请求头)、cookie_name(Cookie 值)。
rules[].weighted_upstreams[]
| 字段 | 类型 | 必填 | 默认 | 描述 |
|---|---|---|---|---|
upstream_id | 字符串/整数 | 否 | — | 预配置的上游对象的ID. 用这个来进行健康检查、重试等. |
upstream | 对象 | 否 | — | 内置上游配置(见下文)。 |
weight | 整数 | 否 | 1 | 分配给该上游的流量权重 |
如果只设置了 weight(未设置 upstream 或 upstream_id),流量将进入路由的默认上游。
内联上游对象
| 字段 | 类型 | 是否必填 | 默认值 | 说明 |
|---|---|---|---|---|
type | string | 否 | "roundrobin" | 负载均衡类型:"roundrobin" 或 "chash"。 |
nodes | array | 是 | — | 后端节点,格式为 [{host, port, weight}]。 |
timeout | object | 否 | 15(秒) | {"connect": N, "send": N, "read": N} |
pass_host | string | 否 | "pass" | "pass" 表示客户端 Host,"node" 表示上游节点,"rewrite" 表示使用 upstream_host。 |
upstream_host | string | 否 | — | 自定义 Host 请求头。仅在 pass_host: "rewrite" 时生效。 |
name | string | 否 | — | 上游的可读名称。 |
内联加权上游不支持:service_name、discovery_type、checks、retries 和 retry_timeout。如有可能,请将共享上游行为保留在关联的服务中。
分步指南:在路由上启用 traffic-split
1. 灰度发布:将 20% 流量发送到新版本
配置 20/80 流量分配:
a6 route create -f - <<'EOF'
{
"id": "canary-release",
"uri": "/api/*",
"plugins": {
"traffic-split": {
"rules": [
{
"weighted_upstreams": [
{
"upstream": {
"name": "new-version-v2",
"type": "roundrobin",
"nodes": {
"backend-v2:8080": 1
}
},
"weight": 2
},
{
"weight": 8
}
]
}
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"backend-v1:8080": 1
}
}
}
EOF
结果:20% 的流量发送到 backend-v2,80% 的流量发送到 backend-v1(路由默认上游)。
2. 蓝绿发布:基于请求头切换
a6 route create -f - <<'EOF'
{
"id": "blue-green",
"uri": "/api/*",
"plugins": {
"traffic-split": {
"rules": [
{
"match": [
{
"vars": [
["http_x-canary", "==", "true"]
]
}
],
"weighted_upstreams": [
{
"upstream": {
"name": "green-env",
"type": "roundrobin",
"nodes": {
"green-backend:8080": 1
}
},
"weight": 1
}
]
}
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"blue-backend:8080": 1
}
}
}
EOF
结果:包含请求头 x-canary: true 的请求发送到绿色环境,其他请求发送到蓝色环境。
3. 将灰度比例提高到 50%
a6 route update canary-release -f - <<'EOF'
{
"plugins": {
"traffic-split": {
"rules": [
{
"weighted_upstreams": [
{
"upstream": {
"name": "new-version-v2",
"type": "roundrobin",
"nodes": {
"backend-v2:8080": 1
}
},
"weight": 5
},
{
"weight": 5
}
]
}
]
}
}
}
EOF
常见模式
通过查询参数进行 A/B 测试
{
"plugins": {
"traffic-split": {
"rules": [
{
"match": [
{
"vars": [
["arg_variant", "==", "B"]
]
}
],
"weighted_upstreams": [
{
"upstream": {
"name": "variant-B",
"type": "roundrobin",
"nodes": {"variant-b:8080": 1}
}
}
]
}
]
}
}
}
带有 ?variant=B 的请求会发送到 B 版本后端。
多规则路由(OR 逻辑)
{
"plugins": {
"traffic-split": {
"rules": [
{
"match": [{"vars": [["http_x-api-id", "==", "1"]]}],
"weighted_upstreams": [
{"upstream": {"type": "roundrobin", "nodes": {"svc-a:8080": 1}}}
]
},
{
"match": [{"vars": [["http_x-api-id", "==", "2"]]}],
"weighted_upstreams": [
{"upstream": {"type": "roundrobin", "nodes": {"svc-b:8080": 1}}}
]
}
]
}
}
}
使用上游编号进行健康检查
{
"plugins": {
"traffic-split": {
"rules": [
{
"weighted_upstreams": [
{
"upstream_id": "canary-upstream",
"weight": 2
},
{
"weight": 8
}
]
}
]
}
}
}
使用a6 upstream create预先创建上游,以配置运行状况检查、重试和其他高级设置。
多重条件和匹配
{
"match": [
{
"vars": [
["arg_name", "==", "jack"],
["http_user-id", ">", "23"],
["http_x-env", "~~", "^(staging|canary)$"]
]
}
]
}
所有三个条件都必须为真(并且逻辑位于单个vars数组中)。
匹配逻辑参考
| 结构 | 逻辑 |
|---|---|
一个 vars 数组中的多个条目 | AND:必须全部匹配 |
match 数组中的多个对象 | OR:任意对象匹配即可 |
match 为空或未设置 match | 无条件:始终应用权重 |
故障排查
| 症状 | 原因 | 解决方法 |
|---|---|---|
| 流量比例不精确 | 轮询算法会产生轻微偏差 | 这是预期行为;请求数量增加后,实际比例会逐渐接近配置值 |
| 匹配规则未触发 | 变量名称错误或运算符不匹配 | 请求头使用 http_header-name,查询参数使用 arg_name |
| 健康检查未生效 | 内联上游不支持 checks | 使用 upstream_id 引用已配置健康检查的上游 |
| 所有流量都进入默认上游 | 匹配条件始终不成立 | 使用 a6 route get 调试,并核对请求头和参数名称 |
| 权重为 0 的上游仍有流量 | 误解了权重语义 | 权重 0 表示不向该上游转发流量,可用于排除该上游 |
配置同步示例
version: "1"
routes:
- id: canary-api
uri: /api/*
plugins:
traffic-split:
rules:
- weighted_upstreams:
- upstream_id: canary-upstream
weight: 2
- weight: 8
upstream_id: stable-upstream
upstreams:
- id: stable-upstream
type: roundrobin
nodes:
"stable-backend:8080": 1
- id: canary-upstream
type: roundrobin
nodes:
"canary-backend:8080": 1
本文根据 api7/a6 仓库中的 a6-plugin-traffic-split/SKILL.md 生成。可在 AI Agent Skills 页面浏览全部 Skill。