往期热门文章:
4 款 MySQL 调优工具,大神都在用! Controller 层代码就该这么写,简洁又优雅! 前言
在生产环境中,如何保证在服务升级的时候,不影响用户的体验,这个是一个非常重要的问题。如果在我们升级服务的时候,会造成一段时间内的服务不可用,这就是不够优雅的。那什么是优雅的呢?主要就是指在服务升级的时候,不中断整个服务,让用户无感知,进而不会影响用户的体验,这就是优雅的。 实际上,优雅下线是目标,而不是手段,它是一个相对的概念,例如 kill PID
和kill -9 PID
都是暴力杀死服务,相对于kill -9 PID
来说,kill PID
就是优雅的。但如果单独拿kill PID
出来说,我们能说它是优雅的下线策略吗?肯定不是啊,就是这个道理。因此,本文讲述的优雅下线仅能称之为“相对的优雅下线”,但相对于暴力的杀死服务,已经足够优雅了。常见的优雅解决方案,主要包括优雅下线和灰度发布。而实际上,灰度发布的范围就已经包含优雅下线了。 最后,在本文中,我们主要讲述基于 Spring Cloud 和 Euraka 的优雅下线以及灰度发布。 优雅下线
常见的下线方式
方式一:kill PID
使用方式:kill java进程ID 该方式借助的是 Spring Boot 应用的 Shutdown hook
,应用本身的下线也是优雅的,但如果你的服务发现组件使用的是 Eureka,那么默认最长会有 90 秒的延迟,其他应用才会感知到该服务下线,这意味着:该实例下线后的 90 秒内,其他服务仍然可能调用到这个已下线的实例。因此,该方式是不够优雅的 。方式二:/shutdown端点
Spring Boot 提供了 /shutdown
端点,可以借助它实现优雅停机。使用方式:在想下线应用的application.yml中添加如下配置,从而启用并暴露 /shutdown
端点:management:
endpoint:
shutdown:
enabled: true
endpoints:
web:
exposure:
include: shutdown发送 POST 请求到/shutdown端点 curl -X http://你想停止的服务地址/actuator/shutdown
该方式本质和方式一是一样的,也是借助 Spring Boot 应用的 Shutdown hook 去实现的。 方式三:/pause端点
Spring Boot 应用提供了 /pause
端点,利用该端点可实现优雅下线。使用方式:在想下线应用的application.yml中添加配置,从而启用并暴露 /pause
端点:management:
endpoint:
# 启用pause端点
pause:
enabled: true
# 启用restart端点,之所以要启用restart端点,是因为pause端点的启用依赖restart端点的启用
restart:
enabled: true
endpoints:
web:
exposure:
include: pause,restart发送 POST 请求到 /actuator/pause
端点:curl -X POST http://你想停止的服务实例地址/actuator/pause
执行后的效果类似下图: 如图所示,该应用在 Eureka Server 上的状已被标记为DOWN,但是应用本身其实依然是可以正常对外服务的。在 Spring Cloud 中,Ribbon 做负载均衡时,只会负载到标记为UP的实例上。 利用这两点,你可以:先用 /pause
端点,将要下线的应用标记为DOWN,但不去真正停止应用;然后过一定的时间(例如 90 秒,或者自己做个监控,看当前实例的流量变成 0 后)再去停止应用,例如kill
应用。缺点 & 局限 方式四:/service-registry端点
使用方式:在想下线应用的application.yml中添加配置,从而暴露 /service-registry
端点:management:
endpoints:
web:
exposure:
include: service-registry发送 POST 请求到 /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"实行后的效果类似如下图: 优雅的下线方式
在上文中,我们讲述了四种常见的下线方式,对比来看,方式四 是一种比较优雅的下线方式。 在实际项目中,我们可以先使用 /service-registry
端点,将服务标记为DOWN,然后监控服务的流量,当流量为 0 时,即可升级该服务。当然,这里假设我们部署了多个服务实例,当一个服务实例DOWN掉之后,其他服务实例仍然是可以提供服务的,如果就部署一台服务的话,那么讨论优不优雅就没那么重要了。除了上述的下线方式之外,还有一种利用 EurekaAutoServiceRegistration
对象达到优雅下线的目标。
-
执行 eurekaAutoServiceRegistration.start()
方法时,当前服务向 Eureka 注册中心注册服务; -
执行 eurekaAutoServiceRegistration.stop()
方法时,当前服务会向 Eureka 注册中心进行反注册,注册中心收到请求后,会将此服务从注册列表中删除。
@RestController
@RequestMapping(value = "/graceful/registry-service")
public class GracefulOffline {
@Autowired
private EurekaAutoServiceRegistration eurekaAutoServiceRegistration;
@RequestMapping("/online")
public String online() {
this.eurekaAutoServiceRegistration.start();
return "execute online method, online success.";
}
@RequestMapping("/offline")
public String offline() {
this.eurekaAutoServiceRegistration.stop();
return "execute offline method, offline success.";
}
}
灰度发布
蓝绿部署
-
部署集群 1 的应用(初始状态),将所有外部请求的流量都打到这个集群上 -
部署集群 2 的应用,集群 2 的代码与集群 1 不同,如新功能或者 Bug 修复等 -
将流量从集群 1 切换到集群 2 -
微信搜索公众号:架构师指南,回复:架构师 领取资料 。
-
如集群 2 测试正常,就删除集群 1 正在使用的资源(例如实例),使用集群 2 对外提供服务
滚动部署
-
没有一个确定 OK 的环境。使用蓝绿部署,我们能够清晰地知道老版本是 OK 的,而使用滚动发布,我们无法确定。 -
修改了现有的环境。 -
如果需要回滚,很困难。举个例子,在某一次发布中,我们需要更新 100 个实例,每次更新 10 个实例,每次部署需要 5 分钟。当滚动发布到第 80 个实例时,发现了问题,需要回滚。这时,我们估计就要疯了。 -
有的时候,我们还可能对系统进行动态伸缩,如果部署期间,系统自动扩容/缩容了,我们还需判断到底哪个节点使用的是哪个代码。尽管有一些自动化的运维工具,但是依然令人心惊胆战。
金丝雀部署
-
准备好部署各个阶段的工件,包括:构建工件,测试脚本,配置文件和部署清单文件 -
从负载均衡列表中移除掉“金丝雀”服务器 -
升级“金丝雀”应用(切断原有流量并进行部署) -
对应用进行自动化测试 -
将“金丝雀”服务器重新添加到负载均衡列表中(连通性和健康检查) -
如果“金丝雀”在线使用测试成功,升级剩余的其他服务器(否则就回滚)
转自:CG国斌
链接:https://blog.csdn.net/qq_35246620/article/details/109166722
关注公众号:Java后端编程,回复下面关键字
要Java学习完整路线,回复 路线
缺Java入门视频,回复: 视频
要Java面试经验,回复 面试
缺Java项目,回复: 项目
进Java粉丝群: 加群
PS:如果觉得我的分享不错,欢迎大家随手点赞、在看。
(完) 加我"微信" 获取一份 最新Java面试题资料
请备注:666,不然不通过~
最近好文
最近面试BAT,整理一份面试资料《Java面试BAT通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。 获取方式:关注公众号并回复 java 领取,更多内容陆续奉上。 明天见(。・ω・。)ノ♡ 本篇文章来源于微信公众号:程序IT圈
原创文章,作者:software,如若转载,请注明出处:https://www.sldh123.com/7454.html