文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

漫谈全链路灰度发布

2024-11-30 03:07

关注

为了解决这一矛盾,在软件开发领域催生出了灰度发布的概念。灰度发布是一种渐进式的软件发布方式,它允许将新功能或更新逐步推送给一部分用户,而不是一次性全部发布。这样的方式能够有效降低线上故障的风险,保障用户体验,同时也为开发团队提供了更多时间和机会在全面发布前进行验证和修复。

然而,随着软件架构的演进,尤其是微服务架构的普及,软件系统往往由多个微服务组成,不同服务的版本升级需要协调和同步。在这种背景下,单一服务的灰度发布已经不能完全适应需求,全链路灰度发布应运而生。

全链路灰度发布考虑到整个软件系统的多个微服务,允许多个微服务同时进行版本控制和升级,以确保整个系统的平稳过渡和稳定性,是一种更为全面和细致的灰度发布方式。通过全链路灰度发布,开发团队能够更加精确地控制不同服务版本的发布比例,降低系统风险,保障线上稳定性,最大程度地满足用户需求。

图片

以图 1 为例,软件系统包含网关和 4 个微服务,通过全链路灰度发布,可以使ServiceB 和 ServiceD 进行灰度发布,通过灰线所示的流量进行灰度功能验证,同时不影响蓝线所示的正常访问流量。

2全链路灰度发布核心问题

我们通过图1 可以清晰地看到,在实施全链路灰度发布时,需要部署相关服务的灰度版本,并确保在整个请求的调用链上,网关和微服务组件能够准确识别正式流量和特定版本灰度流量,并根据流量类型动态地将请求路由到正确版本的上游微服务上。所以,我们需要解决以下几个问题:

微服务标识

我们通过给微服务实例添加标识的方式,使微服务实例具有版本信息,针对不同流量对应版本实例提供服务。

传统模式

在传统模式下,一般需要产品根据使用的微服务框架决定添加标识的方式。我们以基于 Spring Cloud 框架 + Nacos注册中心 的微服务为例,一般通过在微服务元数据配置(spring.cloud.nacos.discovery.metadata)中添加标识,配置示例如下:

spring:
  cloud:
    nacos:
      discovery:
        metadata:
          version: ${APP-VERSION:v1}

微服务在 Nacos 注册中心中服务信息如下:

图片

云原生模式

在云原生模式下,为微服务实例添加标识更加方便,不需要修改微服务代码配置,一般在微服务 Deployment 的 Pod 模版中添加Labal标识即可,实例如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo
spec:
  selector:
    matchLabels:
      app: demo
      version: v1
  template:
    metadata:
      labels:
        app: demo
        version: v1

流量标识

和微服务标识相同,我们也是通过为流量添加不同标识的方式区分流量,流量标识在业界还有一个更专业更形象的叫法叫流量染色。

流量染色分两步:第一步在流量源头染色,第二步在调用链内染色。

第一步比较简单,通过前端或者网关根据流量特点(比如浏览器类型,用户标识,地域标识等)为流量添加标识(比如在HTTP Header中添加version标签)。

第二步是全链路灰度中最核心也是最复杂的部分,需要流量标识在调用链中透传下去,保证调用链上的每个微服务组件都能根据标识识别流量并动态路由。

传统的微服务框架注重基础功能的实现,例如服务注册与发现、负载均衡等,而未将流量标识透传作为核心特性之一,导致在实际应用中难以实现流量标识的无缝传递。

云原生时代的 Kubernetes + Istio 同样无法帮助微服务实现流量标识透传。不少人存在误解,认为 Istio 能对微服务实例的出入流量进行拦截,应该原生支持流量标识透传,但实际上 Istio 本身没有流量标识透传的能力。

图片

Istio Sidecar 对微服务入口和出口流量拦截如上图所示,Sidecar 虽然能将入口流量1 拦截后转给微服务容器(入口流量2),也能将微服务容器出口流量 3 拦截并转发到 Pod 外(出口流量4),但 Sidecar 不知道出口流量 3 和入口流量 2 的对应关系,在实际情况中,Sidecar 会拦截很多的出口流量,也会拦截很多的入口流量,但 Sidecar 并不知道某一个出口流量对应哪个入口流量。只有微服务应用知道对应关系,因为微服务应用亲自做了流量处理(微服务应用收到入口流量请求2后,进行业务逻辑处理,然后再发出出口流量3,请求下一级微服务),所以 Istio 虽然能对微服务出入流量拦截,但不知道出入流量的对应关系,无法将入口流量的标识自动添加到出口流量上,无法做流量标识透传。

流量标识透传方式

那么如何进行流量标识透传呢,通常有以下3种方式:

微服务修改源码方式

微服务侧进行业务代码改造,从入口流量请求中获取流量标识,并在出口流量中添加流量标识,代码示例如下:

// 从请求中获取流量标识 version
String versionValue = request.getHeader("version");
// 构造新请求需要的 Header,获取到的流量标识添加到新请求的 Header 中
HttpHeaders headers = new HttpHeaders();
headers.set("version", versionValue);
// 发起出口流量请求
使用基础SDK方式

将从入口流量请求中获取流量标识,并在出口流量中添加流量标识这种共性逻辑封装到基础 SDK 中,其原理通常涉及 SDK 对请求和响应的拦截处理。这种方法的核心在于SDK能够拦截到微服务内部的请求,从请求中获取流量标识,并在微服务发起外部请求时,将这个标识加入请求中,实现流量标识的透传。基础 SDK 的工作机制一般包括以下几个关键步骤:

使用基础Agent方式

使用 Agent 技术实现流量标识透传是一种相对隐式且高度可配置的方式。Agent 是一种可以介入到 JVM 运行时的程序,它可以对 Java 应用程序进行动态的字节码操作和增强。

在实现流量标识透传时,Agent 可以通过动态字节码增强技术,通过字节码操作工具(如ASM、ByteBuddy等)对特定类或方法进行字节码增强,动态地修改微服务应用的字节码,使得在请求处理链路中自动获取到流量标识,并在请求发起时将这些标识添加到外部请求中。这些标识可能包括从HTTP头部、上下文信息、或者其他标识性的数据。

有一些基础Agent开源方案可以选择参考,如:Homer,这是专门为javaweb应用提供了无感知的header透传的开源方案,华为的Sermant,Sermant 是利用JavaAgent技术为Java应用程序提供服务网格功能的开源方案,提供了流量透传插件tag-transmission,可以帮助微服务实现流量透传功能。

三种方式总结

这三种实现流量标识透传的方式各自具有独特的优势和适用场景。总结如下:

流量路由

流量路由和微服务标识类似,由于传统模式和云原生模式都支持,较流量标识简单很多。

在传统微服务框架(如 Spring Cloud)中,实现动态路由通常通过 API 网关(如Spring Cloud Gateway)或负载均衡器(如Netflix Ribbon)等组件,根据特定的策略或规则,对流量进行分发和路由。例如,可以基于请求头中的流量标识信息,利用负载均衡策略,将请求分发到不同版本的微服务实例上,实现动态路由。

而在云原生架构下(例如 Kubernetes + Istio),动态路由更加简单。通过 Istio 中的流量管理功能,定义Gateway、VirtualService、DestinationRule等规则和配置来实现流量的精细化控制和路由。

3全链路灰度发布实践

我们在云原生模式下,对概述部分图1 所示的微服务进行全链路灰度发布实践。微服务版本情况及调用链路和图 1 一致,微服务实例列表如下:

图片

网关采用 Istio Ingress Gateway,流量标识透传采用基础 Agent 方式,可以在微服务调用链路中透传 key 为 et-mark 的 HTTP Request Header ,流量路由通过 Istio 流量管理功能实现,关键Gateway、VirtualService、DestinationRule 规则部分如下:

---
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: ingress-gateway
  namespace: e2e-canary-release
spec:
  selector:
    istio: ingressgateway
  servers:
  - hosts:
    - 'www.e2e-canary-release.com'
    port:
      name: http
      number: 80
      protocol: HTTP
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: service-a
  namespace: e2e-canary-release
spec:
  gateways:
  - e2e-canary-release/ingress-gateway
  hosts:
  - 'www.e2e-canary-release.com'
  http:
  - route:
    - destination:
        host: service-a
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: service-b
  namespace: e2e-canary-release
spec:
  hosts:
  - service-b
  http:
  - match:
    - headers:
        et-mark:
          exact: v2
    route:
    - destination:
        host: service-b
        subset: v2
  - route:
    - destination:
        host: service-b
        subset: v1
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: service-b
  namespace: e2e-canary-release
spec:
  host: service-b
  subsets:
  - labels:
      version: v1
    name: v1
  - labels:
      version: v2
    name: v2

实际效果如下,可以看到默认情况下请求流量流经的微服务版本均为正式版本v1,当请求header中包含流量标识时,即流量为灰度流量时,会按照图1 中的灰色路径流转,实现了全链路灰度发布。

图片


图片

4总结

本文首先介绍了全链路灰度发布的概念、作用以及实现全链路灰度发布时需要解决的关键问题,针对每个问题分别从传统模式和云原生模式介绍了对应的解决方案,其中对流量标识透传做了详细的介绍,然后在云原生模式下,对微服务 Demo 进行了全链路灰度发布实践,展示了实践效果。由于能力和时间有限,一些内容仅进行了粗浅介绍,希望后续可以继续深入研究分享,文中存在错误的地方,也望大家指正。

5参考文章及相关链接

作者:张海文,中国移动云能力中心高级软件研发工程师,移动云服务网格负责人,QCon、KubeCon等大会分享者,专注于云原生、微服务、算力网络等。

来源:畅聊云原生内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯