点击上方“服务端思维”,选择“设为星标”
回复”669“获取独家整理的精选资料集
回复”加群“加入全国服务端高端社群「后端圈」
作者 | 乌拉
出品 | 爱番番技术
导读
随着虚拟化技术的成熟和分布式框架的普及,在容器技术、可持续交付、编排系统等开源社区的推动下,以及微服务等开发理念的带动下,应用上云已经是不可逆转的趋势。
微服务架构下服务数量爆炸式增长,对应的交付基建工作量暴增,且服务间拓扑复杂,又导致了升级影响难评估、问题定位困难、单独测试环境成本极高等问题给高效能交付带来了极大挑战。另一方面,云原生带来了标准化、松耦合、易观测、易扩展的特性,为交付基建与业务解耦、更灵活的环境管理和、无损发布带来新机遇。
爱番番产品从 20 年 4 月 全面云化,在云化时代,我们如何克服上述效能挑战,同时利用云原生的技术红利实现产品的高效能交付呢?
爱番番是典型的 toB 型业务,具有以下特点:
从产品形态上,产品战线长,涵盖 ( 拓、聊、追、洞察 ) 等核心产品能力。
从市场环境上,市场环境环境竞争异常激烈,对产研的效率与质量提出更高的要求。
从研发模式上,产品与研发采用敏捷思维研发,需要不断的创新与试错,快速完成 PoC及 MVP 产品的研发上线。
从部署形态上,除了提供 SaaS 服务外,同时具有多样化售卖的诉求。
团队以业务领域划分的多个 scrumTeam,如下图:
团队持续交付面临的挑战:
2. 云原生架构下的持续交付实践
为实现团队高效的价值交付,我们从敏捷机制改进和全流程持续交付能力提升两方面开展了建设:
流程机制层面: 用户价值,流动效率提升为核心的敏捷体系建设,包含以下几个方面:
敏捷迭代机制:以用户价值流动效率为核心理念,保障团队目标一致,信息透明。
需求拆分管理:标准化、可视化、自动化的管理机制,在成本可控的前提下达成小批量需求加速流动,快速验证价值。
分支模式和环境管理:基于云原生强大的流量管控能力,实现基于 istio 的全链路灰度环境能力,实现简洁、灵活、低风险的分支模式。
全流程的数据度量体系:通过目标指标度量了解现状,过程指标度量挖掘问题,问题自动创建任务,协同 peer 推动问题闭环。
技术层面:全流程环节自动化智能化提升,包含以下几个方面:
基础设施:建设与业务解耦的基础设施服务,解决服务爆炸带来的成本问题。
自动化:微服务下合理分层自动化体系,可控投入下保障有效质量召回,解决复杂拓扑带来的回归漏测问题。
发布能力:一键操作高效执行、过程可视、可感知、可控的极致发布体验,解决高频发布需求下的发布成本问题。
工具赋能:丰富的工具能力赋能研发测试各效能痛点环节,为人员赋能(建设中,本文暂不详细介绍)。
下面主要从技术层面的 3个 方向逐一进行方案说明。
什么是与业务解耦的基础设施?
这里的与业务解耦其实是借鉴了serverless 的思路,是指把基础设施服务化,独立运维。以前,我们的业务团队研发和 QA,除了需要进行业务的开发和测试工作之外,有大量的时间都花费在了新应用、日志、配置的接入以及环境、流水线、监控维护等等和核心业务无关的事项上,就像下面这个图的左边,而且,任意基础设施服务要升级,比如日志平台 SDK 升级、流水线需要统一增加一项安全检测环节等等,都需要各个业务团队配合升级,落地推广困难。如果我们把这些基建内容通过服务化的形式提供给业务团队使用,就能让业务研发和 QA 聚焦于业务的关键事项,从而大幅度提升团队效能。就像下面的右边这个图。同时基础设施的升级业务无感知,再也不会有基础设施能力落地推广困难的问题。
上文已经提到,基础设施面临的最大问题是,由于爆炸的服务个数带来的暴增的 Devops 基础设施接入和维护成本问题。如果能打造服务化的基础设施,就可以实现基础设施的 0 成本接入和运维。那么如何打造与业务解耦,服务化的基础设施呢?
与业务解耦的第一步是基础设施的标准化,只有标准化的过程才有可能规模化,从而实现技术设施服务化。我们主要针对以下几部分内容进行了标准化改造:
模块标准化:代码结构、打包流程、标准容器、镜像管理、部署过程。
标准流水线
标准的基础服务:APM组件、配置中心、发布平台、资源管理。
研发模式:
与业务解耦的第二步,是基于标准化的基础上,建立声明式的基础设施能力。这里的声明式是指给业务团队声明式的基础设施体验。业务团队只需要在标准配置中声明一些基础属性,即可自动完成所有基础设施的接入,且后续维护上业务 0 成本。主要分为两个环节的建设:
接入时:分钟级的一键接入
我们的做法是通过脚手架为抓手来构建基础设施的一键接入能力。如下图所示:
脚手架:自动生成框架代码,包含基础 apm 组件、api 管理平台等的接入。
configMap:自动生成应用标准配置并基于配置新增/变更主动触发接入服务。
接入服务:拉取 configMap 配置并解析,根据配置内容调度不同的基础设施服务完成接入初始化。
脚手架是我们这边新模块创建的入口。所有新代码库都是通过脚手架创建,他会帮助开发自动生成一整套集成了标准组件的代码框架。
在脚手架创建新模块的时候,根据业务声明的模块属性,如是否接入 apm、模块代码类型、模块服务类型等等自动完流水线创建、基础组件接入、集群环境申请、配置文件生成等操作。一个新的服务,从创建代码库到服务全套基础设施接入完成,服务可直接部署到测试集群的时间< 10 分钟。
运行时:根据服务声明内容动态运行,实现业务升级维护0成本
基础组件部分,因为都是以 sidecar 模式提供服务,所以运行时天然与业务解耦,因此重点在于如何实现流水线在运行时与业务解耦。我们针对流水线进行了模板化、参数化改造,并和业务的声明属性结合。就像下面这张图,流水线每次都是动态运行的,运行的内容是依赖左侧 5部分声明数据实时生成,包括 cicd 通用配置、流水线模板、任务脚本、任务策略、业务声明属性。除了业务自己的声明文件,其余部分都是基础设施组独立运维,故对应任务优化、添加、统一配置修改等均对业务透明。如下图,如果要针对流水线上的某个环节进行优化,或者增加一些环节,仅需基础设施组修改流水线模板或者任务脚本即可。
与业务解耦的第三步,通过智能化的策略能力,实现高稳定的基础设施服务。
服务化之后,基础设施作为独立运维的服务,所有的问题都需要设施团队独立维护排查,所以与业务解耦的第三步就是建立高稳定高效低运维成本的基础设施能力。我们的思路是通过智能化的策略,来保障高效和稳定。在流水线运行的前中后通过策略给流水线增加一个”监工”,模拟人工判断任务是否应该执行,模拟人工分析跟进、修复问题等。
分析常见的流水线稳定和效率问题比如环境不稳定、底层资源不稳定、网络异常等等,大体可分为 偶发问题重试可恢复、问题相对复杂需人工排查、阻塞问题需人工修复三类。而效率方面大量重复、无效任务比如只加了个 log 也要跑全套测试流程,导致了资源浪费,也导致了执行效率低下。如下图左侧所示:
针对这些场景,我们在流水线运行前后都添加了可配置的策略判断过程,判断任务是否需要跳过、排队、重试等等,从而提升稳定性和效率。
典型场景:
自动红灯分析:任务失败后可自动根据日志错误码分析问题原因并给出标注,方面后续根据统计数据更有效的优化。
排队策略:在自动化等任务执行之前,自动检测依赖环境是否正常,从而降低运行失败导致的红灯。
成本:模版创建&维护流水线 1000+,降低创建和维护成本 90%。
稳定:流水线整体稳定性从 85% 提升到 95%, 工具链稳定性从 95% 提升到 99%。
效率:代码提交到部署完成 80 分位时间从 30+ 分钟降低到 10 分钟。
解决了服务暴增的问题,下面我们来看复杂拓扑下的回归漏测问题。通常情况下解决回归的质量和效率问题,都会想到自动化测试。但是云原生微服务架构下,什么样的分层自动化体系,可以既保障召回,又不引入过多的自动化建设和维护成本呢?和传统 3 层金字塔自动化不一样,云原生架构下的自动化,由于服务内部相对简单,而服务拓扑复杂,所以测试的重点是在系统端到端测试,实际的分层测试的比重更像一个倒过来的金字塔。
而由于端到端成本过高,考虑到投入产出比,爱番番的分层自动化是按照右下角这个结构来建设的,其中接口 DIFF 测试、契约测试、纯前端 DIFF 测试是无人工介入,最核心的三个部分。下面会就接口 DIFF 自动化测试和契约测试方案进行说明。
我们接口的 DIFF 测试是基于强大的全链路灰度环境能力来建设的,这是云原生架构给我们带来的红利。先介绍下我们的全链路灰度方案。
我们是基于 istio 的灵活的路由能力,通过同构底层「分组多维路由」的架构设计, 自研 CRD Operator 构建爱番番的「全链路灰度发布」平台。该方案支持了我们的线下多路复用环境、线上安全的容量评估以及金丝雀发布等多个场景。
测试环境多路复用是指,使用有限的资源,在一套基础环境上逻辑隔离出多套环境,支持并行开发、联调的需求。
如下图所示,不同的分支对应着不同的 feature,通过流量染色 + 流量规则路由的方式,使得不同分支拥有逻辑上隔离的环境,支持并行开发。在前端给流量打上橘色标记之后,全链路的请求会走橘色的链路进行访问。
有了如上所述的多套逻辑隔离的测试环境之后,每当有新的分支环境拉出并有代码更新时,即可通过将流量在 base 环境( 部署最后一次上线的代码 )和新分支环境进行回放,并对比两者的返回是否存在差异来进行回归测试。我们的 diff 方案如下:
该方案具备如下几个优点:
基于流量回放的接口 diff,最大限度的覆盖线上用户真实场景。
全流程自动化,无人工参与。
配置化的流量筛选策略和 diff 策略接入,便于扩展优化。
分布式任务运行,支持大批量并发。
微服务的架构,服务之间依赖复杂,而且通常每个服务都是独立的团队维护,服务和服务之间,前后端之间大多通过 API 调用。那么这种情况下可能就会出现如下场景:A 团队开发的 API 同时服务于 B\C 团队。最开始测试的时候都是通过的。但是后续迭代中,B 团队对字段 A 有一些调整的需求,A 团队根据需求改了,也测试通过了,但是上线后发现 C 团队功能异常了。
以上问题的本质原因为:
服务提供方服务的消费者越来越多的情况下,服务的变更影响难以评估,服务的变更也不能及时同步到所有消费者,所以往往是消费方发现问题了反馈,导致损失。为了避免上述问题,我们引入了契约测试。
契约测试的核心思路是通过消费者驱动的方式,建立服务端和各个消费端之前的契约,在服务端有修改之后,通过测试和所有消费方之前的契约是否被毁坏来保障服务升级的安全性。同时,契约也可以作为双方测试解耦的手段。通过契约测试,团队能以一种离线的方式 ( 不需要消费者、提供者同时在线 ),通过契约作为中间的标准,验证提供者提供的内容是否满足消费者的期望。
常见的契约测试方案有真正实践消费者驱动的如 pact,契约由消费端生成并维护,提供方代码更新之后,拉取所有消费方契约进行测试,即解决了集成测试解耦问题,又保障了服务方能满足所有消费方需求。( 下左图 )
也有非消费者驱动,提供方生产契约,并提供 mock 服务,消费方可以基于契约文件测试,如Spring Cloud Contract。只能解决集成测试解耦的问题。( 下右图 )
爱番番的方案则是取了折中。一方面由于团队习惯,契约一直是服务提供方给出,另一方面又希望保留消费者驱动特性,从而保障服务方能满足所有消费方需求。我们选择了在提供方生成契约,但是通过线上日志和调用链解析的方式来补充模拟消费端契约case。且整个过程全自动化。
自动化虽然是效能提升的好手段,但是长期以来,自动化的稳定性问题、问题跟进排查成本的居高不下都是阻止大家开展自动化建设或者自动化建设半途而废的重要原因。针对自动化的稳定性提升和跟进成本降低,我们建设了 case 失败自动定位和修复能力,让智能化的小助手帮助大家轻轻松松维护 case 运行。下面是我们自动定位的一个效果实例:
我们会在自动化 case 运行失败后,调用自动定位服务,自动对失败的 case 进行标注,根据标注结果会对失败 case 进行分类处理。
比如,环境问题会自动重试,批量未知会发送到自动化小组进行排查,元素找不到会发送到业务 QA 排查。
以下是实现的方案。包含基础定位能力和基础数据获取。在这些基础能力之上,建设了配置层,实现配置解析和调度能力,让我们可以通过配置的方式,灵活组合不同的定位策略快速支持不同场景的问题定位。
不同类型模块对接了不同的发布平台和流程,统一发布困难,底层发布方式的变更需要各模块升级,迁移成本高。
由于模块众多且复杂拓扑,而且模块间上线有依赖关系,每次上线 100+ 模块,人工控制流程,风险高而且效率低。上线过程的的记录和分析人耗也很高。
整体上线过程不可见,风险感知滞后。
如何解决以上问题?
首先是基于云原生构建多平台统一的部署与发布引擎,无缝集成 CICD,实现发布过程的高度标准化,同时支持多种发布策略。如下图:
通过 CD 发布平台的统一,实现各类型模块统一发布,且底层部署迁移业务无感知。
有了统一的发布平台之后,为了解决上线过程复杂低效的问题,我们希望实现完全自动化的发布过程。
分析发布前后需要进行的事项,如下图所示。基于这些事项,梳理了要自动完成整个发布过程需要收集的数据,如右图所示,包含发布模块封板信息、依赖信息、配置信息等等。基于这些数据,根据固定的编排逻辑,自动生成服务发布拓扑以及本次上线步骤。生成的上线拓扑和步骤信息经人工确认之后,自动调用对应上线发布服务进行发布,并针对发布过程数据自动统计,生成发布过程总结。
发布过程可视:服务粒度的依赖拓扑已经实时上线进度展现、过程可视可感知。
金丝雀发布策略:发布无损、风险及时感知并召回。
迭代 story 量增长 85.8%,发布周期稳定,研发测试周期下降 30%,千行 bug 率从 1.5 降低到 0.5。
Local 工具箱赋能开发效能,通过 IDE 本地插件工具,赋能开发编码测试过程,提升研发环节效能。
智能风险识别,通过白盒能力,构建质量风险识别体系,应用于准入、准出、灰度等场景。
乌拉,在百度爱番番主要负责团队持续交付建设。
— 本文结束 —
● 漫谈设计模式在 Spring 框架中的良好实践
● 颠覆微服务认知:深入思考微服务的七个主流观点
● 人人都是 API 设计者
● 一文讲透微服务下如何保证事务的一致性
● 要黑盒测试微服务内部服务间调用,我该如何实现?
关注我,回复 「加群」 加入各种主题讨论群。
对「服务端思维」有期待,请在文末点个在看
喜欢这篇文章,欢迎转发、分享朋友圈
在看点这里