掌门教育自 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。