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

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介:

本文是《微服务治理实践》系列篇的第三篇文章,主要分享 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;
相关文章
|
22天前
|
负载均衡 测试技术 持续交付
高效后端开发实践:构建可扩展的微服务架构
在当今快速发展的互联网时代,后端开发扮演着至关重要的角色。本文将重点探讨如何构建可扩展的微服务架构,以及在后端开发中提高效率的一些实践方法。通过合理的架构设计和技术选型,我们可以更好地应对日益复杂的业务需求,实现高效可靠的后端系统。
|
27天前
|
设计模式 API 数据库
构建高效微服务架构:从理论到实践
【2月更文挑战第29天】 在现代软件开发领域,微服务架构已经成为一种流行的设计模式,它通过将大型应用程序拆分成一系列小型、独立的服务来提高系统的可维护性、扩展性和敏捷性。本文将深入探讨微服务的核心概念、设计原则以及如何在实际项目中实现和优化微服务架构。我们将从微服务的定义出发,讨论其与传统单体架构的区别,并分析微服务的优势与挑战。接着,文章将提供一套实践指南,包括服务划分、通信机制、数据一致性问题以及安全性考虑等方面,以指导开发者构建和维护一个高效的微服务系统。
|
6天前
|
Kubernetes 安全 Java
构建高效微服务架构:从理论到实践
【4月更文挑战第9天】 在当今快速迭代与竞争激烈的软件市场中,微服务架构以其灵活性、可扩展性及容错性,成为众多企业转型的首选。本文将深入探讨如何从零开始构建一个高效的微服务系统,覆盖从概念理解、设计原则、技术选型到部署维护的各个阶段。通过实际案例分析与最佳实践分享,旨在为后端工程师提供一套全面的微服务构建指南,帮助读者在面对复杂系统设计时能够做出明智的决策,并提升系统的可靠性与维护效率。
|
23天前
|
消息中间件 敏捷开发 运维
构建高效可靠的微服务架构:策略与实践
随着现代软件开发的复杂性增加,微服务架构逐渐成为企业解决大型应用系统分解、敏捷开发和持续部署问题的有效手段。本文深入探讨了构建一个高效且可靠的微服务架构的关键策略,包括服务的合理划分、通信机制的选择、数据一致性保障以及容错处理。通过分析这些策略在具体案例中的应用,我们旨在为开发者提供一套可行的微服务设计及实施指南。
128 6
|
29天前
|
安全 数据管理 API
构建高效微服务架构:从理论到实践
【2月更文挑战第27天】 在数字化转型的浪潮中,微服务架构已成为企业追求敏捷、灵活与可扩展性的关键解决方案。本文将深入探讨微服务的设计原则、开发流程以及如何在实际项目中实现一个高性能的微服务系统。我们将通过分析微服务的核心优势,揭示其背后的技术挑战,并提供一系列切实可行的策略来优化微服务的性能和稳定性。文中不仅包含了丰富的理论依据,还结合了实际案例分析,为开发者和企业决策者提供了一套全面的微服务实施指南。
|
3天前
|
Kubernetes 监控 Cloud Native
构建高效云原生应用:基于Kubernetes的微服务治理实践
【4月更文挑战第13天】 在当今数字化转型的浪潮中,企业纷纷将目光投向了云原生技术以支持其业务敏捷性和可扩展性。本文深入探讨了利用Kubernetes作为容器编排平台,实现微服务架构的有效治理,旨在为开发者和运维团队提供一套优化策略,以确保云原生应用的高性能和稳定性。通过分析微服务设计原则、Kubernetes的核心组件以及实际案例,本文揭示了在多变的业务需求下,如何确保系统的高可用性、弹性和安全性。
10 4
|
14天前
|
消息中间件 安全 API
构建高效微服务架构:策略与实践
【4月更文挑战第1天】在数字化转型的浪潮中,微服务架构已成为企业追求敏捷、可扩展和灵活部署的重要技术手段。本文将深入探讨如何通过合理的设计原则和先进的技术栈,构建一个高效的微服务系统。我们将剖析微服务设计的核心要点,包括服务的划分、通信机制、数据一致性以及安全性问题,并结合案例分析,展示如何在现实世界中应用这些策略以提升系统的可靠性和性能。
|
15天前
|
设计模式 API 持续交付
构建高效微服务架构:从理论到实践
在当今快速迭代和部署的软件开发环境中,微服务架构已成为一种流行的设计模式,它允许开发团队以模块化的方式构建、维护和扩展应用程序。本文将深入探讨微服务的核心概念,包括其定义、优势、挑战以及如何在实际项目中实施。我们将通过一个实际案例来展示如何将传统的单体应用拆分成一系列独立、松耦合的服务,并通过容器化、服务发现、API网关和持续集成/持续部署(CI/CD)等技术手段来管理这些服务。
|
23天前
|
消息中间件 缓存 API
微服务架构下的API网关性能优化实践
在现代的软件开发中,微服务架构因其灵活性和可扩展性被广泛采用。随着服务的细分与增多,API网关作为微服务架构中的关键组件,承担着请求路由、负载均衡、权限校验等重要职责。然而,随着流量的增长和业务复杂度的提升,API网关很容易成为性能瓶颈。本文将深入探讨API网关在微服务环境中的性能优化策略,包括缓存机制、连接池管理、异步处理等方面的具体实现,旨在为开发者提供实用的性能提升指导。
|
25天前
|
缓存 负载均衡 监控
构建高效微服务架构:API网关的作用与实践
【2月更文挑战第31天】 在当今的软件开发领域,微服务架构已成为实现系统高度模块化和易于扩展的首选方法。然而,随着微服务数量的增加,确保通信效率和管理一致性变得尤为重要。本文将探讨API网关在微服务架构中的核心角色,包括其在请求路由、安全性、负载均衡以及聚合功能方面的重要性。我们将通过具体案例分析,展示如何利用API网关优化后端服务,并讨论实施过程中的最佳实践和常见挑战。