前言

SpringCloud微服务架构中,微服务的上下线是不可避免的,但如果你的服务发现组件使用的是Eureka,那么默认最长会有90秒的延迟,其他应用才会感知到该服务下线,这意味着:该实例下线后的90秒内,其他服务仍然可能调用到这个已下线的实例。因此,该方式是不够优雅的 。

但是我们可以结合k8s,单个服务升级的过程中,不停止对外服务滚动更新,使得用户对整个升级过程无感知,从而实现服务的优雅升级。

操作

1.开启/service-registry 端点

在application.yml中,添加此配置,从而暴露/service-registry 端点:

1
2
3
4
5
6
7
8
9
10
management:
security:
enabled: false
health:
solr:
enabled: false
endpoints:
web:
exposure:
include: info,service-registry

服务在下线的时候发送发送POST请求到/actuator/service-registry 端点:

同时要延时90秒等eureka 的缓存信息全部更新

1
curl -X POST http://localhost:9100/actuator/service-registry?status=DOWN  -H "Content-Type: application/vnd.spring-boot.actuator.v2+json;charset=UTF-8";sleep 90'

结合kubernetes的滚动更新实行后的效果类似如下图:

如果Deployment的replicas为1,滚动更新会先启动一个pod,同时旧的pod执行POST操作,把自己的状态更改为DOWN,这个状态会持续90s 直到所有的client缓存中的信息全部更新,不再调用这个状态为DOWN 的服务,同时新的POD状态为UP已经注册被其他的CLIENT刷新到缓存,开始提供服务。

2.Kubernetes 设置管理pod生命周期

kubernetes默认的pod终结等待时间是30s 无法达到我们默认的90s就会销毁,这会导致其他的client缓存信息没有来得及更新还是会调用,这个时候会出现服务器内部错误500的提示,因此我们改为更加保险的120S

下一步我们要让微服务下线的时候发送POST请求,使用kubernetes 我们可以使用 lifecycle hook可以解决这个问题。

lifecycle有两种回调函数

1
2
PostStart:容器创建成功后,运行前的任务,用于资源部署、环境准备等。
PreStop:在容器被终止前的任务,用于优雅关闭应用程序、通知其他系统等等。
1
2
3
4
5
6
7
lifecycle:
preStop:
exec:
command:
- /bin/bash
- -c
- 'curl -X POST http://localhost:9100/actuator/service-registry?status=DOWN -H "Content-Type: application/vnd.spring-boot.actuator.v2+json;charset=UTF-8";sleep 90'