springcloud如何实现服务的平滑发布
在之前的文章中我们提到服务的优雅下线,见:
SpringCloud服务如何在Eureka安全优雅的下线
但这个对于ribbon调用其实是不平滑的,shutdown请求到后服务就马上关闭了,服务消费此时未感应到服务下线了,会仍然往这个服务发送请求,从而导致报错。
简介方案有:一、开启重试(前提是保证接口做好幂等处理)。
二、使用pause来下线服务(推荐)
操作步骤如下:
1、 服务提供方配置
|
后台端点禁用安全校验 management.security.enabled=false # 开启服务暂停端点 endpoints.pause.enabled=true # 禁用密码验证 endpoints.pause.sensitive=false |
由于这些管理端点比较敏感需要加一个filter来过滤IP白名单
代码参考:对actuator的管理端点进行ip白名单限制(springBoot添加filter)
2、 服务消费者
|
# 2秒拉取最新的注册信息 eureka.client.registry-fetch-interval-seconds=2 # 2秒刷新ribbon中的缓存信息 |
3、发布流程
|
Curl –X POST http://127.0.0.1:端口/pause Sleep 6S Kill -9 Java –jar xx.jar启动服务 curl -I -m 10 -o /dev/null -s -w %{http_code} http://127.0.0.1:端口/health 来检测是否是200,持续N秒,如果失败则需要回滚发布并终止后续节点的发布。 |
说明:这里的sleep的最大理论值为: eureka.client.registry-fetch-interval-seconds + (ribbon.ServerListRefreshInterval+eureka.client.registry-fetch-interval-seconds) = 6S;
后面括号里的相加是因为这2个定时有可能恰好非常巧的错过了才会出现,为了安全起见我们可以基于上述的公式再加个一两秒。
为什么要访问/health呢?主要是为了对服务进行预热(主要是数据库连接池/jedis连接池等),这样当超时时间很多的服务在第一次请求时不会出现超时。
4、eureka
|
# 5秒清理一次过期的注册信息 # 如果是按照上面的流程来执行发布则其实可以不配,使用默认值 eureka.server.eviction-interval-timer-in-ms=5000 # 关闭自我保护 # 内网服务不需要进行分区保护 eureka.server.enable-self-preservation=false # 服务注册5秒即可被发现 |
三、扩展tomcat的shutdownhook(不推荐,如果切换为成其他容器则无效了)
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit; import org.apache.catalina.connector.Connector;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextClosedEvent; import lombok.extern.slf4j.Slf4j; /**
* 优雅关闭tomcat
* @author yangzl
* @data 2019年4月2日
*
*/
@Slf4j
@Configuration
public class TomcatGracefulShutdown implements TomcatConnectorCustomizer,
ApplicationListener<ContextClosedEvent> {
// 有个等待时间的配置
@Autowired
private ShutdownProperties properties; private volatile Connector connector; @Override
public void customize(Connector connector) {
this.connector = connector;
} @Override
public void onApplicationEvent(final ContextClosedEvent event) {
LocalDateTime startShutdown = LocalDateTime.now();
LocalDateTime stopShutdown = LocalDateTime.now();
try {
log.info("We are now in down mode, please wait " + properties.getWaitSecond() + " second(s)..."); if (connector == null) {
log.info("We are running unit test ... ");
Thread.sleep(properties.getWaitSecond() * 1000);
return;
}
connector.pause(); final Executor executor = connector.getProtocolHandler().getExecutor();
if (executor instanceof ThreadPoolExecutor) {
log.info("executor is ThreadPoolExecutor");
final ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
threadPoolExecutor.shutdown();
if (!threadPoolExecutor.awaitTermination(properties.getWaitSecond(), TimeUnit.SECONDS)) {
log.warn("Tomcat thread pool did not shut down gracefully within " + properties.getWaitSecond() + " second(s). Proceeding with force shutdown");
} else {
log.debug("Tomcat thread pool is empty, we stop now");
}
}
stopShutdown = LocalDateTime.now();
} catch (final InterruptedException ex) {
log.error("The await termination has been interrupted : " + ex.getMessage());
Thread.currentThread().interrupt();
} finally {
final long seconds = Duration.between(startShutdown, stopShutdown).getSeconds();
log.info("Shutdown performed in " + seconds + " second(s)");
}
}
}
调用shutdown时tomcat会此等待M秒后再退出,效果基本等同于第二种方案,但最终退出时有时会报错,而且也仅仅适配tomcat,不够通用。
springcloud如何实现服务的平滑发布的更多相关文章
- springcloud添加自定义的endpoint来实现平滑发布
在我之前的文章 springcloud如何实现服务的平滑发布 里介绍了基于pause的发布方案. 平滑发布的核心思想就是:所有服务的调用者不再调用该服务了就表示安全的将服务kill掉. 另外actu ...
- 通过Nginx、Consul、Upsync实现动态负载均衡和服务平滑发布
前提 前段时间顺利地把整个服务集群和中间件全部从UCloud迁移到阿里云,笔者担任了架构和半个运维的角色.这里详细记录一下通过Nginx.Consul.Upsync实现动态负载均衡和服务平滑发布的核心 ...
- 实战SpringCloud响应式微服务系列教程(第二章)
接上一篇:实战SpringCloud响应式微服务系列教程(第一章) 1.1.2背压 背压是响应式编程的核心概念,这一节也是我们了解响应式编程的重点. 1.背压的机制 在生产者/消费者模型中,我们意识到 ...
- 实战SpringCloud响应式微服务系列教程(第十章)响应式RESTful服务完整代码示例
本文为实战SpringCloud响应式微服务系列教程第十章,本章给出响应式RESTful服务完整代码示例.建议没有之前基础的童鞋,先看之前的章节,章节目录放在文末. 1.搭建响应式RESTful服务. ...
- 系统架构设计:平滑发布和ABTesting
平滑发布的介绍 背景 单位的云办公相关系统没有成熟的平滑发布方案,导致每一次发布都是直接发布,dll文件或配置文件的变更会引起站点的重启. 云办公系统的常驻用户有10000+,即使短短半分多钟,也会收 ...
- 一个C#开发者学习SpringCloud搭建微服务的心路历程
前言 Spring Cloud很火,很多文章都有介绍如何使用,但对于我这种初学者,我需要从创建项目开始学起,所以这些文章对于我的启蒙,帮助不大,所以只好自己写一篇文章,用于备忘. SpringClou ...
- wcf服务与web发布时无法访问 几种解决办法
1 如果wcf服务与web发布在同一iis目录下,没有跨域的问题 但发布前要修改 ServiceReferences.ClientConfig 把wcf服务地址改为你发布后的iis的ip地址( ...
- WCF报 当前已禁用此服务的元数据发布的错误
这是 Windows© Communication Foundation 服务. 当前已禁用此服务的元数据发布. 如果具有该服务的访问权限,则可以通过完成下列步骤来修改 Web 或应用程序配置文件以便 ...
- springcloud干货之服务消费者(ribbon)
本章介绍springcloud中的服务消费者 springcloud服务调用方式有两种实现方式: 1,restTemplate+ribbon, 2,feign 本来想一篇讲完,发现篇幅有点长,所以本章 ...
随机推荐
- ActiveMQ挂了,重启一直无法将所有实例启起来的问题
背景 2017年3月29日 下午2-3点时分,工单模块无法访问.跟踪日志发现,ActiveMQ连接不上导致整个工单模块瘫痪: 首先判断可能是系统需要然后尝试重启工单模块,重新启动工单模块,结果:重启 ...
- 使用 PySide2 开发 Maya 插件系列 总览
使用 PySide2 开发 Maya 插件系列 总览 使用 PySide2 开发 Maya 插件系列一:QT Designer 设计GUI, pyside-uic 把 .ui 文件转为 .py 文件 ...
- pageHelper多个sql分页
之前有个需求,在一个页面中需要有多个sql分页查询然后放到一个list中,展示,但是会出现一个bug,就是每次分页都会展示第一条查出的所有的数据: 第一页 第二页 因为是截的生产环境,第一条数据被处理 ...
- Trace 2018徐州icpc网络赛 (二分)(树状数组)
Trace There's a beach in the first quadrant. And from time to time, there are sea waves. A wave ( xx ...
- python数据结构之栈
栈 栈(stack),有些地方称为堆栈,是一种容器,可存入数据元素.访问元素.删除元素,它的特点在于只能允许在容器的一端(称为栈顶端指标,英语:top)进行加入数据(英语:push)和输出数据(英语: ...
- Python itertools模块详解
这货很强大, 必须掌握 文档 链接 http://docs.python.org/2/library/itertools.html pymotw 链接 http://pymotw.com/2/iter ...
- webstorm过期最新激活方法
打开webstorm 注册时,在打开的License Activation窗口中选择“License server”,在输入框输入下面的网址:http://idea.iteblog.com/key.p ...
- KO的使用例子
var model; function QueuingRecordViewModel() { model = this; // model = this 不可缺少 model.info = ko.ob ...
- BZOJ.1566.[NOI2009]管道取珠(DP 思路)
BZOJ 洛谷 考虑\(a_i^2\)有什么意义:两个人分别操作原序列,使得得到的输出序列都为\(i\)的方案数.\(\sum a_i^2\)就是两人得到的输出序列相同的方案数. \(f[i][j][ ...
- OI常用重载运算符
用STL时经常用到 PS:这里有个巨坑,把重载写在STL里常数会爆炸,分分钟大数据TLE 所以就把重载放在结构体里啦 //以priority_queue的重载为例 //priority_queue默认 ...