微服务治理实践 | 金丝雀发布

本文涉及的产品
注册配置 MSE Nacos/ZooKeeper,118元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
云原生网关 MSE Higress,422元/月
简介:

本文是《微服务治理实践》系列篇的第三篇文章,主要分享 Spring Cloud & Dubbo 微服务框架下的金丝雀发布。

第一篇:《微服务治理解密》
第二篇:《微服务治理实践:服务查询》

前言

阿里巴巴集团内部有不少故障是因为发布直接或间接引起。因此提升发布的质量,减少错误的发生,是有效减少线上故障的一个关键环节。

为什么大部分的故障和发布相关?因为发布是整个功能更新到线上的最后一个环节,一些研发过程中累计的问题,在最后发布环节才会触发。同时发布本身也是一个复杂的过程,在发布过程中,往往容易出现一些错误操作或者遗漏关键操作。

日常发布中,我们常常会有如下一些错误的想法:

  • 这次改动的内容比较小,而且上线要求比较急,就不需要测试直接发布上线好了
  • 发布不需要走灰度流程,快速发布上线即可
  • 灰度发布没有什么用,就是一个流程而已,发布完就直接发布线上,不用等待观察
  • 虽然灰度发布很重要,但是灰度环境很难搭建,耗时耗力优先级并不高

这些想法都可能让我们进行一次错误的发布。

阿里巴巴内部有安全生产三板斧概念: 可灰度、可观测、可回滚。所有研发同学必须要掌握发布系统的灰度、观测和回滚功能如何使用。

今天我们来聊聊灰度发布。

灰度发布策略

灰度发布是发布整个过程中一个非常重要的环境。目前灰度发布策略有这几种:

  • 蓝绿发布(Blue-Green Deployment)

1

通过部署两套环境来解决新老版本的发布问题。如果新版本(New Version)发生问题要进行回滚的时候,直接通过切流将流量全部切到老版本(Old Version)上。

优点:升级切换和回退比发布回滚迅速
缺点:成本较高,需要部署两套环境。如果新版本中基础服务出现问题,会瞬间影响全网用户;如果新版本有问题也会影响全网用户

  • 金丝雀发布(Canary Release)

2

优点:灵活,策略自定义,可以按照流量或具体的内容进行灰度(比如不同账号,不同参数),出现问题不会影响全网用户
缺点:没有覆盖到所有的用户导致出现问题不好排查

  • 滚动发布(Rolling Release)

3

金丝雀发布的一种变化。通过分批发布的方式进行多批发布(比如一共 9 个实例,分 3 批,每次 3 个实例发布),适合大规模应用发布

优点:出现问题不会影响全网用户,适合大规模应用发布
缺点:发布和回滚周期较长

本文将介绍 Spring Cloud & Dubbo 微服务框架下的金丝雀发布。

微服务金丝雀发布开源实现

微服务金丝雀发布的核心是服务路由,只要能控制服务路由的逻辑,就能确定流量的走向,确定流量走向也就意味着可以控制路由到任意节点。

目前 Spring Cloud 开源国内有 Nepxion Discovery 这款框架支持灰度发布,或是开发者自己实现 Ribbon 里对应的接口即可。 Apache Dubbo 开发者实现 Dubbo 提供的 Router 或 LoadBalance 即可;另外 Dubbo Admin 界面提供了条件路由、标签路由功能也可以完成动态路由功能。

Spring Cloud

有这么一个 Spring Cloud 服务调用场景:

4

  • Query Parameter 中存在 name=jim 的请求,路由到 192.168.1.1 节点
  • Header 中存在 Test=1 的请求,路由到 192.168.1.2 节点
  • Cookie 中存在 lang=zh-cn 的请求,路由到 192.168.1.3 节点

这些不同类型的请求数据决定着 Spring Cloud 的服务路由逻辑。Spring Cloud 服务路由组件为 Netflix Ribbon(Spring Cloud Hoxton 引入了 Spring Cloud LoadBalancer 用于替换 Netflix Ribbon)。Ribbon 内部的 ILoadBalancer 接口用于获取实例(Server)列表信息,IRule 接口用于获取最终的确定的实例(Server)。因此,如何使用/扩展这两块接口是 Spring Cloud 动态路由的核心。

不论是 Netflix Ribbon 或者 Spring Cloud LoadBalancer,它们在路由的过程中都无法获取 Request 信息,Request 信息存储着用户请求内容中的所有数据。为了这个这个解决,需要引入 ThreadLocal 来透传 Request 数据。

Apache Dubbo

Apache Dubbo 不论是 Router 或者 LoadBalance,它们提供的方法内部都可以获取到 Invocation。有了 Invocation 之后可以获取调用的方法、调用的参数类型、调用的参数值、Attachment。

这些 Invocation 里的内容可以决定过滤掉哪些 Invoker,比如定义了一个 CanaryRouter 对于 getEnv 方法路由到灰度 Invoker,否则路由到其它 Invoker(每个节点注册的时候设置一个自定义的 parameter gray 到 url 中,表示这是一个灰度节点):

public class CanaryRouter extends AbstractRouter {
    @Override
    public <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException {
        List<Invoker> normal = new ArrayList<>();
        List<Invoker> canary = new ArrayList<>();
        for(Invoker invoker : invokers) {
            if(invoker.getUrl().getParameter("gray", false)) {
                canary.add(invoker);
            } else {
                normal.add(invoker);
            }
        }
        if(invocation.getMethodName().equals("getEnv")) {
            return canary;
        } else {
            return normal;
        }
    }
}

EDAS 金丝雀发布实践

EDAS 金丝雀发布支持 Apache Dubbo 和 Spring Cloud 微服务框架。金丝雀发布的底层使用 Java Agent 技术通过字节码增强 Apache Dubbo 和 Spring Cloud 的路由逻辑。由于是使用 Agent 技术,而且在抽象类上进行了拦截,这使得对 Apache Dubbo 和 Spring Cloud 的 的版本以及注册中心都有了更全面的支持。

  • 版本: Apache Dubbo 支持 2.5.x, 2.6.x 以及 2.7.x;Spring Cloud 支持 Dalston、Edgware、Finchley 以及 Hoxton(暂不支持 Hoxton 里的 Spring Cloud LoadBalancer 负载均衡组件)
  • 注册中心: 支持 Zookeeper,Consul,Eureka,Nacos,Etcd 等注册中心

下面,我们开始体验 EDAS 上的金丝雀发布。

创建应用

创建 Provider 和 Consumer 应用:

5

Provider 请注意填写至少 2 个 Pod 数:

6

全部创建完毕后,调用 consumer 对外暴露的地址确认 consumer 可以顺利调用 provider 服务。

金丝雀发布

Provider 进行应用部署,选择金丝雀发布:
7

设置新版本号:

8

设置对应的规则(本文使用按比例灰度,90% 的流量进入灰度实例):

9

等待金丝雀发布完毕:
10

金丝雀发布结果验证

金丝雀发布完毕后,再次调用 consumer 对外暴露的地址确认金丝雀是否生效。或者可以在发布单页面中查看灰度监控数据:

11

12

这里查看了 3 分钟监控,89.89% 的流量进入了灰度实例(时间越久,比例越准确),基本满足按照比例的灰度部署。

当结果符合预期并进行全量发布时,发布单页面点击 "下一步" 即可:
13

规则解释

Spring Cloud

Spring Cloud 灰度规则目前支持两种类型:

  • 按比例灰度,可设置 0 - 100 之间的整数
  • 按内容灰度,可以根据参数的内容进行灰度

14

其中 path 表示请求路径(不填表示支持所有路径),参数类型支持选择 Cookie,Header 或 Parameter,条件支持 "=", ">", "<", ">=", "<=", "!=", 白名单, 取模。

条件列表中的每一项支持 "与" 或者 "或" 运算。

举个例子,这是 consumer 调用 provider 的一个请求:

URL: http://custom-provider/goods/query
Parameter: goodsId=JL110
Header: ENV=Prod

那么规则可以这样设置:

15

Apache Dubbo

Apache Dubbo 灰度规则目前支持两种类型:

  • 按比例灰度,可设置 0 - 100 之间的整数
  • 按内容灰度,可以根据接口参数的内容进行灰度

其中条件支持 "=", ">", "<", ">=", "<=", "!=", 白名单, 取模。

条件列表中的每一项支持 "与" 或者 "或" 运算。

举个例子,定义一个接口如下:

public interface CanaryService {

    String call(String str, int num1,
        Integer num2, String[] strArr, Map<String, String> map,
        List<String> list, User user);

}

这是 consumer 调用 provider 的参数信息:

str=str
num1=1
num2=2
strArr=[1, 2, 3]
map={"1":"1", "2", "3"}
list=[0, 1, 2]
User=User{name=name, age=20}

那么规则可以这样设置:

16

参数 0、1、2 是 String、int 和 Integer 对象,无需设置表达式,直接进行比较。
参数 3 表示一个 String[] 数组,表达式 [0] 表示取第 1 个元素,数组中的第 1 个元素为 1。
参数 4 表示一个 Map<String, String>,表达式 .get("1") 表示取 key 为 "1" 的元素,Map 中 key 为 "1" 的元素是 "1"。
参数 5 表示一个 List 集合,表达式 .get(1)表示取第 2 个元素,数组中的第 2 个元素为 1。
参数 6 表示一个自定义 User 对象(有 name 和 age 两个属性),表达式 .getName() 表示调用 getName() 方法,该方法返回 name 属性的值,这里传递的是 name。

ECS 集群使用

上述内容介绍的是在 K8S 集群下的操作。如若在 ECS 集群下使用,需要确保至少存在 2 个分组(如下截图存在 "默认分组" 和 "gray" 这两个分组):

17

部署应用,选择金丝雀发布:

18

上传新的部署包,设置新版本号,选择灰度分组:

19

后续规则的操作跟 K8S 集群一致。

金丝雀发布后回滚

当金丝雀发布后,发现有 bug 存在,需要进行应用回滚。

发布单页面直接点击 "立即回滚":

20

金丝雀发布实现细节

Apache Dubbo 金丝雀底层实现的原理是通过 Java Agent 技术动态添加一个 Router,该 Router 内部使用了 Spring 的表达式 SPEL 进行参数,表达式解析结果判断是否需要对 Invoker 列表进行修改。如果是常规请求,删除灰度节点;如果是灰度请求,删除正常节点。

Spring Cloud 金丝雀底层的实现细节是对 ILoadBalancer 接口对应的实现类返回的 Server 列表进行修改。如果是常规请求,删除灰度节点;如果是灰度请求,删除正常节点。

这里如何判断哪些节点是灰度节点呢? 这会跟应用发布流程绑定,当使用 ECS 集群需要选择灰度分组,K8S 集群需要填写灰度 Pod 个数。这些灰度实例或灰度 Pod 启动的时候会带上一个灰度标表示自己是一个灰度实例或 Pod(Spring Cloud 写入到 metadata 持久化到注册中心;Apache Dubbo 写入到 custom parameter 持久化到注册中心)。

另外一个问题: 灰度规则如何保存呢?我们在 Agent 里通过 Nacos Configuration 的监听去监听对应 dataId 的数据变化,这里的 dataId 跟每个应用 id 绑定(应用 id 也通过跟灰度标一样的机制持久化到注册中心)。每次应用发布都会在 id 对应的 dataId 中写入灰度规则,Agent 监听并在内存进行修改。

招贤纳士

我们 Dubbo / Spring Cloud 商业化团队正在招人,除了 EDAS,我们还有 ARMS (应用实时监控服务)、MSE(微服务引擎)、ACM(应用配置管理)、SAE(Serverless 应用引擎)等独立产品。我们在忙什么?用心打磨这些产品,就是我们的工作。团队的目标是将阿里巴巴在服务治理上的最佳实践通过产品化的形式输出给阿里云上的企业客户,帮助客户实现业务永远在线。

简历投递方式:fangjian.fj@alibaba-inc.com

作者信息:

方剑(花名:洛夜)阿里云智能高级开发工程师,Spring Cloud Alibaba PMC,Apache RocketMQ Committer, Nacos Committer。主要负责 Spring Cloud Alibaba 开源项目及微服务商业化内容,目前关注 Spring Ecosystem, 微服务,云原生等领域。

相关实践学习
使用DAS实现数据库自动SQL优化
本场景介绍如何使用DAS实现数据库自动SQL优化。
SpringMVC框架入门
Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。在使用Spring进行WEB开发时,可以选择使用Spring的SpringMVC框架或集成其他MVC开发框架,如Struts2等。 相关的阿里云产品企业级分布式应用服务 EDAS:企业级分布式应用服务 EDAS(Enterprise Distributed Application Service)是一个应用托管和微服务管理的 PaaS 平台,提供应用开发、部署、监控、运维等全栈式解决方案,同时支持 Spring Cloud、Apache Dubbo(以下简称 Dubbo )等微服务运行环境,助力您的各类应用轻松上云。产品详情: https://www.aliyun.com/product/edas&nbsp;
相关文章
|
8天前
|
API 持续交付 开发者
后端开发中的微服务架构实践与挑战
在数字化时代,后端服务的构建和管理变得日益复杂。本文将深入探讨微服务架构在后端开发中的应用,分析其在提高系统可扩展性、灵活性和可维护性方面的优势,同时讨论实施微服务时面临的挑战,如服务拆分、数据一致性和部署复杂性等。通过实际案例分析,本文旨在为开发者提供微服务架构的实用见解和解决策略。
|
9天前
|
弹性计算 Kubernetes Cloud Native
云原生架构下的微服务设计原则与实践####
本文深入探讨了在云原生环境中,微服务架构的设计原则、关键技术及实践案例。通过剖析传统单体架构面临的挑战,引出微服务作为解决方案的优势,并详细阐述了微服务设计的几大核心原则:单一职责、独立部署、弹性伸缩和服务自治。文章还介绍了容器化技术、Kubernetes等云原生工具如何助力微服务的高效实施,并通过一个实际项目案例,展示了从服务拆分到持续集成/持续部署(CI/CD)流程的完整实现路径,为读者提供了宝贵的实践经验和启发。 ####
|
1天前
|
监控 Go API
Go语言在微服务架构中的应用实践
在微服务架构的浪潮中,Go语言以其简洁、高效和并发处理能力脱颖而出,成为构建微服务的理想选择。本文将探讨Go语言在微服务架构中的应用实践,包括Go语言的特性如何适应微服务架构的需求,以及在实际开发中如何利用Go语言的特性来提高服务的性能和可维护性。我们将通过一个具体的案例分析,展示Go语言在微服务开发中的优势,并讨论在实际应用中可能遇到的挑战和解决方案。
|
17天前
|
Kubernetes 负载均衡 Docker
构建高效后端服务:微服务架构的探索与实践
【10月更文挑战第20天】 在数字化时代,后端服务的构建对于任何在线业务的成功至关重要。本文将深入探讨微服务架构的概念、优势以及如何在实际项目中有效实施。我们将从微服务的基本理念出发,逐步解析其在提高系统可维护性、扩展性和敏捷性方面的作用。通过实际案例分析,揭示微服务架构在不同场景下的应用策略和最佳实践。无论你是后端开发新手还是经验丰富的工程师,本文都将为你提供宝贵的见解和实用的指导。
|
1天前
|
Kubernetes Cloud Native Docker
云原生技术探索:容器化与微服务的实践之道
【10月更文挑战第36天】在云计算的浪潮中,云原生技术以其高效、灵活和可靠的特性成为企业数字化转型的重要推手。本文将深入探讨云原生的两大核心概念——容器化与微服务架构,并通过实际代码示例,揭示如何通过Docker和Kubernetes实现服务的快速部署和管理。我们将从基础概念入手,逐步引导读者理解并实践云原生技术,最终掌握如何构建和维护一个高效、可扩展的云原生应用。
|
2天前
|
监控 API 持续交付
后端开发中的微服务架构实践与挑战####
本文深入探讨了微服务架构在后端开发中的应用,分析了其优势、面临的挑战以及最佳实践策略。不同于传统的单体应用,微服务通过细粒度的服务划分促进了系统的可维护性、可扩展性和敏捷性。文章首先概述了微服务的核心概念及其与传统架构的区别,随后详细阐述了构建微服务时需考虑的关键技术要素,如服务发现、API网关、容器化部署及持续集成/持续部署(CI/CD)流程。此外,还讨论了微服务实施过程中常见的问题,如服务间通信复杂度增加、数据一致性保障等,并提供了相应的解决方案和优化建议。总之,本文旨在为开发者提供一份关于如何在现代后端系统中有效采用和优化微服务架构的实用指南。 ####
|
4天前
|
消息中间件 设计模式 运维
后端开发中的微服务架构实践与挑战####
本文深入探讨了微服务架构在现代后端开发中的应用,通过实际案例分析,揭示了其在提升系统灵活性、可扩展性及促进技术创新方面的显著优势。同时,文章也未回避微服务实施过程中面临的挑战,如服务间通信复杂性、数据一致性保障及部署运维难度增加等问题,并基于实践经验提出了一系列应对策略,为开发者在构建高效、稳定的微服务平台时提供有价值的参考。 ####
|
5天前
|
消息中间件 监控 数据管理
后端开发中的微服务架构实践与挑战####
【10月更文挑战第29天】 在当今快速发展的软件开发领域,微服务架构已成为构建高效、可扩展和易于维护应用程序的首选方案。本文探讨了微服务架构的核心概念、实施策略以及面临的主要挑战,旨在为开发者提供一份实用的指南,帮助他们在项目中成功应用微服务架构。通过具体案例分析,我们将深入了解如何克服服务划分、数据管理、通信机制等关键问题,以实现系统的高可用性和高性能。 --- ###
26 2
|
6天前
|
监控 安全 应用服务中间件
微服务架构下的API网关设计策略与实践####
本文深入探讨了在微服务架构下,API网关作为系统统一入口点的设计策略、实现细节及其在实际应用中的最佳实践。不同于传统的摘要概述,本部分将直接以一段精简的代码示例作为引子,展示一个基于NGINX的简单API网关配置片段,随后引出文章的核心内容,旨在通过具体实例激发读者兴趣,快速理解API网关在微服务架构中的关键作用及实现方式。 ```nginx server { listen 80; server_name api.example.com; location / { proxy_pass http://backend_service:5000;
|
16天前
|
监控 Cloud Native Java
云原生架构下微服务治理策略与实践####
【10月更文挑战第20天】 本文深入探讨了云原生环境下微服务架构的治理策略,通过分析当前技术趋势与挑战,提出了一系列高效、可扩展的微服务治理最佳实践方案。不同于传统摘要概述内容要点,本部分直接聚焦于治理核心——如何在动态多变的分布式系统中实现服务的自动发现、配置管理、流量控制及故障恢复,旨在为开发者提供一套系统性的方法论,助力企业在云端构建更加健壮、灵活的应用程序。 ####
63 10
下一篇
无影云桌面