波司登云原生微服务治理探索

背景
Aliware
波司登创始于1976年,专注于羽绒服的研发、设计、制作,是全球知名的羽绒服生产商。波司登用一系列世人瞩目的辉煌成绩证明了自己的实力:连续26年全国销量领先,连续22年代表中国向世界发布防寒服流行趋势,产品畅销美国、法国、意大利等72个国家,全球超过2亿用户。作为羽绒服革命的旗手,波司登引领了行业内的“三次革命”。
在产品力和销售成绩单背后,波司登在生产、仓储、物流、销售各环节已完成数字化转型和创新改造。除生产端的智能生产工厂,波司登对仓储和物流环节也进行智能化改造,提升小单快反、拉式补货的比重,最大限度减少困扰服装企业多时的“库存”问题;为了精准分发销售端产品,波司登建立数据中台,打通全渠道数据,赋能消费者研究、商品企划、渠道匹配等。现在,波司登每件羽绒服从生产到抵达消费者,背后都是一段数字之旅。 02
云原生技术发展
Aliware
随着波司登数字业务的飞速发展,背后的 IT 技术也在不断更新迭代。波司登极为重视客户对服务的体验,并将系统稳定性、业务功能的迭代效率、问题的快速定位和解决视为构建核心竞争力的基石。服饰行业会积极参与各大电商平台的促销活动,业务流量的波峰波谷现象明显,如果由于资源分配不合理导致高峰时期订单溢出、运力不足,会极大影响顾客和商家的体验。此外,波司登自研了用户运营平台(用户洞察系统、内容管理系统、用户管理 CRM 系统及用户小程序)、零售运营平台(线上平台订单管理 OMS 系统、线下渠道管理系统、门店收银 POS 系统)、商品运营平台(订单处理中心 OPC、库存计算中心 ICC、商品订货系统、商品运营 iMOS 系统、采购制造 GiMS 系统、物流管理 EWM 系统、机器人调度 WCS 系统) 等诸多垂直业务功能,在市场需求的快速变化下,产品功能创新和迭代效率问题也是对技术架构的一大挑战。 这些现状的解法和云原生架构带来的核心能力不谋而合,在波司登系统改造上云的过程中,CIO 戴建国亲自带队,围绕着云原生技术体系,推动波司登的各条业务线进行技术升级改造,加快数智化发展进程。在技术选型上,波司登始终遵循着2条原则:
全面拥抱开源开放的主流技术标准。 使用开源开放的主流技术标准可以确保技术方案的成熟度,更便捷的从开发者社区获取技术资源和最佳实践,也能够帮助企业更好的招募技术人才。此外,这样的策略也避免了被封闭技术体系和特定云厂商所捆绑。
尽可能利用云计算的价值。 将稳定性保障、底层技术实现、技术组件维护、弹性伸缩等非功能性需求尽可能交给云厂商解决,让技术团队将更多的精力投入到业务创新上。这2个原则并不矛盾,相反,它们之前可以非常好的融合,是所有使用云计算的企业用户都值得借鉴的架构选型标准。比如 Kubernetes 就是典型的满足开源开放标准的技术标准,阿里云提供的 Kubernetes 产品可以简化用户的搭建成本,更好的与云计算资源进行集成。同时用户依然可以基于开源 Kuberntes 的标准协议与 API 使用云产品,这就是2条选型原则相互融合的最好体现。
03
容器化改造
Aliware
云原生趋势下,Kubernetes 毫无疑问已经成为了企业新一代云 IT 架构的基础设施。从2021年开始,波司登就开启了微服务和容器化改造计划,将 IT 系统的底座逐步从虚拟机迁移到 Kubernetes。 在 Kubernetes 平台的选择上,基于技术选型的2条原则,波司登选择了阿里云容器服务 ACK 。ACK 以阿里云可靠稳定的 IaaS 平台为底座,向下封装了 30+ 款云产品,形成了自动化运维和云平台交互的新界面,从而提升企业业务系统的弹性和自动化运维能力。

统一微服务架构
Aliware
与容器化改造几乎同步进行的是对微服务架构的统一。在此之前,波司登的各个业务单元多种技术栈并存,彼此之间相互通讯复杂度高,项目成员的交接往往要耗费巨大的精力,极大程度上阻碍了数字化转型的进展,因此微服务架构统一势在必行。在 CIO 戴建国的带领下,波司登经历了1年多时间完成了这一项艰巨的工作,虽然投入精力巨大,但收益是立杆见影的,而且可以持续发挥作用:不论是内部团队还是三方 ISV ,在技术框架上都有统一的标准可以遵循,各团队共享技术栈后,研发效率成倍提升。 关系到未来多年的 IT 战略,在微服务架构的选型上,高开放性、高成熟度、高普及度这三条标准缺一不可,考虑到波司登以 Java 为主要开发语言,Spring Cloud Alibaba就成为了微服务框架的最佳选择。

微服务架构的挑战
Aliware
微服务对单体架构进行了拆分,不同模块之间通过网络进行通讯,本质上来讲,这并没有降低系统的复杂度,反而让系统复杂度大幅度提升,在管理难度上也为开发者提出了更高的挑战。随着微服务架构的深入使用,波司登技术团队遇到了2个难题:
性能问题定位困难 。 随着业务规模的增长,对于每一个来自用户的请求,链路变得越来越长,这也代表着应用之间的调用关系变得越来越复杂。传统的依赖于单机业务日志的监控手段根本无从下手,这就需要建立全新的链路跟踪机制,帮助开发者全面洞察系统运行状态,并在系统遇到异常的时候快速的定位和解决问题。这个挑战相对比较容易解决,阿里云的 ARMS 应用监控提供了无侵入式方案实现微服务链路跟踪,在易用性、功能性、稳定性上都有突出的表现。波司登把部署在容器服务 ACK 的微服务应用一键接入 ARMS 应用监控后,接下来要做的事情就主要是熟练掌握工具,并配合 Promethues/Grafana 实现统一大盘,并利用报警平台实现事件闭环,ARMS 也通过开箱即用的方式在云上提供了相关工具。
应用变更频繁造成事故 。 为了适应互联网业务需求的不断变化,应用变更在大型微服务架构中,是极为频繁的工作。新应用的上线、新版本的发布、新配置的推送、应用扩容、应用缩容,这些都属于应用变更的范畴。微服务架构的复杂性以及业务的快速迭代,让波司登的技术团队在每次应用变更中都疲惫不堪,因为绝大多数生产环境的事故都由应用变更导致。这个难题不能简单靠云产品来解决,需要技术团队深入剖析每一次事故的根因,针对性的进行优化,并建立一整套安全变更的行政机制,确保每一次变更都能让团队高枕无忧。第2个难题属于微服务治理的范畴,微服务治理是微服务化深入的必经之路,涵盖流量治理、服务容错、安全治理等多个领域,帮助更低成本、更稳定、更高效地开发,运维微服务应用。在波司登的实战经验中,上下线有损问题和安全变更问题造成的业务影响最大,波司登的技术团队围绕着这几个问题进行了深入探索。

下线有损问题
Aliware
微服务化之后,有一个问题长期困扰着波司登的技术团队:每次有应用下线的时候,都会导致一部分前端用户的请求失败。应用缩容和版本更新这2种情况都会产生应用主动下线行为,这两种情况对于波司登的业务系统都是每天都要执行的日常工作。为了尽可能的保障用户体验,波司登最先考虑的是让版本更新都在用户量相对比较少的凌晨进行,以缩小问题的影响面,但这其实并不能太好的解决问题。一方面,为了提升资源利用率,应用缩容基本上发生在白天;另一方面,凌晨进行版本变更加重了 IT 团队的负担,若是遇到了新版本的 bug,也不利于团队进行保障,始终不是长久之计。因此还是要从根本上找到问题的原因,通过技术方式解决问题。 我们通过下面这个图看一下微服务节点下线的正常流程

-
下线前,消费者根据负载均衡规则调用服务提供者,业务正常。
-
服务提供者节点 A 准备下线,先对其中的一个节点进行操作,首先是触发停止 Java 进程信号。
-
节点停止过程中,服务提供者节点会向注册中心发送服务节点注销的动作。
-
服务注册中心接收到服务提供者节点列表变更的信号后会,通知消费者服务提供者列表中的节点已下线。
-
服务消费者收到新的服务提供者节点列表后,会刷新客户端的地址列表缓存,然后基于新的地址列表重新计算路由与负载均衡。
- 最终,服务消费者不再调用已经下线的节点。
看似无懈可击的逻辑,但在微服务系统的实际运行过程中,会存在一些微妙的差别。其本质在于,从服务提供者确认下线,到服务消费者感知到服务提供者下线之间,存在时间差,这个时间差就是导致服务调用失败的窗口期。比如 Spring Cloud 使用的 Ribbon 负载均衡默认的地址缓存刷新时间是 30 秒一次,那么意味着即使服务消费者实时地从注册中心获取到下线节点的信号在负载均衡的地址缓存没有刷新前,依旧会有一段时间会将请求发送至老的服务提供者中。

上线有损问题
Aliware
与下线有损问题相对应的是上线有损问题,扩容、应用新版本发布、Pod 重新调度都会产生应用上线行为,相比下线有损问题,上线有损问题很容易被忽视,这是因为上线有损问题只有在高并发大流量的场景中才会暴露出来,其中最典型的场景就是高峰期的应用弹性伸缩。 互联网应用的用户流量存在明显的波峰波谷,波司登也积极参与大促类营销活动来提升品牌曝光度,高峰期的应用弹性伸缩是一项常规技术手段。但波司登的技术团队发现应用弹性伸缩所达到的效果往往不及预期,其具体的表现是新扩容出来的应用实例在启动后会有3-5分钟左右的性能瓶颈期,在这一段时间内,会造成部分用户访问延迟剧增,在极端大流量场景下甚至拖垮了整个应用的性能,存在雪崩效应的风险。 通过排查,波司登研发团队找到了应用上线后存在性能瓶颈期的多个原因:
异步连接资源阻塞 。在 jstack 日志中,发现不少线程阻塞在 taril/druid 等异步连接资源准备上,这是因为应用实例启动后,数据库与 Redis 连接池中的连接未提前建立的情况下,就会接收来自上游的流量负载,从而导致大量线程阻塞在连接的建立上,在大流量场景下性能问题会更加突出。解决问题的思路是预建数据库连接等异步建连逻辑,保证在业务流量进来之前,异步连接资源一切就绪。
ASMClassLoader 类加载器阻塞 。由于 ClassLoader 加载类的代码其默认是同步类加载,在高并发场景下会有大量线程阻塞在 fastjson 的 ASMClassLoader 类加载器加载类的过程中,从而影响服务端性能,造成线程池满等问题。解决的思路是类加载器被加载前开启其并行类加载的能力。
JVM JIT 编译引起 CPU 飙升 。当虚拟机发现某个方法或代码块运行特别频繁时,就会把这些代码认定为热点代码,为了提高热点代码的执行效率,在运行时,虚拟机将会把这些代码编译成与本地平台相关的机器码,并进行各层次的优化。这是 JVM 提升性能的重要技术手段,但JIT编译本身会消耗大量计算资源,造成编译期间的 CPU 使用率飙升。解决这个问题最好的方式是小流量预热,让 Java 应用在启动后可以先接收少部分流量,达到触发 JIT 编译的条件,在编译完成之后再接收正常的业务流量。
日志同步打印导致线程阻塞等其它问题 。 通过应用代码优化实现无损上线,并不是一件简单的事情,需要植入大量非功能性逻辑。特别在小流量预热这项技术上,需要让所有上游应用感知到应用上线的事件后,动态调整负载均衡规则,改造工作量极大。因此波司登的技术团队并没有自行从代码层实现无损上线,而是往无代码侵入的方向寻找无损上线的最优解。 08
安全变更问题
Aliware
随着波司登微服务架构的不断演进,系统支持的业务也越来越复杂,与此同时,业务的迭代速度也发生了翻天覆地的变化。在进行微服务改造之前,新版本发布的频度是以月为单位,这跟现在每周有多个应用需要发布新版本的情况完全不在一个数量级。在经历了多次新版本发布导致的生产事故之后,波司登的技术团队吸取了之前的教训,参考阿里巴巴的安全变更经验,提出了安全变更”可灰度、可监控、可回滚“的原则,这就对波司登技术团队的变更管理提出了更高的要求。特别是在灰度策略上,简单的应用滚动更新不能控制业务流量通往新版本的比例,不能够满足安全变更的要求,需要有更高阶的灰度技术来支撑。 为了实现灰度过程中的路由可控,波司登最初采取的方式是通过物理隔离的方式构建2套环境,每套环境都包含了全部的微服务应用,以及 Message Queue、Redis 等其他中间件。通过前置的网关层实现流量路由,决定用户的流量发送到正式环境还是灰度环境,路由的规则可以基于流量特征进行匹配,也可以设置为百分比。


MSE 微服务治理方案
Aliware
微服务引擎 MSE 是阿里云面向业界主流微服务生态提供的一站式微服务平台,包括注册配置中心、云原生网关和微服务治理3款可以独立输出的产品。对于注册配置中心和云原生网关,波司登已经比较熟悉了,分别为微服务架构提供了 Nacos 以及 Kubernetes Ingress 服务。关于第3款产品微服务治理,波司登的技术团队有过深入的研究,对于解决安全变更领域的多个难题都能带来帮助,但对于微服务应用全面接入 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 实现全链路灰度等。
10
无损下线
Aliware
MSE 实现无损下线的原理很简单,流程如下:

从注册中心下线。 这一步执行完之后,服务的所有消费者有机会从注册中心感知到下线行为,但在 Spring Cloud 体系中,这个感知存在时间差,并不能立即通知所有消费者,所以我们不能单纯依赖这个步骤实现无损下线。
主动通知所有消费者。 这是最为关键的一步,Agent 绕过注册中心,直接给所有消费者发送了实例下线的通知,这样消费方能够立即感知到下线行为。
消息者更新负载均衡。 收到实例下线通知后,服务的消费方将下线的实例从负载均衡实例列表中移除,从而不再发请求到下线的实例。这几个步骤都完成以后,收到下线指令的应用实例才会在处理完所有在途请求的情况下,进入真正的下线状态。所以整个过程不会有任何一次服务请求失败的情况发生。这项技术不需要修改任何一行代码,就能在版本更新或应用缩容的时候提升用户体验,增加微服务系统的稳定性。
如果一个微服务应用处在链路的入口位置,通过 Ingress 暴露给用户,这个时候并不存在挂上了 Agent 的服务消费者应用,无损下线机制还能正常工作吗?答案是肯定的,如果 Ingress 这一层是由 MSE 云原生网关实现的,所有的适配工作都已经完成,无损下线机制依然可以完美运行。 11
无损上线
Aliware
MSE 实现无损上线也是基于类似的原理:
-
微服务消费者可以快速感知微服务提供方的上下线事件
- Agent 可以动态更新微服务消费方的负载均衡规则
因此,用户可以为每一个微服务消费者配置一定时长的预热窗口期,比如2分钟。在这一段时间内,如果感知服务提供方的实例新上线,就在窗口期通过小流量对新上线的实例进行预热,并逐步增量流量规模,直到窗口期结束后恢复正常的流量比例,这样就可以规避 Java 应用启动初期所存在的性能问题。
完整的流程如下:
全链路流量治理
Aliware
通过 MSE 微服务治理,长期困扰波司登的安全变更问题得到了解决,因为波司登一直在追求的逻辑隔离灰度方案可以通过 Agent 技术轻松实现。为了实现逻辑隔离灰度,可以先从金丝雀发布开始入手,金丝雀发布在业界有广泛的使用,是应用版本更新的常用灰度手段。金丝雀发布会对流量进行比例分割,一开始为新版本的实例分配较小比例的流量,经过一段时间的运行,确认新版本运行正常后再逐步提高所分配流量的比例,直到最终全量切流。通过这种方式做发布可以在新版本出现问题时控制影响面,提高系统的稳定性。 金丝雀发布通常通过流量染色和版本打标来实现。在 MSE 的实现中,流量染色可以通过识别流量特征而实现,在下图的例子中,可以通过 HTTP Header 里面的具体字段来决定一个请求是否进行灰度染色。而版本打标是利用 Kubernetes 的声明式部署实现的,通过在 Pod 上添加 Annotation ,可以让对应的版本打上灰度标识。这样就可以限制只有被染过色的流量才会进入打上了灰度标识的版本,从而实现新版本业务的小规模验证,一旦发现新版本存在任何问题,可以及时回滚,把对业务的影响降至最低。


全链路稳定性治理
Aliware
另一个被波司登广泛使用的微服务治理能力是全链路稳定性治理,对于波司登这样需要频繁举办线上运营活动的企业,全链路稳定性治理是非常重要的技术。MSE 提供的全链路稳定性治理,在流量防护方面形成可拓展闭环,能够通过故障识别模型发现不同层次的问题,如接口层的状态码与异常类型、操作系统层的指标异常。在识别出问题后,发出异常告警,方便用户进行针对性的流量治理,如进行自适应限流防护或场景化限流防护;防护规则设置后,系统便按照预设的阈值与防护手段保护系统,而系统防护的效果可通过监控查看,另一方面,也可通过监控反向审视流量防护规则设置的合理性,及时调整。

总结
Aliware
技术能力的不断进步,帮助波司登使用数字化手段对业务进行不断创新,并取得了一系列重要的战果。数字化能力的提升也直接体现在销量与利润上,波司登在羽绒服的销售额和销售量上都登上了全球第一,连续5年实现了营收与利润的双位数增长。波司登的技术团队在云原生微服务治理方面的不断探索,让他们在超大规模微服务架构领域沉淀宝贵经验,但这只是支撑业务高速发展所经历的多项技术变革中的一个重要组成部分。波司登会继续拥抱云计算,通过更先进、更高效的技术,更数字化的运营方式,引领服饰行业激发创新活力,与各行各业的时代变革者共同成长。
推荐阅读:
欢迎关注微信公众号: 互联网全栈架构 ,收取更多有价值的信息。