开发者学堂课程【微服务应用如何实现无损上下线:微服务应用如何实现无损上下线】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/974/detail/14895
微服务应用如何实现无损上下线
内容介绍
一、应用上下线过程当中出现流量有损的背景原因
二、mse 实现应用发布无损上下线的方案
三、mse 实现应用无损上下线的最佳时间 demo 进行演示
一、应用上下线过程当中出现流量有损的背景原因
1. 应用的事故通常发生在应用上下线的过程中,事故的原因可能是因为研发代码出错,导致上下线的过程中信息系统不可用,但即使代码已经做了很好的检查,实际在应用发布的过程中,还是会出现短暂的服务使用报错或者服务不可用的问题。
原因:在流量高峰的时候,报错会多一点,在流量较小时,报错会少一点,所以很多人选择在应用流量特别小的时候,进行应用发布规避线上的问题。
2.常见的应用在上下线的过程出现这个服务报错的原因
(1)服务无法及时下线:服务下线动作不能被上游的消费应用实时感知,在 SpringCloud 应用 Consumer 感知注册中心服务列表存在延时,导致应用下线后在一段时间内仍然调用下线应用。
(2) 例如:Consumer是通过定时的,默认30秒在中心获取最新的服务实例列表信息,假设提供在 ProviderA 下线的时候,被服务消费者感知到存在一定的延时,在延时期间,如果有流量调用,会通过本地的缓存里面调用服务的列表,这个时候就会出现调用已下线的 ProviderA ,出现流量有损的问题。
(3)
(4) 初始化慢:新启动应用需要进行资源加载,大规模流量直接请求过来,导致刚启动应用被流量击垮!
例如:
是K8S直部署的一个应用。在另一个版本弹起来时pllot被流量击垮,问题产生的原因是资源初始化慢。
demo的演示,在第一次调用的时候,因为存在reban核心类的第一次调用,才会进行核心类的初始化。因此第一次调动的延时很长,第一次调用完成之后,后续的调用时间很短,因为存在第一次调用很大的应用初始化时间,因此如果有大量流量之间像刚启动的应用请求,就会出现大量的请求的响应超时。大量的请求的延时阻塞导致刚启动的实例的硬件资源如CPU 、内存等,被消耗殆尽导致刚启动应用被流量击垮。
(3)注册太早:服务存在异步资源加载问题,尽管应用的一些类已经完成了初始化,当服务还未初始化完成就被注册到注册中心,导致响应慢出现请求报错。
(4)发布态与运行态未对齐:使用K8s的滚动发布功能进行应用发布,新应用还未注册到注册中心,老应用实例就被下线,导致无服务可用。
本质:K8s 的滚动发布机制和微服务的应用的生命周期,没有关联关系,K8s 滚动发布,结合就绪探针的机制,能够感知到应用的某个端口启动之后,再进行下批次的应用发布。
对于微服务应用,应用 redio 的就绪状态通常不是应用的某个端口启动就处于就绪状态,而是需要应用自身已经完初始化,并且注册到注册中心,以及能够被上游调用的时候,才处就绪态,可以进行之后的发布。
因此k8s的生命周期与微服务的生命周期没有绑定的关系。因此出现假设应用的某端口已启动,但此时应用没有注册到注册中心,但K8s认为这个应用启动就序,便下线原有的实例,但新的实例也没有上线。因而调用的消费者发现没有可用的实例列表,出现noprovide 的问题。
二、mse 实现应用发布无损上下线的方案
1.无损下线
(1)无损下线背景原因:
服务端:下线动作不能被客户端实时感知,原因为服务端可能已下线,但由于通过新的跳槽时机感知服务端下线的形式会有一定的延时,可能在之后才能感知到服务端下线。
客户端:通过拿取注册中心里面服务列表的方式感知服务端下线,在 SpringCloud 里面默认的拿取动作为30秒一次,因此感知到服务端下线的时间更长,。在真实服务下线到被客户端感知到服务下线的时间内,如果客户端流量比较大,再进行调用,就会出现服务的调用报错。
(2)解决:咨询等待和主动通知的无损下线的方案。首先通过 mse的 java Agent 技术,每一个应用会注入增强,通过自检码的方式增加额外的逻辑,比如说是咨询等待、通知等。
如图所示,例如提供者A,要进行下线时,不会出现没有使用无损下线时马上就下线的情况,会有默认的等待时间。在等待的时间之内,会做一些下线的动作,让上游消费者能够及时感知,避免调用报错。
(3)步骤:
消费者正常调用提供者A,提供者A会在下线之前会通过prestop,实现向注册中心反注册的动作,注册中心能够实时感到提供者A已经下线。
向注册中心进行在反注册之后,提供者A在主动通知的时间之后的等待时间内,会将接收的请求的流量进行记录,并对这些流量的返回值做一些特殊的处理,对流量的发起的消费者,进行主动通知。告诉发送请求的消费者,提供者A已经下线,之后不用调提供者A。收到请求的消费者会把提供者A标记为下线状态,同时,会在注册中心发起拉取服务列表的信息,拉取到最新的服务列表,在下次调用的时不会再调用下线的提供者A,会去调用其他的提供者。
2.无损上线
(1)无损上线原因:
刚启动应用需要一定的初始化时间,但在发布过程中因为流量较大给予初始化时间较短,导致大量的请求来不及初始化,产生比较高的延时,造成请求阻塞,因此应用挤压导致发布的事故。
(2)解决方法:小流量预热
Dubbo 的小流量预热:
小流量预热的效果类似下图所示,正常情况下假设没有小流量预热的实例发布过程中,上线就会接收到正常的Qps值,但经过小流量预热后,应用发布的过程中,接受的流量在预热的周期内缓慢增加,因此通过此机制对刚启动发布的应用进行保护。
(3)原理:
在服务提供端,通过用户配置预热时间,以及权重等参数,通过注册中心被消费者感知,消费者通过预热的附带均衡的算法,实时在调用时刻计算每一个应用的提供者的权重,对于刚启动的应用,它的 StartTime 离 now 比较近,所以分子很小,然最终计算的权重比较小,对于刚启动的应用,所分配的流量就会比较小,然后实现对保护的效果。
(4)Dubbo 的预热并没有解决问题,它是恒定的预热曲线,在使用的过程中,它的普适性不强,对于一些特殊的应用,有时反而会带来问题。
问题:
SpringCloud 应用不能实时感知注册中心实例变化,如何解决因此出现的预热时长低于预期问题?
服务预热如何进行服务预热可视化?
服务预热如何适配云原生应用场景?
Dubbo 采用线性的预热曲线,刚开始应用启动时流量尽可能小,他就要需要把预热的时间设置的比较长,但预热时间长使应用的发布周期变长,会对应用发布的效率造成影响
场景:
启动流量小,预热曲线是线性,预热时长会长,所以设置为9 min
一般滚动发布3批,每批间隔5 min ,批次数1,2,3。
第1批: 0 min ,1个实例预热(流量缓慢增加),5个实例正常(小流量预热,通过负载均衡,把原来要分配给预热实例的多余的流量,均衡到其他的正常或是预热比较久的实例),正常实例能抗住多余流量
第2批: 5 min ,第一个实例是预约9 min ,5 min 时还没结束,所以3个实例预热,3个实例正常,正常实例勉强能抗住多余流量
第3批:10 min ,第一个实例是预约9 min ,所以10 min 时结束,所以5个实例预热,1个实例正常,设置的cpu和内存不是特别大,没法抵挡,原本要分配给这5个预热实例的流量,导致正常机器宕机。
诉求:希望第1 min,流量尽可能小,预热过程能够快速的收敛,可能在第二分钟时马上恢复正常。但是,采用Dubbo的服务预热方法,因为是线性的曲线,无法做到。如果刚开时流量较小,恢复正常的时间就要比较长,基于这个背景,提出基于高阶曲线的可快速收敛预热过程的预热方法。
在 mse 里,提供让用户就是配置一些高级的预热曲线,应用在不同的场景,让所有的应用能够最大限度利用服务预热来对应用进行保护,而不是出现相关分析的问题。
除了对Dubbo的预热进行了改进及产品化以外,在实现无损上线当中的小流量域的过程中,针对 SpringCloud 的应用做了一些处理,或对怎样去实现一个服务域的可视化的能力的增强。
(5)mse 提供的无损上线能力的完整介绍:
第一部分:对于刚启动的应用,有些应用需要资源初始化时间较长,一些连接池需要创建,无损上线的方案通过javaAgent的方式,能够帮助用户进行初始化资源的建立
第二部分:在服务注册过程中有时服务注册太早,应用里面有些服务,需要一些异步的资源加载。未加载完成在线上接收流量,会出现流量阻塞,导致应用宕机。针对doubbo应用和SpringCloud应用都支持来延迟注册的能力解决问题
第三部分:结合K8s就绪检查机制,能够让K8s配置就绪探针与微服务注册完成关联,感知到服务是否注册完成。
第四部分:小流量服务预热,预热模型支持动态调节,支持高阶模型配置,满足更多复杂应用预热场景需求;预热过程支持关联K8sreadiness检查,无缝支持云原生应用发布场景,让服务预热之后,K8s发布之后,就绪检查才会通过。