波司登云原生微服务治理探索
作者:曾孟琪(山猎)
背景
波司登创始于1976年,专注于羽绒服的研发、设计、制作,是全球知名的羽绒服生产商。波司登用一系列世人瞩目的辉煌成绩证明了自己的实力:连续26年全国销量领先,连续22年代表中国向世界发布防寒服流行趋势,产品畅销美国、法国、意大利等72个国家,全球超过2亿用户。作为羽绒服革命的旗手,波司登引领了行业内的“三次革命”。
在产品力和销售成绩单背后,波司登在生产、仓储、物流、销售各环节已完成数字化转型和创新改造。除生产端的智能生产工厂,波司登对仓储和物流环节也进行智能化改造,提升小单快反、拉式补货的比重,最大限度减少困扰服装企业多时的“库存”问题;为了精准分发销售端产品,波司登建立数据中台,打通全渠道数据,赋能消费者研究、商品企划、渠道匹配等。现在,波司登每件羽绒服从生产到抵达消费者,背后都是一段数字之旅。
云原生技术发展
随着波司登数字业务的飞速发展,背后的 IT 技术也在不断更新迭代。波司登极为重视客户对服务的体验,并将系统稳定性、业务功能的迭代效率、问题的快速定位和解决视为构建核心竞争力的基石。服饰行业会积极参与各大电商平台的促销活动,业务流量的波峰波谷现象明显,如果由于资源分配不合理导致高峰时期订单溢出、运力不足,会极大影响顾客和商家的体验。此外,波司登自研了用户运营平台(用户洞察系统、内容管理系统、用户管理 CRM 系统及用户小程序)、零售运营平台(线上平台订单管理 OMS 系统、线下渠道管理系统、门店收银 POS 系统)、商品运营平台(订单处理中心 OPC、库存计算中心 ICC、商品订货系统、商品运营 iMOS 系统、采购制造 GiMS 系统、物流管理 EWM 系统、机器人调度 WCS 系统) 等诸多垂直业务功能,在市场需求的快速变化下,产品功能创新和迭代效率问题也是对技术架构的一大挑战。这些现状的解法和云原生架构带来的核心能力不谋而合,在波司登系统改造上云的过程中,CIO 戴建国亲自带队,围绕着云原生技术体系,推动波司登的各条业务线进行技术升级改造,加快数智化发展进程。在技术选型上,波司登始终遵循着2条原则:
全面拥抱开源开放的主流技术标准。 使用开源开放的主流技术标准可以确保技术方案的成熟度,更便捷的从开发者社区获取技术资源和最佳实践,也能够帮助企业更好的招募技术人才。此外,这样的策略也避免了被封闭技术体系和特定云厂商所捆绑。
尽可能利用云计算的价值。 将稳定性保障、底层技术实现、技术组件维护、弹性伸缩等非功能性需求尽可能交给云厂商解决,让技术团队将更多的精力投入到业务创新上。
这2个原则并不矛盾,相反,它们之前可以非常好的融合,是所有使用云计算的企业用户都值得借鉴的架构选型标准。比如 Kubernetes 就是典型的满足开源开放标准的技术标准,阿里云提供的 Kubernetes 产品可以简化用户的搭建成本,更好的与云计算资源进行集成。同时用户依然可以基于开源 Kuberntes 的标准协议与 API 使用云产品,这就是2条选型原则相互融合的最好体现。
容器化改造
云原生趋势下,Kubernetes 毫无疑问已经成为了企业新一代云 IT 架构的基础设施。从2021年开始,波司登就开启了微服务和容器化改造计划,将 IT 系统的底座逐步从虚拟机迁移到 Kubernetes。
在 Kubernetes 平台的选择上,基于技术选型的2条原则,波司登选择了阿里云容器服务 ACK 。ACK 以阿里云可靠稳定的 IaaS 平台为底座,向下封装了 30+ 款云产品,形成了自动化运维和云平台交互的新界面,从而提升企业业务系统的弹性和自动化运维能力。
基于容器服务 ACK 的易用性以及集成能力,波司登IT系统容器化改造工作比预想中的要顺利得多。对于每一个业务系统而言,从虚拟机迁移到 Kubernetes ,仅仅是底层的承载发生了变化,不会涉及到太多的改造成本。在关键的容器网络实现上,容器服务 ACK 通过云原生 Terway 网络模式,直接基于阿里云的虚拟化网络中的弹性网卡资源来构建的容器网络,将容器和虚拟机纳入同一层网络中,便于业务云原生化迁移。这样完全可以对传统架构实现渐近式容器化改造,在不中断业务的前提下一点一点的从虚拟机往 Kuberntes 上搬。在容器化改造的过程中,当波司登技术团队遇到疑难问题的时候,可以第一时间从阿里云获得最佳实践指导,包括集群规划、平台运维、应用适配、安全防护、可观测等多个方面,这也更进一步的提升了容器化改造的速度。
目前,波司登的自研系统已经 100% 基于 Kubernetes。相比传统的基于虚拟机部署方式,容器化帮助波司登在资源利用率上提升了30%,在运维效率上提升了40%。 波司登的技术团队也在容器化改造的过程中,掌握了管理超大规模Kubernetes集群的能力,并促成了更多云原生新技术的运用。
统一微服务架构
与容器化改造几乎同步进行的是对微服务架构的统一。在此之前,波司登的各个业务单元多种技术栈并存,彼此之间相互通讯复杂度高,项目成员的交接往往要耗费巨大的精力,极大程度上阻碍了数字化转型的进展,因此微服务架构统一势在必行。在 CIO 戴建国的带领下,波司登经历了1年多时间完成了这一项艰巨的工作,虽然投入精力巨大,但收益是立杆见影的,而且可以持续发挥作用:不论是内部团队还是三方 ISV ,在技术框架上都有统一的标准可以遵循,各团队共享技术栈后,研发效率成倍提升。
关系到未来多年的 IT 战略,在微服务架构的选型上,高开放性、高成熟度、高普及度这三条标准缺一不可,考虑到波司登以 Java 为主要开发语言,Spring Cloud Alibaba就成为了微服务框架的最佳选择。
Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案,包含开发分布式应用微服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。这些组件一部分以 SDK 的形式集成到代码中,一部分以中间件的形式独立运行,后者往往可以选择托管版云产品,以降低开发者的工作量。比如阿里云微服务引擎 MSE 就提升了开箱即用的注册配置中心 Nacos,以及云原生网关。
微服务架构的挑战
微服务对单体架构进行了拆分,不同模块之间通过网络进行通讯,本质上来讲,这并没有降低系统的复杂度,反而让系统复杂度大幅度提升,在管理难度上也为开发者提出了更高的挑战。随着微服务架构的深入使用,波司登技术团队遇到了2个难题:
性能问题定位困难。随着业务规模的增长,对于每一个来自用户的请求,链路变得越来越长,这也代表着应用之间的调用关系变得越来越复杂。传统的依赖于单机业务日志的监控手段根本无从下手,这就需要建立全新的链路跟踪机制,帮助开发者全面洞察系统运行状态,并在系统遇到异常的时候快速的定位和解决问题。这个挑战相对比较容易解决,阿里云的 ARMS 应用监控提供了无侵入式方案实现微服务链路跟踪,在易用性、功能性、稳定性上都有突出的表现。波司登把部署在容器服务 ACK 的微服务应用一键接入 ARMS 应用监控后,接下来要做的事情就主要是熟练掌握工具,并配合 Promethues/Grafana 实现统一大盘,并利用报警平台实现事件闭环,ARMS 也通过开箱即用的方式在云上提供了相关工具。
应用变更频繁造成事故。为了适应互联网业务需求的不断变化,应用变更在大型微服务架构中,是极为频繁的工作。新应用的上线、新版本的发布、新配置的推送、应用扩容、应用缩容,这些都属于应用变更的范畴。微服务架构的复杂性以及业务的快速迭代,让波司登的技术团队在每次应用变更中都疲惫不堪,因为绝大多数生产环境的事故都由应用变更导致。这个难题不能简单靠云产品来解决,需要技术团队深入剖析每一次事故的根因,针对性的进行优化,并建立一整套安全变更的行政机制,确保每一次变更都能让团队高枕无忧。
第2个难题属于微服务治理的范畴,微服务治理是微服务化深入的必经之路,涵盖流量治理、服务容错、安全治理等多个领域,帮助更低成本、更稳定、更高效地开发,运维微服务应用。在波司登的实战经验中,上下线有损问题和安全变更问题造成的业务影响最大,波司登的技术团队围绕着这几个问题进行了深入探索。
下线有损问题
微服务化之后,有一个问题长期困扰着波司登的技术团队:每次有应用下线的时候,都会导致一部分前端用户的请求失败。应用缩容和版本更新这2种情况都会产生应用主动下线行为,这两种情况对于波司登的业务系统都是每天都要执行的日常工作。为了尽可能的保障用户体验,波司登最先考虑的是让版本更新都在用户量相对比较少的凌晨进行,以缩小问题的影响面,但这其实并不能太好的解决问题。一方面,为了提升资源利用率,应用缩容基本上发生在白天;另一方面,凌晨进行版本变更加重了 IT 团队的负担,若是遇到了新版本的 bug,也不利于团队进行保障,始终不是长久之计。因此还是要从根本上找到问题的原因,通过技术方式解决问题。
我们通过下面这个图看一下微服务节点下线的正常流程
- 下线前,消费者根据负载均衡规则调用服务提供者,业务正常。
- 服务提供者节点 A 准备下线,先对其中的一个节点进行操作,首先是触发停止 Java 进程信号。
- 节点停止过程中,服务提供者节点会向注册中心发送服务节点注销的动作。
- 服务注册中心接收到服务提供者节点列表变更的信号后会,通知消费者服务提供者列表中的节点已下线。
- 服务消费者收到新的服务提供者节点列表后,会刷新客户端的地址列表缓存,然后基于新的地址列表重新计算路由与负载均衡。
- 最终,服务消费者不再调用已经下线的节点。
看似无懈可击的逻辑,但在微服务系统的实际运行过程中,会存在一些微妙的差别。其本质在于,从服务提供者确认下线,到服务消费者感知到服务提供者下线之间,存在时间差,这个时间差就是导致服务调用失败的窗口期。比如 Spring Cloud 使用的 Ribbon 负载均衡默认的地址缓存刷新时间是 30 秒一次,那么意味着即使服务消费者实时地从注册中心获取到下线节点的信号在负载均衡的地址缓存没有刷新前,依旧会有一段时间会将请求发送至老的服务提供者中。
了解到下线有损问题的本质后,波司登技术团队尝试对微服务应用进行了一些改造。对所有的微服务应该都增加一个向外暴露的 /offline 接口,并把对这个接口的调用加入到 Kubernetes 的 Prestop 脚本中,这样可以在 /offline 接口中加入服务注销相关的逻辑。/offline 接口要实现的第一件事情是主动从注册中心下线,这件事很好做,只需要一段代码,但这并不够,因为服务的消费者依然需要在一段时间后才能从注册中心感知到这个事情。所以 /offline 接口还要实现主动通知服务消费方的逻辑,而这件事情在 Spring Cloud 框架中实现起来要复杂一些,因为没有 channel 模型,服务提供方还不能真正实现主动通知服务消费方的需求,只能通过间接的方式实现。在请求的 Response Header 中带上 ReadOnly 标签,服务消费者收到 ReadOnly 标签后,会主动刷新负载均衡缓存,保证不再有新的请求访问下线过程中的服务提供者。这其中会存在少量的漏网之鱼,也就说明,依然有少量请求会失败。
此外,在下线的过程中,还有一部分请求属于在途请求:服务提供方已经收到了请求,但还没有处理完成。要彻底解决下线有损的问题,需要服务提供者端等待所有在途请求处理都完成之后,再完成下线动作。具体等多久,这个时间是不确定的,所以漏网之鱼始终存在,问题并没有完全解决。
由于 /offline 接口的实现需要侵入代码,而收效又有限,最终没有能够在波司登大面积推广,这样就只能继续从业务上容忍下线有损问题了。
上线有损问题
与下线有损问题相对应的是上线有损问题,扩容、应用新版本发布、Pod 重新调度都会产生应用上线行为,相比下线有损问题,上线有损问题很容易被忽视,这是因为上线有损问题只有在高并发大流量的场景中才会暴露出来,其中最典型的场景就是高峰期的应用弹性伸缩。
互联网应用的用户流量存在明显的波峰波谷,波司登也积极参与大促类营销活动来提升品牌曝光度,高峰期的应用弹性伸缩是一项常规技术手段。但波司登的技术团队发现应用弹性伸缩所达到的效果往往不及预期,其具体的表现是新扩容出来的应用实例在启动后会有3-5分钟左右的性能瓶颈期,在这一段时间内,会造成部分用户访问延迟剧增,在极端大流量场景下甚至拖垮了整个应用的性能,存在雪崩效应的风险。
通过排查,波司登研发团队找到了应用上线后存在性能瓶颈期的多个原因:
异步连接资源阻塞。在 jstack 日志中,发现不少线程阻塞在 taril/druid 等异步连接资源准备上,这是因为应用实例启动后,数据库与 Redis 连接池中的连接未提前建立的情况下,就会接收来自上游的流量负载,从而导致大量线程阻塞在连接的建立上,在大流量场景下性能问题会更加突出。解决问题的思路是预建数据库连接等异步建连逻辑,保证在业务流量进来之前,异步连接资源一切就绪。
ASMClassLoader 类加载器阻塞。由于 ClassLoader 加载类的代码其默认是同步类加载,在高并发场景下会有大量线程阻塞在 fastjson 的 ASMClassLoader 类加载器加载类的过程中,从而影响服务端性能,造成线程池满等问题。解决的思路是类加载器被加载前开启其并行类加载的能力。
JVM JIT 编译引起 CPU 飙升。当虚拟机发现某个方法或代码块运行特别频繁时,就会把这些代码认定为热点代码,为了提高热点代码的执行效率,在运行时,虚拟机将会把这些代码编译成与本地平台相关的机器码,并进行各层次的优化。这是 JVM 提升性能的重要技术手段,但JIT编译本身会消耗大量计算资源,造成编译期间的 CPU 使用率飙升。解决这个问题最好的方式是小流量预热,让 Java 应用在启动后可以先接收少部分流量,达到触发 JIT 编译的条件,在编译完成之后再接收正常的业务流量。
日志同步打印导致线程阻塞等其它问题。通过应用代码优化实现无损上线,并不是一件简单的事情,需要植入大量非功能性逻辑。特别在小流量预热这项技术上,需要让所有上游应用感知到应用上线的事件后,动态调整负载均衡规则,改造工作量极大。因此波司登的技术团队并没有自行从代码层实现无损上线,而是往无代码侵入的方向寻找无损上线的最优解。
安全变更问题
随着波司登微服务架构的不断演进,系统支持的业务也越来越复杂,与此同时,业务的迭代速度也发生了翻天覆地的变化。在进行微服务改造之前,新版本发布的频度是以月为单位,这跟现在每周有多个应用需要发布新版本的情况完全不在一个数量级。在经历了多次新版本发布导致的生产事故之后,波司登的技术团队吸取了之前的教训,参考阿里巴巴的安全变更经验,提出了安全变更”可灰度、可监控、可回滚“的原则,这就对波司登技术团队的变更管理提出了更高的要求。特别是在灰度策略上,简单的应用滚动更新不能控制业务流量通往新版本的比例,不能够满足安全变更的要求,需要有更高阶的灰度技术来支撑。
为了实现灰度过程中的路由可控,波司登最初采取的方式是通过物理隔离的方式构建2套环境,每套环境都包含了全部的微服务应用,以及 Message Queue、Redis 等其他中间件。通过前置的网关层实现流量路由,决定用户的流量发送到正式环境还是灰度环境,路由的规则可以基于流量特征进行匹配,也可以设置为百分比。
这套架构搭建完成之后,是能够非常好的胜任安全变更原则的,每次有新版本发布的时候,都可以基于可控的流量进行小规模验证。通过充分的验证之后再决定是否放大进入新版本的流量比例,或者及时回滚。
但随着物理隔离方案的推广,其局限性也越来越明显的暴露出来。首先这样的架构存在严重的资源浪费问题,虽然可以尽可能利用云计算的弹性能力适配流量规模,但也只是降低了一部分资源,不能从根本上解决资源浪费的问题。而且需要用到的中间件产品往往不能像微服务应用一样灵活的弹性伸缩。
此外,更重要的问题在于隔离方案需要整条业务线甚至全公司统一版本发布节奏,因为大家只有一套共享的灰度环境。微服务架构的规模越大,团队之间的分工会越明确,每个团队所负责的微服务应用在整个微服务架构中所占的比重也就越小。这样的方案在多团队协同作战的时候,极难协调多个团队的版本发布节奏,实际上严重拖慢了业务系统的创新迭代速度。
因为物理隔离方案在实际生产中的局限性,业界更为推崇的是逻辑隔离方案。当需要对某一个微服务应用发布版本的时候,可以独立部署灰度版本,通过调用链路上的流量控制使得灰度流量能在灰度环境和正式环境间流转,实现灰度微服务应用的正常运行,帮助业务方进行新功能验证。逻辑隔离方案不需要做整套环境的冗余,大量节省了资源成本。更为关键的是,逻辑隔离方案可以让不同的团队各自决定自己的灰度节奏,并不需要所有团队都在同一个容器期进行灰度验证。这样不仅可以大幅度提升业务系统创新迭代速度,还能更进一步降低变更所带来的风险,因为职责分享以后,每个团队都可以拥有更长的灰度窗口期,灰度验证过程中遇到了问题也能更精确的定位到责任方。
然而逻辑隔离的技术实现极为复杂,物理隔离方案仅需要在网关层控制路由策略,而逻辑隔离需要每一个微服务应用都必备识别灰度标识并动态控制路由策略的能力。在 Spring Cloud 框架下,微服务应用之间相互调用的负载均衡机制由 Ribbon 实现,实际上属于应用层 SDK 的能力范围。动态控制路由策略相当于动态控制 Ribbon 的负载均衡策略,改造起来会有比较大的工作量。
逻辑隔离机制更为复杂的技术实现在于灰度标识的全链路透传,也就是针对每一个用户请求,如果在微服务应用间流转的过程中被打上了灰度标识,这个灰度标识就必须在接下来的链路中一直传递下去。比如上图 B 服务的灰度服务在调用 C 服务的时候,因为 C 服务并没有灰度版本,所以加到了 C 服务的稳定版本,但接下来的 D 服务是同时存在稳定版本和灰度版本的。这里就存在一个潜在的需求:凡是经过了服务 B 灰度服务的流量,都应该发往服务 D 的灰度版本。这个需求能够实现的必要条件,就是灰度标识的全链路透传。
微服务应用之间的灰度标识全链路透传可以借助于 ARMS 等链路监控工具而实现,存在一定的代码改造工作量。但更为复杂的是,如果链路中存在基于消息中间件的异步调用,就不能仅仅通过调整应用层的负载均衡机制来控制路由策略了,需要对消息中间件的服务端和客户端都进行适配,存在大量改造工作量。跟无损上线一样,波司登的技术团队也没有急于求成对应用层代码进行大刀阔斧的改造,而是与阿里云团队共同探讨更优雅的解决方案。
MSE 微服务治理方案
微服务引擎 MSE 是阿里云面向业界主流微服务生态提供的一站式微服务平台,包括注册配置中心、云原生网关和微服务治理3款可以独立输出的产品。对于注册配置中心和云原生网关,波司登已经比较熟悉了,分别为微服务架构提供了 Nacos 以及 Kubernetes Ingress 服务。关于第3款产品微服务治理,波司登的技术团队有过深入的研究,对于解决安全变更领域的多个难题都能带来帮助,但对于微服务应用全面接入 MSE 微服务治理,波司登还是存在一些顾虑。
主要的顾虑点集中在技术改造复杂度、侵入性、稳定性等方面,波司登的技术团队与阿里云的专家团队经过深入的沟通,对所有潜在风险点逐一进行了评估。经过大量的预研后,波司登决定将微服务应用全面接入MSE微服务治理。这个方案除了在功能层面能够满足波司登微服务治理的需求之外,波司登的技术团队更看中的是这几个方面的特性:
无侵入。 MSE 微服务治理能力基于 Java Agent 字节码增强的技术实现,无缝支持市面上近5年的所有 Spring Cloud 的版本。研发团队不用改一行代码就可以使用,甚至在研发阶段都不需要考虑应用部署的时候是否接入 MSE 微服务治理,让研发团队更聚焦于业务的创新。这是一个非常重要的特性,体现了这套方案的开放度,也能确保方案不会有厂商锁定问题。
接入简单。 用户只需在阿里云容器的应用市场安装 pilot 组件,就可以通过 MSE 控制台对一个命名空间的所有 Java 应用开启治理功能,这个时候 pilot 组件会自动为 Java 应用所在的 Pod 注入 Agent 。当然,更通用的方式是通过 Kubernetes 的声明式描述,来控制每个应用是否开启治理功能,也就是对 Pod 的 yaml 文件加上一行注解,这样能更方便的和 CI/CD 工具集成。当然关闭服务治理功能也是非常容易的,只需在控制台关闭服务治理,或者修改 yaml 文件上的注解就行,不需要改变业务的现有架构,根据需要随启随停。
高稳定性。 同时服务于阿里集巴的内部应该以及多个外部客户,经过了大规模实战验证。
可观测能力。 提供完整的流量可视化视图,支持全局看板、网关实例监控、日志检索、业务 TOP 榜、日志投递、以及报警管理等功能。能够帮助用户直接的了解到微服务治理能力开启后产生的效果,更全面的了解微服务应用的运行状态。
支持混合云场景。 不论是在线下 IDC,还是其他云上部署的微服务系统,只要网络可以通,也能够享受到治理能力的增强,用法保持一致。
拥抱云原生。 与 Kubernetes 体系完美集成,无损上下线使得应用在弹性伸缩的过程中保持流量无损,通过 Jenkins 构建 CI/CD 实现在 Kubernetes 环境下的金丝雀发布,基于 Ingress 实现全链路灰度等。
无损下线
MSE 实现无损下线的原理很简单,流程如下:
当一个微服务应用实例接收到下线指令后,红色字段标识的3个步骤由 Agent 自动实现
从注册中心下线。 这一步执行完之后,服务的所有消费者有机会从注册中心感知到下线行为,但在 Spring Cloud 体系中,这个感知存在时间差,并不能立即通知所有消费者,所以我们不能单纯依赖这个步骤实现无损下线。
主动通知所有消费者。 这是最为关键的一步,Agent 绕过注册中心,直接给所有消费者发送了实例下线的通知,这样消费方能够立即感知到下线行为。
消息者更新负载均衡。 收到实例下线通知后,服务的消费方将下线的实例从负载均衡实例列表中移除,从而不再发请求到下线的实例。
这几个步骤都完成以后,收到下线指令的应用实例才会在处理完所有在途请求的情况下,进入真正的下线状态。所以整个过程不会有任何一次服务请求失败的情况发生。这项技术不需要修改任何一行代码,就能在版本更新或应用缩容的时候提升用户体验,增加微服务系统的稳定性。
如果一个微服务应用处在链路的入口位置,通过 Ingress 暴露给用户,这个时候并不存在挂上了 Agent 的服务消费者应用,无损下线机制还能正常工作吗?答案是肯定的,如果 Ingress 这一层是由 MSE 云原生网关实现的,所有的适配工作都已经完成,无损下线机制依然可以完美运行。
无损上线
MSE 实现无损上线也是基于类似的原理:
- 微服务消费者可以快速感知微服务提供方的上下线事件
- Agent 可以动态更新微服务消费方的负载均衡规则
因此,用户可以为每一个微服务消费者配置一定时长的预热窗口期,比如2分钟。在这一段时间内,如果感知服务提供方的实例新上线,就在窗口期通过小流量对新上线的实例进行预热,并逐步增量流量规模,直到窗口期结束后恢复正常的流量比例,这样就可以规避 Java 应用启动初期所存在的性能问题。
完整的流程如下:
不论是无损上线还是无损下线,都通过从 MSE 的控制台清晰的观察到微服务治理带来的效果。
全链路流量治理
通过 MSE 微服务治理,长期困扰波司登的安全变更问题得到了解决,因为波司登一直在追求的逻辑隔离灰度方案可以通过 Agent 技术轻松实现。为了实现逻辑隔离灰度,可以先从金丝雀发布开始入手,金丝雀发布在业界有广泛的使用,是应用版本更新的常用灰度手段。金丝雀发布会对流量进行比例分割,一开始为新版本的实例分配较小比例的流量,经过一段时间的运行,确认新版本运行正常后再逐步提高所分配流量的比例,直到最终全量切流。通过这种方式做发布可以在新版本出现问题时控制影响面,提高系统的稳定性。
金丝雀发布通常通过流量染色和版本打标来实现。在 MSE 的实现中,流量染色可以通过识别流量特征而实现,在下图的例子中,可以通过 HTTP Header 里面的具体字段来决定一个请求是否进行灰度染色。而版本打标是利用 Kubernetes 的声明式部署实现的,通过在 Pod 上添加 Annotation ,可以让对应的版本打上灰度标识。这样就可以限制只有被染过色的流量才会进入打上了灰度标识的版本,从而实现新版本业务的小规模验证,一旦发现新版本存在任何问题,可以及时回滚,把对业务的影响降至最低。
金丝雀发布最终会演变成全链路流量治理能力,从而真正实现基于逻辑隔离机制的高阶灰度方案。对于穿梭在微服务链路上的流量,一旦被染色,就能将染色信息传递到整条链路。这个机制和泳道非常类似,微服务在同一时间点可能存在多个并存的业务版本,每条泳道象征着一个业务版本,只有经过染色的流量,才会进入到对应泳道中。
波司登经过半年时间的实战探索,在 MSE 微服务治理的帮助下,最终驾驭了大规模微服务架构的全链路流量治理能力,并形成了成熟的流程机制,通过全链路流量治理对每一次应用变更进行充分的灰度验证。有了这项技术之后,每个团队都可以灵活的决定应用变更的时间周期,但对于安全变更的要求变得更高了,一旦造成了生产事故,在行政上会有更严厉处罚措施。因此需要每个团队在实施应用变更的时候,都通过全链路流量治理确保稳定性,这样即使新版本存在漏洞,对于整体业务的影响也能控制在极低的范围内。这项技术被各团队广泛采纳后,波司登的业务迭代频率实现了2倍以上的提升,因为应用变更导致的生产事故降低了 70% 以上。
全链路稳定性治理
另一个被波司登广泛使用的微服务治理能力是全链路稳定性治理,对于波司登这样需要频繁举办线上运营活动的企业,全链路稳定性治理是非常重要的技术。MSE 提供的全链路稳定性治理,在流量防护方面形成可拓展闭环,能够通过故障识别模型发现不同层次的问题,如接口层的状态码与异常类型、操作系统层的指标异常。在识别出问题后,发出异常告警,方便用户进行针对性的流量治理,如进行自适应限流防护或场景化限流防护;防护规则设置后,系统便按照预设的阈值与防护手段保护系统,而系统防护的效果可通过监控查看,另一方面,也可通过监控反向审视流量防护规则设置的合理性,及时调整。
对于防护策略以及防护规则的设定,波登司主要通过全链路压测获得参考。波司登通过阿里云 PTS 模拟用户流量,对系统进行了多次全链路压测。在压测的过程中不断优化微服务架构各个环境的容量配比,确定系统在真实业务中表现出来的系统上限,同时也确定在大流量场景下需要使用到的流量防护策略。为了更进一步提升微服务系统在高并发大流量场景的性能,并提升资源利用率,波司登还充分利用了 ACK 集群的弹性伸缩能力,在业务高峰期让应用和集群资源同时实现自动水平扩扩展,并在业务高峰期自动回收资源。除了在业界广泛运用的单机流控手段(包括并发控制、自适应防护、熔断、主动降级、热点防护等一系列技术)和网关流控手段之外,波司登还深入使用了MSE提供的数据库治理能力,特别是基于 SQL 的流控、降级、容错,避免严重的慢 SQL 发生后拖垮整个数据库,对线上业务产生阻断性的风险。在全链路稳定性治理和弹性伸缩的帮助下,再加上页面静态化、请求拦截、数据隔离、异步处理等常规技术手段,波司登已经建立起在秒杀业务场景中支撑百万级并发量的技术能力,并确保双11活动过程系统的稳定运行。
总结
技术能力的不断进步,帮助波司登使用数字化手段对业务进行不断创新,并取得了一系列重要的战果。数字化能力的提升也直接体现在销量与利润上,波司登在羽绒服的销售额和销售量上都登上了全球第一,连续5年实现了营收与利润的双位数增长。波司登的技术团队在云原生微服务治理方面的不断探索,让他们在超大规模微服务架构领域沉淀宝贵经验,但这只是支撑业务高速发展所经历的多项技术变革中的一个重要组成部分。波司登会继续拥抱云计算,通过更先进、更高效的技术,更数字化的运营方式,引领服饰行业激发创新活力,与各行各业的时代变革者共同成长。