作者:凡问、启淮
前言
本文基于阿里云技术服务团队和产研团队,在解决易易互联使用 MSE(微服务引擎)产品无损上线功能所遇到问题的过程总结而成。本文将从问题和解决方法谈起,再介绍相关原理,后进一步拓展到对微服务引擎和云原生网关无损上线能力的介绍。
易易互联是吉利集团旗下的企业,专注于新能源汽⻋换电业务,提供便捷的换电解决⽅案,成⽴于 2017 年。
易易互联的核⼼业务围绕换电技术与服务展开,包括换电站的研发、建设和运营、电池销售与租赁、以及与之相关的技术服务如电池管理、云平台监控等。其换电站具备⾼智能化特点,配备全天候智能温控系统,⽀持恒温慢充和动态巡检,确保电池充电过程的⾼效与安全,同时实现⻋、站、云平台之间的互联互通。截至 2024 年 5 月,易易互联已在重庆、杭州、 广州、成都、天津等 30 多个城市布局和运营超 400 座换电站,已是营运市场换电补能领域的领先品牌。
易易互联后端采⽤微服务架构,因为换电业务系统包含⻋、站、云三个平台,并且其物联⽹+互联⽹的业务特点,在业务快速迭代的同时,对业务稳定性也有着⾮常⾼的要求。因此,很早开始,易易互联便引⼊ MSE(微服务引擎),通过服务治理的⼀系列功能,提升微服务架构应⽤的研发效率和稳定性。
起因
1.1 客户案例
MSE(阿里云微服务引擎,以下简称 MSE)无损上下线能力可以很好地规避变业务迭代与变更带来的流量损失,保证了业务的连续性,为高增长业务提供坚实的技术保障。而最近易易互联在使用过程中反馈了一例服务无损上线相关问题:服务预热开始时间早于服务注册时间,导致服务上线流量有损。客户对此不解,更是想了解其影响和背后原因原理。
客户的应用的无损上线各功能的执行顺序及业务流量则如下图所示:
而【无损上线 [ 1] 】官方文档预热曲线如下图:
执行顺序从上图可看到有两个特点:
-
预热开始的时间点确实早于服务注册的时间点。
-
预热开始后的 QPS 呈现均匀脉冲形状。
为何上述两幅图的顺序不一致呢?通过原理分析和测试验证,确定问题原因是 K8s liveness 探针配置了 Spring Boot Actuator health 接口,而 MSE 将对 Spring Boot Actuator health 接口调用判断为服务预热开始导致。
1.2 如何避免服务预热误判
接下来讨论如何避免误判问题的发生。对于此问题的回答,我们通过介绍 Spring MVC 请求处理流程和服务预热判断的实现原理来详细说明。
如上图所示:
① 针对 Spring Boot/Cloud 应用,包括服务预热判断在内的很多 MSE 核心逻辑是通过在 DispatcherServlet 上增强实现的。 DispatcherServlet 是 Spring MVC 中用来统一处理请求分发的核心组件。
② 进一步,针对不同请求的分发处理,通过 HandlerMapping 完成,HandlerMapping 的一种实现便是用来处理 Actuator 请求的 EndpointHandlerMapping 组件。
③ 如果发现请求是访问 Actuator Endpoint 的,EndpointHandlerMapping 就会把请求分发至对应组件,如 /actuator/info转发至 InfoEndpoint。而对于健康检查请求 /actuator/health则分发至 HealthEndpoint。
通过上面的流程可见,因为对服务预热判断的逻辑是在 DispatcherServlet,而判断健康检查的组件在 DispatcherServlet 之后的 HandlerMapping,导致 MSE 要想准确判断请求是正常业务 RPC,还是健康检查这样的非业务调用,存在相当困难。这也是导致此问题的核心原因。
而解决此问题的直接方法,也是通过增加配置,告知 MSE,哪些请求不用纳入服务预热判断逻辑。 具体方法如下:
避免服务预热误判的直接方法
在应用运行时的环境变量中增加如下配置,可避免误判问题:profile_micro_service_record_warmup_ignored_path=<skip_urls,如 /actuator/health,多个地址用,分割>
但上述方式,要引入额外配置,有一定侵入性,也不便在大规模组织中统一规范,不算是最优方案。那是否有更好的方式?
通常情况,K8s liveness 配置 TCP 协议即可,并不一定需要配置 HTTP。而将 K8s liveness 探针配置为 TCP 协议,并不会触发此问题,那能否通过此方案作为解决方案?
如何使用方可以统一和规范 K8s liveness 探针配置,配置为 TCP 不失为一种规避方案。但从产品角度,不能假定所有客户都这样做。并且将 K8s liveness 配置 HTTP 协议探针,能更准确反映服务的真实状态,也有不少使用场景,因此不能将强制 TCP 作为解决方案。
对于如何更优雅地解决此问题方面,目前正在考虑的方向包括自动识别并忽略用户的存活探针/就绪探针等端点、RPC 流量打标等方法。
前者可以一定程度上避免显式配置问题,但无法完全解决此问题。而后者通过解决如何判断流量是否来自于真实的业务调用这一核心问题解决。在 Consumer 发起服务调用时,给请求 header 中加上某个特定的标签。Provider 侧在接收流量时,在首次检测到请求带有这些标签时,就可以认定此时服务预热开始,并上报相关事件。这种方式最为精确,但需要服务 Provider/Consumer 全部接入 MSE。因此,最终方案应该是综合使用多种手段,屏蔽技术复杂性,使得服务预热更加有效。
1.3 再谈微服务的无损上线
MSE 微服务治理的无损上线功能是在 21 年底正式上线。微服务无损上线的功能,最早产生在需求快速迭代,强调研发效率的互联网行业,以及注重稳定性的 ToB 行业。
而近些年,以汽车为代表的传统行业,随着愈加注重数字化,对软件系统的稳定性和研发效率日益重视,也盼望着微服务治理等技术的普及和易用。
如果没有无损上线能力,当应用发布或因弹性调度而导致的应用重启,应用将产生如错误率增加、RT 升高等表现。随着微服务的拆分,链路上的任意环节的上述问题,就可能导致全链路的异常表现。而在互联网 ToC 业务领域,除了少部分如支付、出行关乎民生的基础服务外,多数可能只会影响娱乐、消费等场景。但当传统行业也数字化之后,微服务稳定性将进一步影响我们生活的方方面面,如汽车行业中的车控、充电等功能。
纵观整个为服务治理,可分为开发态、变更态和运行态。 这三个领域中,变更态是有研发行为主动产生,对线上环境会有直接影响的领域。而变更态中的治理技术,则可分为无损上下线和全链路灰度两大部分。由此也可见无损上线的重要性。
面对如此重要的无损上线功能,虽然功能在正式发布后经过了多年打磨,但因为微服务治理技术面临的主要难题是与众多技术以及不同的配置方式的相互整合,难免出现不相兼容匹配的情况。当出现这种问题时,除了产品的优化改进外,从产品原理角度理解,进而按照最佳方式使用,也是关键。
实现无损上线的三大功能
本节将再对 MSE 无损上线进行介绍,以帮助大家用好此特性。
MSE 服务治理无损上线特性提供了三种功能,分别是延迟注册、小流量服务预热和就绪检查。
服务延迟注册采用被动等待的策略,以便在引入外部服务调用前,应用内部组件已完成初始化。 现代应用所依赖的外部服务和技术众多,导致内部组件众多,且关系复杂,最终导致生命周期的复杂化。在这种情况下,通过增加等待时间,以是应用在提供服务前完成初始化,便成为最简单的选择。
但有一些组件,如内置了开启延迟初始化的连接池、线程池的组件,必须通过真实调用才能触发组件初始化。但直接放入全量调用,有难免产生大面积的服务抖动。此时便需要第二种功能,服务小流量预热。 小流量预热方法通过在服务消费端根据各个服务提供者实例的启动时间计算权重,结合负载均衡算法,控制刚启动应用流量随启动时间逐渐递增到正常水平的这样一个过程,帮助刚启动运行的服务进行预热。需要微服务 Comsumer 和 Provider 都有 MSE 服务治理功能纳管才能实现。如同服务延迟注册的时长一样,服务小流量预热的时长也没有统一标准,而是需要根据线上实际情况,以及测试结果,通过观察错误率、RT 等指标,逐步调整而得。
此外, MSE 无损上线还提供了一套进阶能力,来解决 K8s 场景下,服务变更潜在的流量损失和 RT 升高的问题。在 K8s 滚动发布应用时,如果发布中的应用,其 readiness 探测已经成功,则 K8s 会认为当前应用已经做好准备,并把流量路由到这个应用中。再按照默认的滚动发布策略,老的节点就会被下线。在这个前提下,我们就应该考虑好,readiness 探测通过后,到底有没有准备好接收流量?
无损上线功能考虑到这个场景,提供了一套内置的就绪检查。如果用户使用了无损上线提供的就绪检查,那么 K8s readiness 会在服务注册完毕后,才会通过,这样可以保证至少正在上线的应用已经注册到注册中心,可以被消费者应用发现和调用,避免了新节点还没注册,老节点就被下线,进而带来的消费者应用发起调用时,出现没有可用节点的问题。
此外,在 K8s 上服务发布时,可能会在一个比较短的时间内,将所有老节点替换成新启动的节点。而提供服务的这些新节点,可能还没有进行充分预热,此时系统的整体 rt 难免会变长。所以无损上线还提供了通过就绪检测前完成服务预热的功能,可以保证按照 K8s 默认滚动发布策略的情况下,新创建的节点在预热结束之后,老 Pod 才会被 K8s 下线,避免了平均 RT 升高的问题。
如需使用这些进阶功能,您需要将就绪检查配置成 MSE 服务治理提供的就绪检测端口,如下:
云原生网关的无损上线能力
除了上述场景,微服务网关也是一类需要考虑无损上线能力的场景。阿里云 MSE 云原生网关产品,也提供了相应的特性。
应用发布经常会在网关上看到 5XX 错误码上升,影响客户体验。这是因为应用启动瞬间缓存没有 ready 等原因,突然大量流量涌入会导致处理慢,请求 RT 上涨,最终导致客户调用服务超时,并且用户流量越大这个问题越严重。为了解决这个问题,MSE 云原生网关也提供了服务预热能力,使用方法如下:
步骤 1: 在服务管理中配置负载均衡策略,将预热时间改成 60s(60s 内逐渐把流量调大,该值为经验值)。
步骤 2: 假设后端有 2 个 Endpoint 滚动发布,节点逐步从低到高调整权重,放大流量,从而用小流量预热系统,保证上线流量无损。
🔔 注: 在观察上述预热过程中,有用户反馈错误码减少的同时,没有看到曲线平缓上升过程。通常原因是观测大盘的采样周期是分钟级,看不到 60s 内的变化情况。如果希望看到观测效果,可以把预热时间调大,或者把采样周期调整到秒级(会导致可观测成本增加)。
小结
在后续版本的 MSE 微服务治理中,将考虑前述的改进措施,避免显式配置,从而解决服务预热误判问题的同时,简化使用 ,降低门槛。
进一步,比微服务治理功能更重要是,MSE 所代表的技术如何更好地推动云原生落地。目前无损上线特性所提供的功能,是通过增加自适应的时间来提供更稳定的服务,这与云原生的弹性伸缩强调的快速响应有所不同。如何在快速和稳定之间寻找一个最佳的平衡,一直是云原生技术人不得不面对的重要课题。
不过目前而言,微服务治理和弹性伸缩技术还处于技术普及阶段,尤其是正在进行数字化转型的行业和领域。重点仍是普及和用好 MSE 微服务引擎的各种功能。因此,希望大家能多多使用 MSE 微服务治理,包括无损上线在内的各项功能。如遇问题,可通过各种服务渠道,如工单或企业技术服务等,反馈问题。阿里云将和客户一起共同推动云原生技术发展。
相关链接:
[1] 无损上线
https://help.aliyun.com/zh/mse/user-guide/graceful-start