Skip to content

Commit

Permalink
[frontend-gray] Increase gray types according to the ratio-weight gray (
Browse files Browse the repository at this point in the history
  • Loading branch information
heimanba committed Sep 22, 2024
1 parent ffc5458 commit ee67553
Show file tree
Hide file tree
Showing 6 changed files with 389 additions and 120 deletions.
82 changes: 75 additions & 7 deletions plugins/wasm-go/extensions/frontend-gray/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,15 @@ description: 前端灰度插件配置参考
| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 |
|----------------|--------------|----|-----|----------------------------------------------------------------------------------------------------|
| `grayKey` | string | 非必填 | - | 用户ID的唯一标识,可以来自Cookie或者Header中,比如 userid,如果没有填写则使用`rules[].grayTagKey``rules[].grayTagValue`过滤灰度规则 |
| `graySubKey` | string | 非必填 | - | 用户身份信息可能以JSON形式透出,比如:`userInfo:{ userCode:"001" }`,当前例子`graySubKey`取值为`userCode` |
| `rules` | array of object | 必填 | - | 用户定义不同的灰度规则,适配不同的灰度场景 |
| `rewrite` | object | 必填 | - | 重写配置,一般用于OSS/CDN前端部署的重写配置 |
| `baseDeployment` | object | 非必填 | - | 配置Base基线规则的配置 |
| `grayDeployments` | array of object | 非必填 | - | 配置Gray灰度的生效规则,以及生效版本 |
| `graySubKey` | string | 非必填 | - | 用户身份信息可能以JSON形式透出,比如:`userInfo:{ userCode:"001" }`,当前例子`graySubKey`取值为`userCode` |
| `userStickyMaxAge` | int | 非必填 | 172800 | 用户粘滞的时长:单位为秒,默认为`172800`,2天时间 |
| `rules` | array of object | 必填 | - | 用户定义不同的灰度规则,适配不同的灰度场景 |
| `rewrite` | object | 必填 | - | 重写配置,一般用于OSS/CDN前端部署的重写配置 |
| `baseDeployment` | object | 非必填 | - | 配置Base基线规则的配置 |
| `grayDeployments` | array of object | 非必填 | - | 配置Gray灰度的生效规则,以及生效版本 |
| `backendGrayTag` | string | 非必填 | `x-mse-tag` | 后端灰度版本Tag,如果配置了,cookie中将携带值为`${backendGrayTag}:${grayDeployments[].backendVersion}` |
| `injection` | object | 非必填 | - | 往首页HTML中注入全局信息,比如`<script>window.global = {...}</script>` |


`rules`字段配置说明:

Expand Down Expand Up @@ -56,12 +60,30 @@ description: 前端灰度插件配置参考
| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 |
|--------|--------|------|-----|-------------------------------------------------|
| `version` | string | 必填 | - | Gray版本的版本号,如果命中灰度规则,则使用此版本。如果是非CDN部署,在header添加`x-higress-tag` |
| `backendVersion` | string | 必填 | - | 后端灰度版本,会在`XHR/Fetch`请求的header头添加 `x-mse-tag`到后端 |
| `backendVersion` | string | 必填 | - | 后端灰度版本,配合`key``${backendGrayTag}`,写入cookie中 |
| `name` | string | 必填 | - | 规则名称和`rules[].name`关联, |
| `enabled` | boolean | 必填 | - | 是否启动当前灰度规则 |
| `weight` | int | 非必填 | - | 按照比例灰度,比如`50`。注意:灰度规则权重总和不能超过100,如果同时配置了`grayKey`以及`grayDeployments[0].weight`按照比例灰度优先生效 |
> 为了实现按比例(weight) 进行灰度发布,并确保用户粘滞,我们需要确认客户端的唯一性。如果配置了 grayKey,则将其用作唯一标识;如果未配置 grayKey,则使用客户端的访问 IP 地址作为唯一标识。

`injection`字段配置说明:

| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 |
|--------|--------|------|-----|-------------------------------------------------|
| `head` | array of string | 非必填 | - | 注入head信息,比如`<link rel="stylesheet" href="https://cdn.example.com/styles.css">` |
| `body` | object | 非必填 | - | 注入Body |

`injection.body`字段配置说明:
| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 |
|--------|--------|------|-----|-------------------------------------------------|
| `first` | array of string | 非必填 | - | 注入body标签的首部 |
| `after` | array of string | 非必填 | - | 注入body标签的尾部 |



## 配置示例
### 基础配置
### 基础配置(按用户灰度)
```yml
grayKey: userid
rules:
Expand Down Expand Up @@ -94,6 +116,24 @@ cookie中的用户唯一标识为 `userid`,当前灰度规则配置了`beta-us

否则使用`version: base`版本

### 按比例灰度
```yml
grayKey: userid
rules:
- name: inner-user
grayKeyValue:
- '00000001'
- '00000005'
baseDeployment:
version: base
grayDeployments:
- name: beta-user
version: gray
enabled: true
weight: 80
```
总的灰度规则为100%,其中灰度版本的权重为`80%`,基线版本为`20%`。一旦用户命中了灰度规则,会根据IP固定这个用户的灰度版本(否则会在下次请求时随机选择一个灰度版本)。

### 用户信息存在JSON中

```yml
Expand Down Expand Up @@ -174,3 +214,31 @@ grayDeployments:
- `/app1/js/a.js` => `/mfe/app1/v1.0.0/js/a.js`
- `/app1/js/template/a.js` => `/mfe/app1/v1.0.0/js/template/a.js`


### 往HTML首页注入代码
```yml
grayKey: userid
rules:
- name: inner-user
grayKeyValue:
- '00000001'
- '00000005'
baseDeployment:
version: base
grayDeployments:
- name: beta-user
version: gray
enabled: true
weight: 80
injection:
head:
- <script>console.log('Header')</script>
body:
first:
- <script>console.log('hello world before')</script>
- <script>console.log('hello world before1')</script>
last:
- <script>console.log('hello world after')</script>
- <script>console.log('hello world after2')</script>
```
通过 `injection`往HTML首页注入代码,可以在`head`标签注入代码,也可以在`body`标签的`first`和`last`位置注入代码。
80 changes: 58 additions & 22 deletions plugins/wasm-go/extensions/frontend-gray/config/config.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
package config

import (
"strings"

"github.com/tidwall/gjson"
)

const (
XHigressTag = "x-higress-tag"
XPreHigressTag = "x-pre-higress-tag"
XMseTag = "x-mse-tag"
IsHTML = "is_html"
IsIndex = "is_index"
NotFound = "not_found"
XHigressTag = "x-higress-tag"
XUniqueClientId = "x-unique-client"
XPreHigressTag = "x-pre-higress-tag"
IsPageRequest = "is-page-request"
IsNotFound = "is-not-found"
)

type LogInfo func(format string, args ...interface{})
Expand All @@ -22,16 +23,12 @@ type GrayRule struct {
GrayTagValue []string
}

type BaseDeployment struct {
Name string
Version string
}

type GrayDeployment struct {
type Deployment struct {
Name string
Enabled bool
Version string
BackendVersion string
Weight int
}

type Rewrite struct {
Expand All @@ -41,13 +38,27 @@ type Rewrite struct {
File map[string]string
}

type Injection struct {
Head []string
Body *BodyInjection
}

type BodyInjection struct {
First []string
Last []string
}

type GrayConfig struct {
GrayKey string
GraySubKey string
Rules []*GrayRule
Rewrite *Rewrite
BaseDeployment *BaseDeployment
GrayDeployments []*GrayDeployment
UserStickyMaxAge string
TotalGrayWeight int
GrayKey string
GraySubKey string
Rules []*GrayRule
Rewrite *Rewrite
BaseDeployment *Deployment
GrayDeployments []*Deployment
BackendGrayTag string
Injection *Injection
}

func convertToStringList(results []gjson.Result) []string {
Expand All @@ -71,6 +82,17 @@ func JsonToGrayConfig(json gjson.Result, grayConfig *GrayConfig) {
// 解析 GrayKey
grayConfig.GrayKey = json.Get("grayKey").String()
grayConfig.GraySubKey = json.Get("graySubKey").String()
grayConfig.BackendGrayTag = json.Get("backendGrayTag").String()
grayConfig.UserStickyMaxAge = json.Get("userStickyMaxAge").String()

if grayConfig.UserStickyMaxAge == "" {
// 默认值2天
grayConfig.UserStickyMaxAge = "172800"
}

if grayConfig.BackendGrayTag == "" {
grayConfig.BackendGrayTag = "x-mse-tag"
}

// 解析 Rules
rules := json.Get("rules").Array()
Expand All @@ -94,16 +116,30 @@ func JsonToGrayConfig(json gjson.Result, grayConfig *GrayConfig) {
baseDeployment := json.Get("baseDeployment")
grayDeployments := json.Get("grayDeployments").Array()

grayConfig.BaseDeployment = &BaseDeployment{
grayConfig.BaseDeployment = &Deployment{
Name: baseDeployment.Get("name").String(),
Version: baseDeployment.Get("version").String(),
Version: strings.Trim(baseDeployment.Get("version").String(), " "),
}
for _, item := range grayDeployments {
grayConfig.GrayDeployments = append(grayConfig.GrayDeployments, &GrayDeployment{
if !item.Get("enabled").Bool() {
continue
}
grayWeight := int(item.Get("weight").Int())
grayConfig.GrayDeployments = append(grayConfig.GrayDeployments, &Deployment{
Name: item.Get("name").String(),
Enabled: item.Get("enabled").Bool(),
Version: item.Get("version").String(),
Version: strings.Trim(item.Get("version").String(), " "),
BackendVersion: item.Get("backendVersion").String(),
Weight: grayWeight,
})
grayConfig.TotalGrayWeight += grayWeight
}

grayConfig.Injection = &Injection{
Head: convertToStringList(json.Get("injection.head").Array()),
Body: &BodyInjection{
First: convertToStringList(json.Get("injection.body.first").Array()),
Last: convertToStringList(json.Get("injection.body.last").Array()),
},
}
}
25 changes: 21 additions & 4 deletions plugins/wasm-go/extensions/frontend-gray/envoy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ static_resources:
value: |
{
"grayKey": "userId",
"backendGrayTag": "x-mse-tag",
"userStickyMaxAge": 172800,
"rules": [
{
"name": "inner-user",
Expand All @@ -71,7 +73,7 @@ static_resources:
],
"rewrite": {
"host": "frontend-gray-cn-shanghai.oss-cn-shanghai-internal.aliyuncs.com",
"notFoundUri": "/mfe/app1/dev/404.html",
"notFoundUri": "/mfe/app1/{version}/333.html",
"indexRouting": {
"/app1": "/mfe/app1/{version}/index.html",
"/": "/mfe/app1/{version}/index.html"
Expand All @@ -88,10 +90,25 @@ static_resources:
{
"name": "beta-user",
"version": "0.0.1",
"backendVersion": "beta",
"enabled": true
"enabled": true,
"weight": 50
}
]
],
"injection": {
"head": [
"<script>console.log('Header')</script>"
],
"body": {
"first": [
"<script>console.log('hello world before')</script>",
"<script>console.log('hello world before1')</script>"
],
"last": [
"<script>console.log('hello world after')</script>",
"<script>console.log('hello world after2')</script>"
]
}
}
}
- name: envoy.filters.http.router
typed_config:
Expand Down
Loading

0 comments on commit ee67553

Please sign in to comment.