适应多样化需求:WASM 插件在全链路灰度发布中的应用

复制粘贴侠
• 阅读 121

作者:十眠

据调研数据显示,约 70% 的生产故障是由变更引起的。为了消除变更过程存在的风险,在发布过程中,我们总是希望能够用小部分特定流量来验证下新发布应用是否正常。即使新版本有问题,也能及时发现,控制影响面,保障了整体的稳定性,这就是微服务架构下的全链路灰度的能力。

MSE 在微服务全链路灰度场景下提供了一套成熟完善且开箱即用的能力。

适应多样化需求:WASM 插件在全链路灰度发布中的应用

随着企业微服务化改造的深入,对微服务治理的场景与应用也有了更多的诉求,全链路灰度就是如此。MSE 默认支持按照内容规则与百分比规则的灰度路由策略,其中按照内容灰度支持 header、params 等参数件支持精确/前缀/正则等多种匹配策略,满足常见全链路灰度场景的诉求。如果我们遇到较为复杂的场景,发现 MSE 提供的策略无法满足我们诉求时,应该怎么解决?

接下来,我们来一起讨论几个合理且较为复杂的灰度需求。

很多复杂且合理的灰度诉求

其实关于全链路灰度有其他很多合理的诉求,比如:

  1. 我们希望随机百分比可以根据参数特征来调整,这样对于每个用户来说,是否被灰度是固定的,多次调用体验一致。
  2. 我们来自于手机客户端的流量带有 version 特征、来自网页流量又是带有 tag 的特征,我们期望两者满足任一条件的流量去往灰度环境即流量条件匹配为“或”的模式;
  3. 来自我们生产流量确实比较大,我们期望第一批灰度的流量可以控制到整体 1‰ 流量的灰度诉求;
  4. 我们期望可以基于流量 Body 参数解析的灰度诉求。

面对一系列复杂并带有定制需求的合理诉求,产品层面很难做到完全支持。这些诉求在企业客户的生产实际中非常常见,而当前的 MSE 控制台配置方案似乎并不能完美应对这些多样化的实际场景。毕竟,当我们将目光转向不同企业客户的生产实践时,会发现复杂场景的变化和多样性只会更加显著。那么,我们如何能够有效地满足复杂环境下全链路灰度发布的诉求呢?

云原生网关 WASM 插件

什么是 WASM?WASM(WebAssembly)是一种可移植、高性能的二进制指令集,用于在 Web 浏览器中运行代码。Envoy 使用 WASM 作为插件扩展机制,允许开发人员编写自定义的功能扩展,以满足特定的需求。

适应多样化需求:WASM 插件在全链路灰度发布中的应用

云原生网关 WASM 插件扩展机制的工作原理如下:

  1. MSE 云原生网关提供了插件市场,供我们编写自定义的 WASM 插件来满足各种扩展的诉求,如请求/响应转换、过滤器、身份验证等。同时编写 WASM 插件支持(Go、Rust、类 JS、lua 等)。
  2. 我们只需要将编译好的 WASM 文件通过自定义插件的方式上传到插件市场,MSE 云原生网关会将其加载到 Envoy 中。
  3. 当云原生网关处理网络流量时,它会根据配置将流量传递给适当的 WASM 插件进行处理,即上图的 Custom Filters。WASM 插件可以读取和修改请求/响应数据,执行自定义逻辑,并将流量传递给下一个插件或最终目标。

MSE 插件市场还提供了一些默认认证鉴权、流量管控、安全防护等平台官方插件,可以帮助我们提升网关的安全与稳定性,并且支持多语言自定义扩展,满足网关上自定义流量治理需求。

MSE WASM 插件扩展机制的优点包括:

  1. 借助 WASM 特性支持多语言扩展,提供了灵活性和可扩展性,可以通过 WASM 插件编写开发,满足特定的业务需求。
  2. 网关 Wasm 插件与开源 Envoy100% 兼容,不存在锁定。
  3. 提供插件市场,网关的二次扩展功能均通过插件提供给用户按需使用。
  4. 插件采用热更新机制,在沙盒中执行,对网关自身稳定性无影响。

WASM 插件以其独特的轻量级和高效性能特点,为云原生网关带来了创新的扩展能力,而这一切不会带来明显的性能开销。WASM 插件运行在沙箱环境中,提供了一种安全可控的方式来部署自定义逻辑,这样不仅保障了网关的灵活性和可扩展性,也确保了对整体性能的最小影响。

看起来 MSE 云原生网关的 WASM 插件确实是一种优雅且便捷的方式,能够满足各种全链路灰度的需求。接下来,我将通过编写 WASM 插件来实现在复杂条件下的全链路灰度。

通过 WASM 插件实现参数比例

上文提到,WASM 插件可以支持多语言扩展,我们可以选择我们擅长的语言进行开发,本文以 Go 语言为例。

云原生网关提供了 wrapper 包以及相关的 API 供我们快速编写 WASM 插件。

  1. 云原生网关配置基于 x-mse-tag 的灰度路由,详见基于 MSE 云原生网关实现全链路灰度 [ 1]

服务治理泳道配置如下:

适应多样化需求:WASM 插件在全链路灰度发布中的应用

云原生网关路由配置如下:

适应多样化需求:WASM 插件在全链路灰度发布中的应用

我们创建灰度泳道,只要 header 中存在 x-mse-tag=gray 的请求都会被认为是灰度流量,且在后续链路中都会优先去往灰度环境。因此在 WASM 插件中,我们可以对流量进行任意自定义的计算和匹配。只要符合我们的灰度条件,我们就可以在请求头中添加一个名为 "x-mse-tag" 值为 "gray" 的标识。这样,我们就可以对灰度流量进行标记和识别。

  1. 定义插件扩展配置。
type ParamsRandomConfig struct {
    # 参数比例功能开关
    paramsRandomEnable    bool
    # 参数比例依据哪个Header的值,例如userId
  paramsRandomHeaderKey string
    # 参数比例的百分比值,
    paramsPercentageRatio     int64
}
  1. 解析插件扩展参数,在控制台插件配置中填写的 YAML 配置会自动转换为 JSON,此处直接从 JSON 这个参数里解析配置即可。
// 在控制台插件配置中填写的YAML配置会自动转换为JSON,此处直接从JSON这个参数里解析配置即可
func parseConfig(json gjson.Result, config *MyConfig, log wrapper.Log) error {
  // 解析出配置,更新到config中
  config.paramsRandomEnable = json.Get("paramsRandomEnable").Bool()
  config.paramsRandomHeaderKey = json.Get("paramsRandomHeaderKey").String()
  config.paramsPercentageRatio = json.Get("paramsPercentageRatio").Int()

  return nil
}
  1. 请求处理 Filter 编写。
func onHttpRequestHeaders(ctx wrapper.HttpContext, config MyConfig, log wrapper.Log) types.Action {
  if config.paramsRandomEnable {
    randomHeaderValue, err := proxywasm.GetHttpRequestHeader(config.paramsRandomHeaderKey)
    if err != nil {
      proxywasm.LogErrorf("get header enhance error: %v", err)
      return types.ActionContinue
    }

    // 取目标参数值的 hash ,用于百分比值计算
    hash := sha256.Sum256([]byte(randomHeaderValue))
    hashInt := new(big.Int)
    hashInt.SetBytes(hash[:])

    modulo := new(big.Int).Mod(hashInt, big.NewInt(100))
    result := modulo.Cmp(big.NewInt(config.paramsPercentageRatio))
    if result <= 0 {
      // 写入 x-mse-tag=gray 说明该请求流量标为 gray,在后续链路中会优先去玩gray环境的节点,
      // 如果对应的应用没有gray环境,会fallback到基线环境
      proxywasm.AddHttpRequestHeader("x-mse-tag", "gray")
    } else {
      // 不符合灰度条件的流量
      proxywasm.LogInfof("set header false value: %s, hash: %s", randomHeaderValue, hashInt)
    }
  }
  return types.ActionContinue
}
  1. 编译生成 WASM 文件

我们通过如下命令编译生成 WASM 文件。

go mod tidy
tinygo build -o main.wasm -scheduler=none -target=wasi -gc=custom -tags='custommalloc nottinygc_finalizer' ./main.go

编译成功会在当前目录下创建文件 main.wasm。该文件在下文本地调试的示例中也会被用到。

在使用云原生网关插件市场的自定义插件功能时,直接上传该文件即可。

  1. 配置参数并验证参数比例功能

适应多样化需求:WASM 插件在全链路灰度发布中的应用

如上图所示,我们指定 Header 中的 userId 为百分比依据的参数,并且配置了 10% 流量灰度的比例值。点击保存后配置,实时生效。

请求过程中 userId=1 的 header 恒定去往灰度环境,userId=11 的请求恒定去往基线环境。

  1. 观察插件日志

到目前为止,我们通过编写 WASM 插件实现了根据特定 Header 的参数比例需求。

总结

通过 WASM 插件,我们可以实现各种全链路灰度的需求,包括但不限于以下几个方面:

  • 根据用户标识进行灰度

    可以根据用户的身份、角色、权限等信息将特定用户的请求路由到相应的灰度环境,以实现个别用户的全链路灰度。

  • 根据地理位置进行灰度

    可以根据用户的地理位置信息将请求路由到特定地区的灰度环境,以满足特定地区的全链路灰度需求。

  • 基于流量比例的灰度

    可以根据流量比例将请求路由到不同的灰度环境,以实现按比例分配流量的全链路灰度。

  • 基于请求包复杂属性的灰度

    可以根据请求的属性,如请求头、请求体、查询参数等信息,来判断是否满足特定条件,从而路由请求到相应的灰度环境。

利用 WASM 插件的强大适应性,我们可以针对性地编写插件以适应不同的全链路灰度发布需求。这为定制化业务场景提供了无限的可能性,使得灰度测试和发布可以根据独特的业务要求灵活执行。特别是对于计算密集型和无状态的任务,如认证鉴权、请求/响应的加密和混淆、内容转换等,将这些逻辑部署在网关层是理想选择。它不仅保持了系统的简洁和灵活性,而且确保了核心网关功能的低性能损失,这在优化资源使用和维护服务品质方面都提供了显著的好处。

目前 MSE WASM 插件支持 Redis 访问,当然 WASM 插件也不是万能的,如果逻辑里需要对接数据库,或者要起多线程处理,就不适合做成网关插件,当前 WASM 插件也不支持这些能力。

参考链接:

[1] 基于 MSE 云原生网关实现全链路灰度https://help.aliyun.com/zh/mse/user-guide/implement-an-end-to...

[2] 开发插件_微服务引擎(MSE)

https://help.aliyun.com/zh/mse/user-guide/14/?spm=a2c4g.11186...

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
美凌格栋栋酱 美凌格栋栋酱
6个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
3年前
Opentracing + Uber Jaeger 全链路灰度调用链,Nepxion Discovery
当网关和服务在实施全链路分布式灰度发布和路由时候,我们需要一款追踪系统来监控网关和服务走的是哪个灰度组,哪个灰度版本,哪个灰度区域,甚至监控从HttpHeader头部全程传递的灰度规则和路由策略。这个功能意义在于:不仅可以监控全链路中基本的调用信息,也可以监控额外的灰度信息,有助于我们判断灰度发布和路由是否执行准确,一旦有问题,也可以快速定位
Stella981 Stella981
3年前
Dubbo + Zipkin + Brave实现全链路追踪
DubboZipkinBrave实现全链路追踪最近写了一个链路追踪Demo分享下,实现了链路追踪过程中数据的记录,还有能扩展的地方,后期再继续补充。原理参考上面文章《Dubbo链路追踪——生成全局ID(traceId)》(https://my.oschina.net/Luc
Stella981 Stella981
3年前
Nepxion Discovery Agent
前言基于SpringCloud的全链路灰度蓝绿发布功能,其中一个场景是,基于Header传递的全链路灰度路由,采用配置中心配置路由策略映射在网关或者服务上,支持根据用户自定义Header跟路由策略整合,最终转化为路由Header信息而实现,路由策略传递到全链路服务中。这是一个非常普遍的需求,但如果业务方用了服务之间异步调用的方式,会导致存储在Th
Stella981 Stella981
3年前
Nepxion Discovery【探索】图形化全链路发布编排建模和流量侦测
全链路编排建模全链路编排建模工具,只提供最经典和最常用的蓝绿灰度发布场景功能,并不覆盖框架所有的功能全链路蓝绿发布编排建模!(https://oscimg.oschina.net/oscnet/488106cc287b4e6aa1dcc5bb092148e2.png)①导航栏上选择〔全链路服务蓝绿发布〕
Stella981 Stella981
3年前
Nepxion Discovery 5.5.0 发布
!(https://oscimg.oschina.net/oscnet/f81c043194ef4732880459d00c1a720e.png)发布日志功能更新:增加基于Opentracing调用链的支持,目前支持UberJaeger,实现在SpringCloudGateway、Zuul和服务上的灰度
Stella981 Stella981
3年前
Nginx + lua +[memcached,redis]
精品案例1、Nginxluamemcached,redis实现网站灰度发布2、分库分表/基于Leaf组件实现的全球唯一ID(非UUID)3、Redis独立数据监控,实现订单超时操作/MQ死信操作SelectPollEpollReactor模型4、分布式任务调试Quartz应用
Serverless冷扩机器在压测中被击穿问题 | 京东云技术团队
有次全链路压测中,有位同事负责的服务做Serverless扩容(负载达到50%之后自动扩容并上线接入流量)中,发现新扩容的机器被击穿,理论分析之后我们重新进行现象回放,模拟问题重现
混沌演练实践(二)-支付加挂链路演练 | 京东云技术团队
当前微服务架构下,各个服务间依赖高,调用关系复杂,业务场景很少可以通过一个系统来实现,常见的业务场景实现基本涉及多个上下游系统,要保证整体链路的稳定性,需要尽量减少系统之间的耦合性,避免因为单点失效引起整个链路的故障。