Serverless 架构下的服务优雅下线实践( 二 )

  • 服务发布前 , 消费者根据负载均衡规则调用服务提供者 , 业务正常 。
  • 服务提供者 B 需要发布新版本 , 先对其中的一个节点进行操作 , 首先是停止 Java 进程 。
  • 服务停止过程 , 又分为主动注销和被动注销 , 主动注销是准实时的 , 被动注销的时间由不同的注册中心决定 , 最差的情况会需要 1 分钟 。
  • 如果应用是正常停止 , Spring Cloud 和 Dubbo 框架的 Shutdown Hook 能正常被执行 , 这一步的耗时可以忽略不计 。
  • 如果应用是非正常停止 , 比如直接使用 kill -9 停止 , 或者 Docker 镜像构建的时候 Java 应用不是 1 号进程且没有把 kill 信号传递给应用 。 那么服务提供者不会主动去注销服务节点 , 而是在超过一段时间后由于心跳超时而被动地被注册中心摘除 。
  • 服务注册中心通知消费者 , 其中的一个服务提供者节点已下线 。 包含推送和轮询两种方式 , 推送可以认为是准实时的 , 轮询的耗时由服务消费者轮询间隔决定 , 最差的情况下需要 1 分钟 。
  • 服务消费者刷新服务列表 , 感知到服务提供者已经下线了一个节点 , 这一步对于 Dubbo 框架来说不存在 , 但是 Spring Cloud 的负载均衡组件 Ribbon 默认的刷新时间是 30 秒, 最差情况下需要耗时 30 秒 。
  • 服务消费者不再调用已经下线的节点 。
从第 2 步到第 6 步的过程中 , Eureka 在最差的情况下需要耗时 2 分钟 , Nacos 在最差的情况下需要耗时 50 秒 。 在这段时间内 , 请求都有可能出现问题 , 所以发布时会出现各种报错 。
经过上面的分析 , 我们看 , 在传统发布流程中 , 客户端有一个服务调用报错期 , 原因就是客户端没有及时感知到服务端下线的实例造成的 , 这种情况主要是因为服务提供者借助注册中心通知消费者来更新服务提供者列表造成的 , 那能不能绕过注册中心 , 服务提供者直接通知服务消费者呢?答案是肯定的 , SAE 主要做了两件事情 。

Serverless 架构下的服务优雅下线实践
本文插图
  • 服务提供者应用在发布前后主动向注册中心注销应用 , 并将应用标记为已下线的状态;将原来的停止进程阶段 注销服务变成了 prestop 阶段注销服务 。
  • 在接收到服务消费者请求时 , 首先会正常处理本次调用 , 并通知服务消费者此节点已下线 , 服务消费者会立即从调用列表删除此节点;在这之后 , 服务消费者不再调用已经下线的节点 。 这是将原来的依赖于 注册中心推送 , 变成了服务提供者直接通知消费者从调用列表中摘除自己 。
通过上面这个方案 , 就使得下线感知的时间大大减短 , 从原来的分钟级别做到准实时 , 确保您的应用在下线时能做到业务无损 。
分批发布和灰度发布
上面介绍的是 SAE 在处理优雅下线方面的一些能力 , 在应用发布的过程中 , 只有实例的优雅下线是不够的 , 需要有一套配套的发布策略 , 保证我们新业务是可用的 , SAE 提供了分批发布和灰度发布的能力 , 可以使得应用的发布过程更加省心省力;
我们先介绍下灰度发布 , 某应用包含10个应用实例 , 每个应用实例的部署版本为Ver.1版本 , 现需将每个应用实例升级为Ver.2版本 。
Serverless 架构下的服务优雅下线实践
本文插图
从图中可以看出 , 在发布的过程中先灰度2台实例 , 在确认业务正常后 , 再分批发布剩余的实例 , 发布的过程中始终有实例处于运行状态 , 实例升级过程中依照上面的方案 , 每个实例都有优雅下线的过程 , 这就保证了业务无损 。
再来看下分批发布 , 分批发布支持手动、自动分批;还是上面的10个应用实例 , 假设将所有应用实例分3批进行部署 , 根据分批发布策略 , 该发布流程如图所示 , 就不再具体介绍了 。


推荐阅读