Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[frontend-gray] Increase gray types according to the ratio-weight gray #1291

Open
wants to merge 20 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
0f298d0
feat: 🎸 frontend-gray plugin support cdn type deploy
heimanba Aug 6, 2024
67a09e8
fix: 🐛 frontend-gray add ProcessStreamingResponseBody
heimanba Aug 6, 2024
0d9a738
Merge branch 'main' into main
heimanba Aug 6, 2024
8a872b9
Merge branch 'main' into main
heimanba Aug 7, 2024
4e5a471
Merge branch 'alibaba:main' into main
heimanba Aug 9, 2024
cea1812
refactor: 💡 优化代码编写以及命名问题
heimanba Aug 9, 2024
5513f95
docs: ✏️ update frontend gray plugin docs
heimanba Aug 12, 2024
3f8ef30
refactor: 💡 优化 IndexRequest 逻辑,以及加上test case
heimanba Aug 14, 2024
97260ee
Merge branch 'main' into main
CH3CHO Aug 14, 2024
b0dc0d0
Merge branch 'alibaba:main' into main
heimanba Sep 9, 2024
1de4f87
feat: 🎸 1. 添加按照比率 weight灰度能力,2. 提供注入inject 脚本到首页HTML的能力
heimanba Sep 9, 2024
e97c616
Merge branch 'main' into main
heimanba Sep 10, 2024
4453f97
feat: 🎸 [frontend-gray]grayKey 可以从cookie或者header中获取
heimanba Sep 10, 2024
122834e
Merge branch 'main' of github.com:heimanba/higress
heimanba Sep 10, 2024
2d0ddab
fix: 🐛 [frontend-gray] 修改header -> head, cookie设置默认时间为2天
heimanba Sep 10, 2024
230710a
Merge branch 'main' into main
heimanba Sep 10, 2024
102f5f6
chore: 🤖 删除 debugGrayWeight字段,同时按照比例灰度优先支持 grayKey 的用户粘滞
heimanba Sep 12, 2024
7a2926e
chore: 🤖 优化CR中提出的问题
heimanba Sep 18, 2024
995dbff
Merge branch 'main' into main
heimanba Sep 20, 2024
2728da4
Merge branch 'main' into main
heimanba Sep 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 73 additions & 7 deletions plugins/wasm-go/extensions/frontend-gray/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@
| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 |
|----------------|--------------|----|-----|----------------------------------------------------------------------------------------------------|
| `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` |
| `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}` |
| `debugGrayWeight` | boolean | 非必填 | - | 开启安比例灰度的Debug模式,用于观测按比例灰度效果 |
CH3CHO marked this conversation as resolved.
Show resolved Hide resolved
| `injection` | object | 非必填 | - | 往首页HTML中注入全局信息,比如`<script>window.global = {...}</script>` |


`rules`字段配置说明:

Expand Down Expand Up @@ -45,12 +49,28 @@
| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 |
|--------|--------|------|-----|-------------------------------------------------|
| `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,如果配置了`weight`,则优先生效 |

`injection`字段配置说明:

| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 |
|--------|--------|------|-----|-------------------------------------------------|
| `header` | array of string | 非必填 | - | 注入header信息,比如`<link rel="stylesheet" href="https://cdn.example.com/styles.css">` |
CH3CHO marked this conversation as resolved.
Show resolved Hide resolved
| `body` | map of string to string | 非必填 | - | 注入Body |
CH3CHO marked this conversation as resolved.
Show resolved Hide resolved

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



## 配置示例
### 基础配置
### 基础配置(按用户灰度)
```yml
grayKey: userid
rules:
Expand Down Expand Up @@ -83,6 +103,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固定这个用户的灰度版本(否则会在下次请求时随机选择一个灰度版本)。如果需要观测按比例灰度是否生效,使用`debugGrayWeight`开启Debug模式。

### 用户信息存在JSON中

```yml
Expand Down Expand Up @@ -163,3 +201,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:
header:
- <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首页注入代码,可以在`header`标签注入代码,也可以在`body`标签的`first`和`last`位置注入代码。
63 changes: 47 additions & 16 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"
XForwardedFor = "x-forwarded-for"
XPreHigressTag = "x-pre-higress-tag"
XMseTag = "x-mse-tag"
IsHTML = "is_html"
IsIndex = "is_index"
NotFound = "not_found"
IsIndex = "is-index"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isIndex这个名字是不是换一下,改成isPageRequest之类的?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isIndex这个名字是不是换一下,改成isPageRequest之类的?

fixed

NotFound = "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 {
Header []string
Body *BodyInjection
}

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

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

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

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

// 解析 Rules
rules := json.Get("rules").Array()
Expand All @@ -94,16 +111,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{
Header: convertToStringList(json.Get("injection.header").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,7 @@ static_resources:
value: |
{
"grayKey": "userId",
"backendGrayTag": "x-mse-tag",
"rules": [
{
"name": "inner-user",
Expand All @@ -71,7 +72,7 @@ static_resources:
],
"rewrite": {
"host": "frontend-gray-cn-shanghai.oss-cn-shanghai-internal.aliyuncs.com",
"notFoundUri": "/mfe/app1/dev/404.html",
"notFoundUri": "/mfe/app1/dev/333.html",
"indexRouting": {
"/app1": "/mfe/app1/{version}/index.html",
"/": "/mfe/app1/{version}/index.html"
Expand All @@ -88,10 +89,26 @@ static_resources:
{
"name": "beta-user",
"version": "0.0.1",
"backendVersion": "beta",
"enabled": true
"enabled": true,
"weight": 50
}
]
],
"debugGrayWeight": true,
"injection": {
"header": [
"<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
Loading