掌门1对1微服务体系Solar第1弹:全链路灰度蓝绿发布智能化实践

Posted by Yezhiwei on May 1, 2020

原文链接:https://mp.weixin.qq.com/s/o_BYQ8Gz_YIykgTVR8yO9A

掌门教育自 2014 年正式转型在线教育以来,秉承“让教育共享智能,让学习高效快乐”的宗旨和愿景,经历云计算、大数据、人工智能、AR/VR/MR 以及现今最火的 5G,一直坚持用科技赋能教育。掌门教育的业务近几年得到了快速发展,特别是今年的疫情,使在线教育成为了新的风口,也给掌门1对1新的机遇。随着业务规模进一步扩大,流量进一步暴增,微服务体系下,业务服务新增和迭代频率大大加快,运维和业务人员经常需要熬夜人工上线,疲劳状态下容易产生生产事故,运维成本和业务成本也将大大上升。在此背景下,基础架构部推出可以白天安全上线,流量无损的微服务灰度蓝绿发布智能化系统,并通过强有力的各种监控手段来保证流量的精确制导和调拨,提升技术驱动能力。

关于 Solar

Solar 作为掌门1对1下一代基础微服务体系,2019年11月开始筹划,2020年1月4日推出第一版,2020年4月15日发布 1.2.0 & 2.2.0 里程碑稳定版,兼容 Spring Cloud Edgware版、Finchley版、Greenwich版、Hoxton版本。基于三层体系而构建:

  • 基础公共组件。Solar 的基础组件,基础公共组件一般呈原子层面的独立存在,组件间也可适当耦合,基本上可达到一个组件被移除,不影响另外一个组件的运行的特征。
  • 基础公共框架。Solar 的基础框架,依托 Spring Cloud 服务体系,以框架形式对外暴露。它的另外一个重要特征,是对基础公共组件的聚合,一种“搭积木”的方式进行构建。
  • 基础公共服务。Solar 的基础服务,以公共服务形式对外暴露。它的另外一个重要特征,是对基础公共组件的使用,它是 Solar 框架卫星环绕式的组成部分。

Solar 基于 Spring Cloud 技术栈,支持 Eureka 注册中心、Apollo 配置中心、Zuul 网关、2个限流熔断降级组件(Sentinel、Hystrix)等,Skywalking + Opentracing 和 CAT 的 APM 调用链监控,Prometheus + Grafana 指标监控,Kibana 日志监控等,具有企业级的插件引入、开箱即用特征。它包含几大核心模块:

  • 全链路灰度蓝绿发布智能化&DevOps 发布平台集成
  • Zuul 网关动态过滤转发灰度蓝绿&Furion 统一控制台
  • Sentinel 全链路熔断限流降级权限和自研功能
  • Apollo & Eureka & VI & Sensitive & EventBus & Agent & XXL-Job 等中间件和组件
  • Docker CI &自动化测试
  • 服务和网关一键脚手架
  • 监控三要素,Tracer(Skywalking & CAT),Metrics (多维度的业务指标监控),Logger(MDC,Kibana & ES & GOHANGOUT等的ELK日志集群)
  • 打通基础数据中间件,MySQL(ShardingSphere)& RocketMQ & MongoDB & Redis
  • 支持大数据平台,Kafka & Elastic Search & InfluxDB
  • 接入GPM监控平台,Prometheus & Grafana & InfluxDB & AlarmCenter (运维、邮件、钉钉机器人和掌控APP告警)
  • 接入阿里云,OSS 支撑

术语解释

全链路

用于端到端的调用访问范畴,一般是往网关到下游若干服务的链路拓扑结构。例如,网关 -> A服务 -> B服务 ->……的调用和访问

灰度发布

灰度发布又名金丝雀发布,指不停机旧版本,部署新版本,低比例流量(例如:5%)切换到新版本,高比例流量(例如:95%)仍走旧版本。通过监控观察确认无问题,逐步扩大范围,慢慢的把所有流量都迁移到新版本上来。

灰度发布的作用:支持白天向生产环境发布新服务,安全平滑的逐步切换流量,保证流量以最小代价实现无损。

全链路灰度发布

全链路灰度发布是指流量在全链路权重分配。如下两条链路,流量必须走“链路1”或者“链路2”,不能出现交叉情形,例如,A服务(1.0版本)不允许去访问B服务(2.0版本),这样方式可以有效避免新旧版本不兼容的情况。

链路1:网关 -> A服务(1.0版本) -> B服务(1.0版本) 链路2:网关 -> A服务(2.0版本) -> B服务(2.0版本)

操作者给“链路1”分配 95% 的权重流量,给“链路2”分配 5% 的权重流量。假如“链路2”中任何一个服务出现问题,我们可以直接切掉“链路2”的 5% 流量,实施流量回滚。下文中提到的版本 1.0 表示已经上线的旧服务,版本 2.0 表示即将要上线的新服务。

蓝绿发布

蓝绿发布即不停机旧版本,部署新版本,将流量切到新版本,便于快速回滚,旧版本待流量为零,可以继续保留较长时间后下线。

蓝绿发布的作用:支持白天向生产环境发布新服务,通过条件方式,实现在两个部署环境快速切换,如果新服务存在问题,可以快速切换到老服务,保证流量以最小代价实现无损。

全链路蓝绿发布

全链路灰度发布是指流量在全链路条件分配。如下两条链路,流量必须走“链路1”或者“链路2”,不能出现交叉情形,例如,A服务(1.0版本)不允许去访问B服务(2.0版本),这样方式可以有效避免新旧版本不兼容的情况。

链路1:网关 -> A服务(1.0版本) -> B服务(1.0版本) 链路2:网关 -> A服务(2.0版本) -> B服务(2.0版本)

操作者给“链路1”分配一个 Http Header 值,给“链路2”分配另一个 Http Header 值,例如:Header 中 domain=green,选择执行“链路1”,domain=blue,选择执行“链路2”。假如“链路2”中任何一个服务出现问题,直接把 domain 切换到 www,实施流量回滚。

适用条件

  • 所有全链路服务必须前置 Solar 网关,即所有全链路服务的流量必须通过 Solar 网关进入
  • 所有全链路服务必须接入 Solar 框架
  • 未接入 Solar 框架的服务必须实施最后一次滚动发布,使之接入Solar 框架后具备全新的全链路灰度发布和蓝绿发布的能力
  • 业务服务如果存在静态 IP负载均衡,Solar 框架也兼容,但不会对它灰度发布和蓝绿发布

蓝绿发布流程

注意:我们实现了对灰度发布和蓝绿发布的糅合,下文提到的“蓝绿发布”有广义性,同时包含狭义的“蓝绿发布”和“灰度发布”的含义。

蓝绿成功的流程:

创建蓝绿计划(Plan) -> 蓝环境部署(Deploy) -> 执行蓝绿(Blue-Green) -> 蓝绿验证(Check) -> 下线绿环境(Offline) -> 完成蓝绿计划(Finish)

蓝绿失败的流程:

创建蓝绿计划(Plan) -> 蓝环境部署(Deploy) -> 执行蓝绿(Blue-Green) -> 蓝绿验证(Check) -> 蓝环境回滚(Rollback)

蓝绿发布前

创建蓝绿计划:

  • 用户在 CD 平台上创建蓝绿计划,他需要事先统筹确定,今天有多少个服务要发布新版本(本文假设需要发布A新服务和B新服务为例进行阐述),执行全链路版本条件驱动或者权重放量。
  • 根据蓝绿计划里的服务列表自动创建基准兜底的服务版本匹配策略(版本只取生产环境上运行的服务版本),保证流程只运行在绿环境里,规则推送给线上所有网关。
<rule>
<strategy>
    <version>{"solar-service-a":"1.0", "solar-service-b":"1.0"}</version>
</strategy>
</rule>

蓝绿发布中

部署蓝环境的全链路服务

A新服务和B新服务的机器通过 VI 启动点火成功并拉入流量(注册到注册中心)之后,进入蓝绿环节。

执行蓝绿

根据用户提交的蓝绿计划,CD 平台将自动创建蓝绿策略。注意:下文中提到的 XML 展现方式,用户是接触不到的,只是为了表达逻辑含义而已。

执行蓝绿条件驱动模式:

通过蓝绿发布计划的配置页面,配置服务版本号,路由链路,以及每条链路的路由条件,下面配置表示为 Http Header 中 domain 字段为 Green 时候走 route1 的链路,domain 字段为 Blue 时候流量走route2 的链路。Header 字段可自定义,对于同一网关和BI下不同业务系统的蓝绿发布和路由,可以通过 namespace 进行隔离,其作用是支持不同业务系统同时实施蓝绿发布方案。

<rule>
<strategy-customization>
    <conditions type="blue-green">
        <condition id="condition1" header="#H['domain'] == 'green'" version-id="route1"/>
        <condition id="condition2" header="#H['domain'] == 'blue'" version-id="route2"/>
    </conditions>
    <routes>
        <route id="route1" type="version">{"solar-service-a":"1.0", "solar-service-b":"1.0"}</route>
        <route id="route2" type="version">{"solar-service-a":"2.0", "solar-service-b":"2.0"}</route>
    </routes>
</strategy-customization>
</rule>

执行蓝绿权重放量模式:

通过蓝绿发布计划的配置页面,配置服务版本号,路由链路,以及每条链路所占的权重百分比,下面配置表示为 route1 的链路(Green 链路)所占的流量百分比为 5%,route2 的链路(Blue 链路)所占的流量百分比为 95%。相对于“蓝绿条件驱动模式”,“蓝绿权重放量模式”需要使用者分几次条件蓝绿权重,并进行多次观察,小心放量。

<rule>
<strategy-customization>
    <conditions type=“gray">
        <condition id="condition1" version-id="route1=95;route2=5"/>
    </conditions>
    <routes>
        <route id="route1" type="version">{"solar-service-a":"1.0", "solar-service-b":"1.0"}</route>
        <route id="route2" type="version">{"solar-service-a":"2.0", "solar-service-b":"2.0"}</route>
    </routes>
</strategy-customization>
</rule>

蓝绿验证

通过蓝绿验证的工具(例如:Skywalking 全链路调用链中验证),验证蓝环境是否有新流量接入,新流量是否会引起业务调用异常和错误。相对于“蓝绿条件驱动模式”,“蓝绿权重放量模式”需要使用者多次执行“全链路侦测”,观测权重百分比概率执行是否准确。

蓝绿发布后

蓝绿成功,执行如下步骤:

  • 下线绿环境。下线绿环境的所有服务
  • 完成蓝绿计划。清除蓝绿策略

蓝绿失败,执行如下流程:

蓝绿验证失败后,执行蓝环境回滚。当全链路中任何一个服务出现问题,就需要回滚。回滚方式,切回基准度低策略,默认指向绿环境。

<rule>
<strategy>
    <version>{"solar-service-a":"1.0", "solar-service-b":"1.0"}</version>
</strategy>
</rule>

回滚后,对于出问题的服务,进行问题排查,重新上线,再执行蓝绿发布计划。

蓝绿发布并行隔离

当同一网关下,不同系统同时并行执行蓝绿发布,为避免冲突(不同系统的全链路蓝绿发布中包含相同的服务,但指向不同的版本匹配),可以通过命名空间(namespace)进行隔离,namespace 通过 Http Header 传入,由 Spel 表达式进行命中,表达方式如下:

<rule>
<strategy-customization>
    <conditions type="blue-green">
        <condition id="condition1" header="#H['namespace'] == 'x-system' && #H['domain'] == 'green'" version-id="route1"/>
        <condition id="condition2" header="#H['namespace'] == 'y-system' && #H['domain'] == 'blue'" version-id="route2"/>
    </conditions>
    <routes>
        <route id="route1" type="version">{"solar-service-a":"1.0", "solar-service-b":"1.0"}</route>
        <route id="route2" type="version">{"solar-service-a":"2.0", "solar-service-b":"2.0"}</route>
    </routes>
</strategy-customization>
</rule>

注意:上述方式只适用于“蓝绿条件驱动模式”。

蓝绿的外界驱动和网关驱动

外界驱动

在全链路中,由外界传递蓝绿的 Header 标志值到网关上,来驱动全链路蓝绿发布,例如:上文提到的 namespace 和 domain的Header。外界一般包括界面端,手机端等元素。

网关驱动

在全链路中,外界不传递蓝绿的Header标志值,而是通过在策略中加入对应的 Header 值,并写入到网关上,来驱动全链路蓝绿发布。表达方式如下:

<rule>
<strategy-customization>
    <conditions type="blue-green">
        <condition id="condition1" header="#H['namespace'] == 'x-system' && #H['domain'] == 'green'" version-id="route1"/>
        <condition id="condition2" header="#H['namespace'] == 'y-system' && #H['domain'] == 'blue'" version-id="route2"/>
    </conditions>
    <routes>
        <route id="route1" type="version">{"solar-service-a":"1.0", "solar-service-b":"1.0"}</route>
        <route id="route2" type="version">{"solar-service-a":"2.0", "solar-service-b":"2.0"}</route>
    </routes>
    <headers>
        <header key="namespace" value="x-system"/>
        <header key="domain" value="green"/>
                </headers>
</strategy-customization>
</rule>

外界不需要做任何改动,根据蓝绿的 Header 匹配,确定走 route1 的路由路径。

注意:上述方式只适用于“蓝绿条件驱动模式”

蓝绿智能化实践

智能化,包括运维部署智能化和蓝绿驱动智能化。

  • 运维部署智能化:业务人员部署服务时候,不需要接触任何云环境,只需要几步界面点击即可完成。
  • 蓝绿驱动智能化:业务人员只需要按照既定的版本迭代规则,不需要接触复杂的蓝绿规则策略,只需要几步界面点击即可完成。

计划创建

我们可以通过创建一个发布计划,执行蓝绿发布。一个发布计划可以关联多个服务,即进行全链路的蓝绿发布。

计划审批

创建完的蓝绿发布计划会进入待审批状态,每个服务至少需要一个Owner 审批通过后才可进入发布配置。由于涉及到生产环境上的服务上下线,我们采用了非常严格的权限控制。

发布配置

审批通过后,进入发布配置页。

发布系统配置

该步骤为运维智能化发布步骤:

  • 选择应用参与蓝绿发布的版本信息
  • 选择应用参与蓝绿发布的 Group 信息(运维层面的分组信息)

完成后进入【堡垒发布】。

堡垒发布

堡垒机的作用是尝试全链路新版本流量的引流,具有流量堡垒、屏障和保护作用。一旦堡垒机流量出现问题,可以快速回滚。

堡垒机发布完成后,生成兜底规则,兜底规则的作用是确保新版本上线过程中,或者快速回滚过程中流量打回到老的稳定版本,下一步进入【蓝绿配置】。

蓝绿策略配置和执行

权重放量模式:

  • 蓝绿版本选择:所有应用的蓝版本和蓝条件必须配置
  • 蓝绿权重配置:根据案例输入蓝绿版本的权重百分比。权重百分比的设置过程,是需要人工观察和不断减少旧版本权重,增加新版本权重的过程

条件驱动模式:

  • 蓝绿版本选择:所有应用的蓝版本和蓝条件必须配置,绿版本和绿条件为可选
  • 蓝绿条件配置:根据案例输入蓝绿版本的表达式

表达式提供用户自主校验功能,可选择对应规则进行校验。表达式分为两种:

  • 普通模式,支持简单的 ==,!=, >,>=,<,<= 六种操作,并且通过 && 或者 || 串联起来

  • 高级模式,通过Spring Spel语句的编写,支持更多高级的科学计算和逻辑计算场景

校验通过后进入下一步 【开始验证】。

执行验证

蓝绿和兜底规则生效后,可以执行如下功能,进行准确性验证。

蓝绿全链路路由预检测功能,输入路由规则可以查看预检测结果。

路由策略预检测。在符合当前条件下,从网关派发到全链路服务的路由 Header Json 内容是否准确,是否符合预期。

路由路径预检测。在符合当前条件下,从网关到全链路服务进行智能化侦测,把途径的服务的版本等各类信息打印出来。

跳转定位到 Skywalking 观察全链路追踪的结果。

从 Skywalking 的 SOLAR Span 上,我们可以看到很多关键性的信息:

  • TraceId 和 SpanId 输出
  • AppId 和服务名输出
  • 所在服务的 IP 地址输出
  • 灰度版本,区域和子环境输出
  • 灰度版本路由规则输出
  • 调用链服务中的 RestController 的类名,方法名,入参,出参输出
  • 调用链服务中的任何代码未被捕获的异常的输出
  • 业务扩展接口自定义业务数据输出

通过对接 Skywalking 后台实现流量追踪。

通过掌门监控平台,对接钉钉机器人的通知机制,随时监控蓝绿规则和策略的变更。

执行回滚

  • 验证失败后,执行回滚。当全链路中任何一个服务出现问题,就需要回滚。回滚方式,即删除配置 strategy-customization 节点下的策略,保留 strategy 节点下的策略,默认将执行基准兜底的服务匹配策略。
  • Baking 阶段回滚后,对于出问题的服务,进行问题排查,重新上线,再执行发布计划。

执行全量发布

验证通过后,将执行全量发布,蓝绿发布流程结束。

后续展望

我们将不仅局限在 Spring Cloud 微服务侧的蓝绿发布,将持续推进前端、网关、Nginx 等端到端和各类技术栈的蓝绿发布,实现真正全链路的蓝绿发布,争取把广大业务部门的同学从熬夜的泥潭里早日解放出来,做到白天无损且安全的生产环境发布。

作者介绍:

  • 吴毅挺,掌门技术副总裁,负责技术中台和少儿技术团队。曾就职于百度、eBay、携程,曾任携程高级研发总监,负责从零打造携程私有云、容器云、桌面云和 PaaS 平台。
  • 任浩军,掌门基础架构部研发经理。曾就职于平安银行、万达、惠普,曾负责平安银行平台架构部 PaaS 平台基础服务框架研发。10多年开源经历,GitHub ID:@HaojunRen,Nepxion 开源社区创始人,Nacos Group Member,Spring Cloud Alibaba & Nacos & Sentinel & OpenTracing Committer。