在之前的文章中我们提到服务的优雅下线,见:

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中的缓存信息
ribbon.ServerListRefreshInterval=2000

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秒即可被发现
eureka.server.response-cache-update-interval-ms=5000

三、扩展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如何实现服务的平滑发布的更多相关文章

  1. springcloud添加自定义的endpoint来实现平滑发布

    在我之前的文章  springcloud如何实现服务的平滑发布 里介绍了基于pause的发布方案. 平滑发布的核心思想就是:所有服务的调用者不再调用该服务了就表示安全的将服务kill掉. 另外actu ...

  2. 通过Nginx、Consul、Upsync实现动态负载均衡和服务平滑发布

    前提 前段时间顺利地把整个服务集群和中间件全部从UCloud迁移到阿里云,笔者担任了架构和半个运维的角色.这里详细记录一下通过Nginx.Consul.Upsync实现动态负载均衡和服务平滑发布的核心 ...

  3. 实战SpringCloud响应式微服务系列教程(第二章)

    接上一篇:实战SpringCloud响应式微服务系列教程(第一章) 1.1.2背压 背压是响应式编程的核心概念,这一节也是我们了解响应式编程的重点. 1.背压的机制 在生产者/消费者模型中,我们意识到 ...

  4. 实战SpringCloud响应式微服务系列教程(第十章)响应式RESTful服务完整代码示例

    本文为实战SpringCloud响应式微服务系列教程第十章,本章给出响应式RESTful服务完整代码示例.建议没有之前基础的童鞋,先看之前的章节,章节目录放在文末. 1.搭建响应式RESTful服务. ...

  5. 系统架构设计:平滑发布和ABTesting

    平滑发布的介绍 背景 单位的云办公相关系统没有成熟的平滑发布方案,导致每一次发布都是直接发布,dll文件或配置文件的变更会引起站点的重启. 云办公系统的常驻用户有10000+,即使短短半分多钟,也会收 ...

  6. 一个C#开发者学习SpringCloud搭建微服务的心路历程

    前言 Spring Cloud很火,很多文章都有介绍如何使用,但对于我这种初学者,我需要从创建项目开始学起,所以这些文章对于我的启蒙,帮助不大,所以只好自己写一篇文章,用于备忘. SpringClou ...

  7. wcf服务与web发布时无法访问 几种解决办法

    1   如果wcf服务与web发布在同一iis目录下,没有跨域的问题   但发布前要修改 ServiceReferences.ClientConfig 把wcf服务地址改为你发布后的iis的ip地址( ...

  8. WCF报 当前已禁用此服务的元数据发布的错误

    这是 Windows© Communication Foundation 服务. 当前已禁用此服务的元数据发布. 如果具有该服务的访问权限,则可以通过完成下列步骤来修改 Web 或应用程序配置文件以便 ...

  9. springcloud干货之服务消费者(ribbon)

    本章介绍springcloud中的服务消费者 springcloud服务调用方式有两种实现方式: 1,restTemplate+ribbon, 2,feign 本来想一篇讲完,发现篇幅有点长,所以本章 ...

随机推荐

  1. day40 mycql 视图,触发器,存储过程,函数

    视图,触发器,存储过程,自定义函数 -- 回顾 1.mysql 约束 1.非空 not null 2. 主键约束 primary key 3. 唯一约束 unique 4. 外键约束 foreign ...

  2. Raspberry Camera详解+picamera库+Opencv控制

    使用树莓派的摄像头,将树莓派自身提供的picamera的API数据转换为Python Oencv可用图像数据: # import the necessary packages from picamer ...

  3. css3和html5

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  4. 用单向链表实现两数倒序相加(java实现)

    很久没做算法题了,准备重操旧业,于是刷了一波LeetCode,看到一个比较经典的链表算法题,分享出来. 题目 给定两个非空链表来表示两个非负整数.位数按照逆序方式存储,它们的每个节点只存储单个数字.将 ...

  5. sudo passwd root输入普通用户密码后显示用户不再sudoers文件中

    在写上一篇VirtualBox创建共享文件夹的时候,在运行下图授权时,root密码一直输入错误 然后我就在终端输入 su root,却发现需要密码,但我却不知道密码是什么 于是我就在终端输入如下命令, ...

  6. Alpha(5/10)

    鐵鍋燉腯鱻 项目:小鱼记账 团队成员 项目燃尽图 冲刺情况描述 站立式会议照片 各成员情况 团队成员 学号 姓名 git地址 博客地址 031602240 许郁杨 (组长) https://githu ...

  7. jquery,underscore,lodash那些事儿

    一.参考链接 https://jquery.com/ https://en.wikipedia.org/wiki/JQuery https://developer.mozilla.org/zh-CN/ ...

  8. 潭州课堂25班:Ph201805201 django框架 第七课 常用 字段类型及参数,关系表的实现,表关系对象add,create的方法 (课堂笔记)

    写个类,创建表格 执行命令生成文件 提交,在数据库中创建 进入数据库查看 对数据进行修改操作 只有用到 save() 才能触发 updaer_time 的更改, 下边 update 方法不会修改 up ...

  9. 更改pip安装源的镜像解决安装总是timeout的情况(pip 豆瓣镜像源)

    由于国外的pip源总是由于各种原因不能被访问或者网速过慢,而造成的timeout错误 解决方法是修改pip的配置文件(如果没有配置文件在相应的地方新建,配置文件的路径和名字参考这里),设置安装包时候访 ...

  10. BZOJ4738 : 汽水

    二分答案$mid$,若存在一条路径满足$|ave-k|<mid$,则答案至多为$mid-1$. 若$ave\leq k$,则$\sum(w-k)\leq 0$,且$\sum(k-w-mid)&l ...