作者 | 张洪箫(花名:伏见)阿里巴巴新零售高级技术专家
来源|阿里巴巴云原生公众号
前言
考拉海购的整个云化改造是从 2019 年 10 月份开始的,当时的唯一目标就是短时间内快速完成迁移。在不到 4 个月的时间里,考拉团队唯一考虑的是如何以最快的速度完成使命,云原生是我们选择的最合适的一条路。
实践历程
本篇主要从第三阶段的云产品接入和第四阶段运研模式的升级来谈谈考拉海购的实践过程。
云产品接入
1. 云原生产品定义
云原生本质上是一套技术体系和方法论。随着容器技术、可持续交付、编排系统等技术的发展,同时在开源社区、分布式微服务等理念的带动下,应用上云已经是不可逆转的趋势。真正的云化不仅仅是基础设施和平台的变化,应用本身也需要做出改变。在架构设计、开发方式、应用运维等各个阶段基于云的特点,面向开源和标准化,建设全新的云化的应用,即云原生应用。
云原生技术有利于各组织在公有云、私有云和混合云等新型动态环境中,构建和运行可弹性扩展的应用。根据 CNCF 的定义,云原生的代表技术包括容器、服务网格、微服务、不可变基础设施和声明式 API。阿里云提供了消息队列产品,如消息队列 RocketMQ 版、消息队列 Kafka 版等,应用实时监控服务 ARMS,微服务引擎 MSE,应用高可用服务 AHAS,性能测试 PTS,函数计算 FC 等中间件云原生产品,为考拉海购从传统应用向云原生应用演进,打下了坚实的基础。
2. 心路历程
我们在云产品的接入过程中, 大致在心态上经历了三个阶段。
1)第一阶段:很好、很强大,接入效率杠杠的
这部分主要是在 2019 年 10 月 - 2020 年 3 月之前,那时候接入的都是数据库、Redis,以及 ASI 这种产品,相对用户比较多,整体比较稳定,与开源产品基本上完全兼容,迁移工具及周边建设都比较完善,所以迁移起来非常平稳,基本上改动一部分点就可以了。
2)第二阶段:云产品真丰富,要啥都有
以前很多组件还是我们自己维护的,但是随着连接实例的增加,读写的次数多了,时不时出现宕机。那时候听说微服务引擎 MSE 很好用,它提供一站式微服务能力加持,包括微服务依赖组件托管、无侵入的微服务治理,更快捷、稳定、低成本的运行微服务。我们找了下 MSE 的兄弟,他们拍着胸口说没问题,产品运行之后真的就没出现过那些问题了。
像这样的例子还很多,那时候的感受是,只有真正体系化地去使用云原生产品,你才会对云原生的价值有更深刻的感受。
3)第三阶段:磨合适应
随着考拉海购开始接入集团的业务平台,供应链也开始和集团进行融合,我们也进一步开展云化的历程。过程中也有挑战,不过在克服重重困难后,我们如期完成了各项的改造,并且非常平稳的度过了几次大促,云原生产品非常好地支撑了考拉海购业务的增长。
3. 接入的过程
1)接入策略
由于云产品和考拉海购自建的产品有一定的能力差异,所以我们建立了一整套产品评估和接入试验田机制来保证整个接入的有序及功能的可迁移性,正是这套机制的良好运行,我们整个的稳定性得到了保障,在整个基础大变动中都没有出现大的故障。
我们的整个保障流程如下图:
2)权限方案
接入云产品面临的第一个问题是,云账号,云产品资源权限怎么管理?阿里云本身提供了 RAM 产品,作为管理用户身份与资源访问权限的服务。那么 RAM 账号如何何员工身份关联?
- 是为每个产品申请一个子账号,所用人共用该子账号?
- 还是为每个人申请一个 RAM 子账号,单独为每个人管理资源权限?
- 或者为应用申请一个子账号,通过员工的应用权限来和子账号的资源权限做关联?
考拉海购有几百人,方案2和3都面临着很高的子账号生命周期以及资源权限的管理成本,所以我们初期在使用这些中间件云产品时,出于简单考虑,都采用了第一个方案——申请一个子账号,开发一起用。
其带来的问题就是资源权限粒度太粗,比如使用任务调度(SchedulerX) , 登录到控制台就可以操作所有应用的所有任务,这对于安全生产来说,本身就是一件很危险的事情。所以为了应用安全,我们向中间件云产品提的第一个需求,基于 RAM 提供按应用粒度做资源授权的能力。
考拉海购用户在登录云控制台时,感知不到 RAM 账号。在基于 RAM 云产品 STS(Security Token Service) 的能力,封装了一层简单的云控制台跳转临时授权,在生成 STS Token 时,根据 BUC 获取当前用户,并生成和指定一个额外的权限策略,限制该用户操作云资源(应用)的权限。登录页面如下图:
SchedulerX 也基于 STS 的能力,通过 RoleSessionName 来和员工身份关联,完成权限管理操作。当然,这个只是暂时的方案,能帮考拉海购解决一部分问题,最终的解决方案还是要靠全局来解,这部分以后我们再谈。
3)消息方案
迁移目标:
考拉海购消息体系基于消息队列 Kafka、消息队列 RabbitMQ,在其上自研了事务消息中心和延迟消息产品满足业务丰富的消息需求。经过调用云上消息队列 RocketMQ 产品,发现其能完美的兼容、支持考拉海购现有的完整的消息体系,能够提供足够的性能保障、稳定行保障,并且额外提供支持了消息轨迹和消息查询的功能,对业务使用上更加友好。
实施过程:
整体迁移涉及考拉海购上百工程,无法进行统一时间上的安排改造,所以针对考拉海购的场景,制定了横跨数月的迁移方案。并研发 SDK,实现了消息双写、topic 映射,支持压测消息等多项考拉海购特有的功能场景。让业务同学无需投入大量人力。升级 SDK 增加几行配置就可以实现消息的双写。
- 阶段一:所有业务进行消息双写改造。
- 阶段二:所有业务进行消息双读改造。
- 阶段三:进行消息总体收尾阶段,业务方切换成单独单写状态,至此完全剥离考拉海购原有的消息体系。
4)RPC 方案
RPC 主要涉及 RPC 框架以及服务注册中心。考拉海购使用 RPC 框架 Dubbok (Dubbo 内部分支)+ Nvwa (考拉自研注册中心),而集团使用 HSF + ConfigServer 。
由于前期业务有和集团微服务互通的需求,基于 HSF 本身兼容 Dubbo 协议,阿里云 EDAS 团队为我们提供了 Dubbo ConfigServer 注册中心的扩展,考拉应用在引入该扩展包之后,注册 CS 以及从 CS 订阅, 可以非常方便快捷地和集团 HSF 应用相互调用。
紧接着,我们开始使用 Dubbo3.0,基于 Dubbo 内核重构 HSF3.0,升级之后,原考拉 Dubbo 应用具备 HSF 的全部特性,可以和集团服务无缝互通。但是作为一个新的 SDK,在功能以及性能上必然面临着很大的挑战。我们前期在考拉海购场景下,引入该 SDK 进行了长达一个月的功能测试,解决了近 40 个功能问题。同时也在压测时,针对性能问题,解决了调用延时、注册中心推送及缓存的问题。同时考拉海购 Dubbo 注册中心扩展等也要去支持 Dubbo3.0,最终经历了双十一大规模验证。
同时我们采用双注册、双订阅的模式,也为未来考拉海购自研注册中心的迁移下线打下基础。待所用应用升级之后,就可以修改为只连 CS 的连接串,然后下线 Nvwa。同时,考拉海购也迁移到云原生产品微服务引擎 MSE 上,特别感谢阿里云 MSE 团队为对齐原考拉治理平台 Dubbo 相关功能作出的支持。
5)SchedulerX 方案
挑战:
云上 ScheduleX 定时任务瓶体和考拉海购的 kschedule 定时任务平台,通过调研比较,发现 ScheduleX 可以说是 kschedule 的架构升级版,除了满足基础的定时调度,分片调度之外,还支持了更大规模的任务调度。对于整体迁移来说,最大的难点在于如何迁移同步考拉海购 13000+ 的定时任务,期间每一个任务都需要在代码中进行手动改造,在平台上进行配置。人力消耗巨大。
迁移方案:
- 自研同步工具进行 13000+ 定时任务同步以及报警信息同步,解决了业务同学海量的人肉操作。
- 自研考拉海购云原生管控平台进行定时任务权限信息同步,保障数据迁移后的安全性。
6)环境隔离方案
微服务场景下,环境治理是一个比较大的问题,环境隔离本质上是为了最大化利用测试环境的资源,提升需求测试的效率。考拉原来基于 Dubbo 的路由策略,开发了一套环境路由逻辑。思想是基于主干环境加项目环境的策略,只需要部署需求涉及变更的应用,流量通过携带项目标签,优先路由到项目环境,如果没有部署,则复用主干环境的服务和资源。因此主干环境的稳定以及项目环境的路由是测试环境治理的重中之重。
迁移到阿里云之后,阿里云其实有一套类似的方案,基于 SCM 路由,达到同样的效果,如下图所示:
但是功能上 SCM 不支持考拉海购的 RPC 框架 Dubbok 以及消息框架 ,不过得益于 ARMS 优秀的插件包机制,我们将 HSF 的 scm 插件通过代码增强的方式打包成插件,移植到了 Dubbok 上,具备了 Aone SCM 方案的能力。通过 JVM 参数和发布平台结合,在前期充分测试以及和 QA 开发同步的基础上,我们在一周之内切换到集团的 SCM 方案上。后续考拉海购基本以主干环境+项目环境的方式进行需求迭代开发。
7)高可用组件方案
AHAS 限流:
对于限流来说有三个关键点:一是接入,需要在应用代码或者基础组件中埋点,从而能够收集 metrics 以及进行相应限流操作;二是限流能力,规则配置与下发;三是监控与报警。
AHAS 和考拉海购原限流组件(NFC) 面向用户使用层面基本一致,提供注解、API 显示调用、Dubbo filter、http filter 等方式,在迁移时仅需要替换对应的 API 即可,由于组件 API 相对简单,因此接入成本还是比较低的。同时 AHAS 也提供了 JavaAgent 接入能力,不需修改代码即可接入。
在能力方面,AHAS 比原考拉的的组件更加完善,提供了基于系统负载的保护以及熔断降级。原本有个需求是集群限流的功能,AHAS 团队很给力,在 618 之前上线了该功能让我们用了起来。在监控报警方面提供了实时的秒级监控,TopN 接口展示等功能,很完善。也有流控自动触发报警,通过钉钉的方式。
AHAS 故障演练:
考拉海购应用部署在 ASI,Ahas-Chaos 通过 K8s 对外提供的 Operator 能力,在业务无感的情况完成了接入,并顺利的参与到了集团 527 联合演练当中。
8)压测链路改造方案
考拉原本已经有了一套全链路压测的影子方案。其核心主要分为两个部分:
- 全链路压测标透传
- 流量拦截以实现影子路由、服务 Mock 等
迁移第一步是要先接入应用实时监控服务 ARMS;迁移第二步则是接入性能测试 PTS,支持 ARMS 和考拉组件,接管考拉原有的影子路由逻辑。
ARMS 和 PTS 本身都是使用 JavaAgent 的方式,通过字节码增强来完成对各个基础组件的埋点,这种操作的好处是接入成本低,业务感知小。最终我们顺利完成了全链路压测的改造。
9)同城双活方案
考拉海购在迁移到集团机房后,一段时间内还存在自建、云产品和集团组件三者共存的情况,基于现状,我们设计了一套自有的双活及 SPE 方案。
线上正常状态:
基于 DNS 和 Vipserver 的同机房优先,既能支持日常的流量随机,也能支持单机房流量隔离。
单机房压测下状态:
基础设施即代码 (IaC)
1. 什么是 IaC
Infrastructure as Code ——基础设施即代码,是一种使用新的技术来构建和管理动态基础设施的方式。它把基础设施、工具和服务以及对基础设施的管理本身作为一个软件系统,采纳软件工程实践以结构化的安全的方式来管理对系统的变更。
我的理解就是,通过将软件的运行环境、软件的依赖,及软件的代码进行一致化的管理(变更,版本等),并提供类似 BaaS 化的解耦方式,使得软件不被某个特定环境绑定,可以在任意环境快速复制运行。
2. 实践内容
1)构建部署体系
我们在考拉原有的应用 DevOps 体系之上,结合 IaC & GitOps 理念,对应用的构建、部署、配置加载、日常运维等方面基于 AppStack & IaC 做了改造,相关的构建、部署、应用静态配置全部迁移到应用 git 源码中。借助于 git 对应用所有相关配置进行托管,配置的版本迭代相对于之前的模式更加的清晰,同时也能很有效的保证应用源码、构建配置、容器配置、静态配置的版本一致性。
2)轻量化容器
以本次云原生改造为契机,我们将考拉原有的容器镜像体系与集团标准进行了对标改造,比较大的变化就是将原有的启动用户从 AppOps 修改为了 admin。
另一方面,我们引入了轻量化容器。作为云原生的基础之一,容器层的隔离能力是一大卖点。考拉海购整体进行了切换,完成了轻量化容器的改造,整体将 pod 分成了应用容器、运维容器,以及自定义容器几类,整个部署变得更加的轻量级,也更加易于掌控。
改造后的部署形态见下图。
3)CPU-share
上图的模式是 CPU-set,即容器会绑定一部分 CPU,运行时也只会使用绑定的 CPU,这种方式在正常的宿主机上运行的效率是最高的,因为减少了 CPU 的切换。考拉海购的部署全部切换到了 CPU-share 模式,即在同一个 NUMA chip 下,该容器可以使用该 chip 下所有的 CPU( CPU 时间片总数不会超过 limit 配置),这样只要该 chip 下有空闲的 CPU,就会使抢占不会太激烈,能大大提高运行的稳定性。
最终在大促峰值压测的验证中,神龙机的 CPU 在 55% 以下都能保持一个比较稳定的运行状态,进而保证了整体服务的稳定性,资源也得到了更充分的利用。
4)镜像配置分离
镜像配置分离指的是将应用的容器镜像和应用依赖的配置(静态配置、发布配置)隔离开独立存放。这样做的目的是能够最大程度地复用应用镜像,减少应用镜像的构建次数提高构建部署效率;同时,迁移到 AppStack 后应用代码回滚时也会自动回滚静态配置,不需要业务手动去静态配置中心回滚静态配置,极大降低了业务回滚的风险。
另外当镜像和配置分离后,镜像可以在任何环境进行部署,而不必依赖对应环境的配置。这样的话,我们发布流程就可以从面向变更,调整为面向制品,上线的即是测试的镜像。
3. 实施策略
1)自动化
IaC 迁移中任务较重的是配置迁移,环境迁移及整体标准化,提高迁移效率将极大加快 IaC 迁移的速度,也会给业务开发迁移过程中的心态带来积极影响。
- 构建发布配置存放在考拉旧有的部署平台上,静态配置存放在自研的配置中心上。旧有部署平台首先打通考拉的配置中心和集团 gitlab 代码仓库,再根据标准化的 service.cue 模板自动将旧有的部署中心和配置中心的各类配置直接创建到业务的代码中,自动完成 IaC 配置迁移工作,大大节约了业务迁移时间提高了迁移效率。
- 我们沉淀出了一套云原生环境的 API,具备了云原生环境以及云原生流水线的自动化创建、修改以及删除能力,也提高了业务接入效率。
IaC 自动化迁移功能上线后,平均每个应用大约只需要 1 分钟的时间就可以完成各类配置的迁移、云原生环境、云原生流水线的创建,全程无需业务接入。在完成上述的配置映射及重建后,应用只需要简单的进行构建发布,然后解决部分由于兼容问题导致的启动不正常,即完成了 IaC 的迁移,整体成本比较低。
2)接入支持
IaC 的接入不同于中间件的升级,涉及到应用的整个发布、部署体系的变化,并且当前阶段 AppStack 的稳定性不算特别高,所以我们采取的接入策略是项目室封闭接入,全程提供技术支持,保证业务能够第一时间解决问题,提高业务参与度和幸福感,也能在第一时间收集问题,助力我们优化接入流程,比如前期业务需要手动创建流水线,到后面我们通过 API 自动给需要迁移的业务创建对应的流水线。
而业务迁移 IaC 的实现又有两个阶段,两个阶段我们采用了不同的接入模式,通过在不同的阶段,采用不同的支持方式,达到业务稳定快速接入的目标。
双十一之前:
- 项目组出一人常驻项目室支持
- 每周一到周五,都有不同部门的开发到会议室专注迁移
- 每天上午培训相关知识,下午、晚上进行应用切换
双十一之后:
- 项目组出三人常驻项目室支持
- 每周只迁移固定的部门,由部门派出固定的人完成该周的全部迁移工作
- 培训放在每周一上午
两者的差异主要是前期平台的稳定程度,及业务研发的熟悉度比较低,所以接入相对比较谨慎,更多的是以一种验证,及推广的心态来,后续相对稳定之后,整体就是以平推的模式来进行接入。
成果
1. 无重大故障发生
考拉海购的云原生改造周期很长,不管是 618 和 双11 这样的大促,或是每月的会员日等普通大促,在项目组成员的通力协作下,没有因为云原生改造引起的重大故障发生。
2. 融合成绩喜人
- 解决考拉海购和集团应用部署的差异,完全兼容当前集团的模式,在部署层面与集团技术体系完成对齐。
- 解决考拉海购内部调用和集团调用的差异。
- 完成 SPE 和双活建设,容灾体系进一步和集团对齐。
3. 效能提升、成本节约
- 迁移有状态容器,每批次部署减少 100 秒,解决 IP 变更导致的启动失败问题。
- 配置和代码做到了强绑定,后续回滚的时候再也不需要关系静态配置的回滚。
- 从日常容量到大促容量从各个应用分别扩容,到 0.5 人日完成全站扩容到基准水位。
- 服务器数量减少 250 台。
4. 完善云产品功能
- 推动解决云产品易用性、稳定性问题,丰富云上中间件产品的场景丰富度。
- 推动云原生过程中的安全生产、账号等问题的解决。
未来,Mesh 是发力方向之一
技术下沉是互联网发展的大趋势。在微服务时代,Service Mesh 应运而生。虽然引入 Mesh 代理,会带来一定性能损耗和资源开销,以及 Mesh 服务实例的运维和管理成本。但是其屏蔽了分布式系统的诸多复杂性,让开发者可以回归业务,聚焦真正的价值:
- 专注业务逻辑,通过 Mesh 屏蔽分布式系统通信的复杂性(负载均衡、服务发现、认证授权、监控追踪、流量控制等)。
- 语言无关,服务可以用任何语言编写。
- 解耦基础设施,对应用透明,Mesh 组件可以单独升级,基础设施可以更快的升级迭代。
考拉海购这一年来一直在坚定的进行云原生化改造,虽然过程中碰到了非常多的挑战,但是我们从未怀疑过这一方向的正确性,并在每一次解决问题之后收获到了更多的业务价值。今年 双11,整个云原生升级帮助考拉减少了 250 台服务器,并沉淀出一套完整的 IaaS + PaaS 上云落地实践方案。考拉在云上的研发效率也有了大幅提升,例如使用阿里云直播中心服务,考拉快速完成了海外直播服务从 0 到 1 的搭建。此外,“爬树 TV”、“Like 社区”等新功能也相继上线。
随着云原生改造的持续发展,云原生带来的红利也越来越显著。我相信当业务跟基础设施进一步解耦,有一天会实现业务与基础设施无关,业务研发只需要关心自己的业务,再也不用为运行环境而苦恼,进而在运研效率上获得巨大的提升。
作者简介
张洪箫(花名:伏见)阿里巴巴新零售高级技术专家,拥有 10 年开发测试运维经验,在基础架构和研发效能领域有非常丰富的经验,积极的拥抱云原生,推崇持续、快速、高质量的软件交付方式。
想了解考拉 双11 同款开源 & 云产品,欢迎参与 1 月 30 日 Spring Cloud Alibaba Meetup 广州站,了解完美日记、虎牙是如何使用 SCA 全家桶赋能业务,落地微服务。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。