当前位置: 首页 > 后端技术 > Java

SpringCloud微服务优雅下线+灰度发布的正确姿势,写的好!

时间:2023-04-01 13:22:48 Java

前言在生产环境中,如何保证服务升级时不影响用户体验是一个非常重要的问题。如果我们在升级服务的时候,会导致服务一段时间不可用,不够优雅。那么什么是优雅呢?主要是指在服务升级时,整个服务不会中断,让用户感知不到,从而不影响用户体验。这很优雅。其实优雅下线是目的,不是手段。这是一个相对的概念。比如killPID和kill-9PID都是暴力杀服务。与kill-9PID相比,killPID是优雅的。但是如果单拿killPID来说,能不能说是优雅的离线策略呢?绝对不是,这是事实。所以,本文所描述的优雅注销只能称为“比较优雅的注销”,但相对于暴力杀服务来说已经足够优雅了。常见的优雅方案主要有优雅离线和灰度发布。事实上,灰度发布的范围已经包含了优雅的离线。最后,本文主要讲一下基于SpringCloud和Euraka的优雅离线和灰度发布。优雅下线常见下线方式一:killPID用法:killjavaprocessID这种方式使用了SpringBoot应用的Shutdownhook,应用本身的下线也是优雅的,但是如果你的服务发现组件使用的是Eureka的话,那么在其他应用感知到该服务下线之前,默认会有最多90秒的延迟,也就是说:在实例下线后的90秒内,其他服务可能仍然会调用下线的实例。因此,这种方法是不优雅的。方法二:/shutdown端点SpringBoot提供了/shutdown端点,可以用来实现优雅关机。使用方法:在你要下线的应用的application.yml中添加如下配置启用/shutdown端点暴露:management:endpoint:shutdown:enabled:trueendpoints:web:exposure:include:shutdown发送一个POST请求到/shutdown端点curl-Xhttp://你要停止的服务地址/actuator/shutdown这个方法的本质和方法一一样,也是借助于SpringBoot应用程序的关闭挂钩。SpringBoot的基础就不介绍了。推荐阅读这个免费教程:https://github.com/javastacks/spring-boot-best-practice方法三:/pause端点SpringBoot应用提供了一个/pause端点,可以用来实现优雅离线.使用方法:在需要下线的应用程序的application.yml中添加配置,以启用和暴露/pause端点:management:endpoint:#启用暂停端点pause:enabled:true#启用重启端点,之所以要开启重启端点是因为暂停端点的开启依赖于重启端点的开启restart:enabled:trueendpoints:web:exposure:include:pause,restart发送POST请求到/actuator/pause端点:curl-XPOSThttp://你要停止的服务实例执行address/actuator/pause后的效果类似下图:EurekaServer已经被标记为DOWN,但是应用本身仍然可以正常对外服务。在SpringCloud中,Ribbon做负载均衡时,只会加载到标记为UP的实例上。利用这两点,你可以:首先使用/pause端点将应用程序标记为DOWN下线,但并不真正停止应用程序;然后在一定时间后(比如90秒,或者自己做一个监控,看到流量变成0之后),停止应用,比如kill应用。缺点&限制方法四:/service-registry端点的使用方法:在离线应用的application.yml中添加配置,暴露/service-registry端点:management:endpoints:web:exposure:include:service-registrysendsPOST请求到/actuator/service-registry端点:curl-X"POST""http://localhost:8000/actuator/service-registry?status=DOWN"\-H"Content-Type:application/vnd.spring-boot.actuator.v2+json;charset=UTF-8》执行后效果类似下图:优雅的注销方式上面我们介绍了四种常见的注销方式。相比之下,方法4是一种更优雅的下线方式。在实际项目中,我们可以先使用/service-registry端点将服务标记为DOWN,然后监控服务的流量。当流量为0时,可以升级服务。当然,这里假设我们部署了多个服务实例。当一个服务实例宕机时,其他服务实例仍然可以提供服务。如果只部署一个服务,那么优雅与否的讨论就没有那么重要了。除了上面的离线方式,还有一种方式就是使用EurekaAutoServiceRegistration对象来达到优雅离线的目的。当执行eurekaAutoServiceRegistration.start()方法时,当前服务向Eureka注册中心注册该服务;当执行eurekaAutoServiceRegistration.stop()方法时,当前服务会向Eureka注册中心注销,注册中心收到请求后会将服务从Eureka注册中心删除,从注册列表中删除。示例代码如下:@RestController@RequestMapping(value="/graceful/registry-service")publicclassGracefulOffline{@AutowiredprivateEurekaAutoServiceRegistrationeurekaAutoServiceRegistration;@RequestMapping("/online")publicStringonline(){this.eurekaAutoServiceRegistration.start();return"执行在线方法,在线成功。";}@RequestMapping("/offline")publicStringoffline(){this.eurekaAutoServiceRegistration.stop();return"执行离线方法,离线成功。";}}到这里,我们介绍了两种比较优雅的下线方式。具体如何操作,我们可以根据实际情况进行封装,或者使用自动化脚本实现更优雅的下线方式。Blue-GreenDeployment蓝绿部署,英文全称为BlueGreenDeployment,是一种可以保证系统不间断上线的部署方式。如何保证系统提供不间断的服务?即同时部署两个集群,对外只提供一个集群的服务。当需要升级时,切换集群进行升级。蓝绿部署无需停机且风险较小。大致步骤是:部署集群1(初始状态)的应用,将所有外部请求的流量都发送到这个集群,部署集群2的应用。集群2的代码和集群1不同,比如新功能或bug修复等。将流量从集群1切换到集群2。如果集群2测试正常,则删除集群1正在使用的资源(如实例),使用集群2对外提供服务。因为我们在使用蓝绿部署方式的时候需要对流量进行控制,所以需要依赖路由服务,比如Nginx等。滚动部署滚动部署,英文称为RollingUpdate,也是一种可以保证系统不间断上线的部署方式。与蓝绿部署不同,滚动部署不是对外提供服务的非此即彼版本,而是更细粒度的平滑版本升级。如何实现细粒度平滑升级版本?滚动部署只需要一个集群,集群下的不同节点可以独立进行版本升级。比如在一个12节点的集群中,我们一次升级4个节点,将升级后的节点重新投入使用,如此循环往复,直到集群中的所有节点都更新到新版本。与蓝绿部署相比,这种部署方式更节省资源,因为它不需要运行两个集群。但是这种方法也有很多缺点,比如:没有判断OK的环境。通过蓝绿部署,我们可以清楚地知道旧版本是可以的,但是通过滚动发布,我们就不能确定了。修改现有环境。如果你需要回滚,这很困难。比如一个release,我们需要更新100个实例,一次10个实例,每次部署需要5分钟。rollout到第80个实例时,发现问题,需要回滚。这个时候,我们估计要疯了。有时,我们也可能动态扩展系统。如果部署时系统自动扩容/缩容,我们还需要判断哪个节点使用哪个代码。虽然现在有一些自动化运维工具,但还是让人望而却步。并不是说滚动发布不好,有的场景是非常适合滚动发布的。金丝雀部署金丝雀部署,又称灰度部署(或,灰度发布),英文全称为CanaryDeployment,指的是一种能够在黑白之间平滑过渡的发布方式。金丝雀的名字来源于“矿井里的金丝雀”。早在17世纪,英国矿工就发现金丝雀对气体非常敏感,即使空气中有极少量的气体,金丝雀也会停止鸣叫;而当气体含量超过一定限度时,虽然迟钝的人类没有察觉,但金丝雀已经中毒身亡。当时,在采矿设备相对简单的条件下,工人们每次下矿都会带上一只金丝雀,作为遇到险情紧急疏散的“瓦斯检测指标”。我们来看看金丝雀部署的步骤:为部署的每个阶段准备工件,包括:构建工件、测试脚本、配置文件和部署清单文件从负载均衡列表中删除“金丝雀”服务器升级“黄金”“金丝雀”应用(切断原有流量并部署)对应用进行自动化测试,并重新将“金丝雀”服务器加入负载均衡列表(连通性和健康检查)如果“金丝雀”在线使用测试成功,升级其余服务器(或回滚)在金丝雀部署中,路由权重通常根据用户数量设置,例如90%的用户维护旧版本,10%的用户尝试新版本。应用程序不同版本的共存通常与A/B测试结合使用,以测试多个选项。金丝雀部署的一个典型例子是,当我们使用一个应用时,应用邀请我们进行“内测”或“新版本体验”。如果我们同意,那么我们就变成了金丝雀。版权声明:本文为CSDN博主“CG国斌”原创文章,遵循CC4.0BY-SA版权协议,转载请附上原文出处链接及本声明。