微服务(Nacos、eureka、consul)优雅上下线方案汇总_nacos下线服务
前提
优雅的本质
一个服务有多个(如A、B 两个实例)实例提供服务时,客户端请求服务时会访问此服务的多个实例,当进行A实例进行部署时将流量切换到B实例,然后再关闭或重新发布 ;如何实现这个功能呢?
所以本质就是模拟人工在控制台触发“下线”功能(此实例还是提供服务),过一会儿等流量全部切到其他实例再部署&Kill实例;可以理解为此实例说:“我即将要先下线了,请访问另外实例”。
为什么要过一会儿?
可能客户端缓存的服务提供的实例Ip列表导致无效的请求或服务挂掉后瞬间的访问不到服务的情况
在部署脚本里面植入1、下线脚本;2 增加缓冲时间(如60s),默认Nacos客户端缓存实例列表是30s;
方案1 注册中心自带的方法
我们使用的这个方式,简单无需配置,默认支持;
下线
curl -X PUT \"http://nacos服务ip:port/nacos/v1/ns/instance?serviceName=服务名&ip=172.25.135.221&port=8667&namespaceId=preprod&weight=0&enabled=false\"
上线
curl -X PUT \"http:/nacos服务ip:port/nacos/v1/ns/instance?serviceName=服务名&ip=172.25.135.221&port=8667&namespaceId=preprod&weight=1&enabled=true\"
方案2 基于/service-registry端点
如果应用支持Spring Cloud部署那就更好了。Spring Cloud提供了/service-registry端点。但从名字就可以知道专门针对服务注册实现的一个端点。
在配置文件中开启/service-registry端点:
1
2
3
4
5
6
7
8
9
management:
endpoints:
web:
exposure:
include: service-registry
base-path: /actuator
endpoint:
serviceregistry:
enabled:
true
访问http://localhost:8667/actuator 端点可以查看到开启了如下端点:
1
2
3
4
5
6
7
8
9
10
11
12
{
\"_links\"
: {
\"self\"
: {
\"href\"
:
\"http://localhost:8667/actuator\"
,
\"templated\"
:
false
},
\"serviceregistry\"
: {
\"href\"
:
\"http://localhost:8667/actuator/service-registry\"
,
\"templated\"
:
false
}
}
}
通过curl命令来进行服务状态的修改:上线是UP,下线是DOWN
curl -X \"POST\" \"http://172.25.129.191:8667/actuator/service-registry?status=DOWN\" -H \"Content-Type: application/vnd.spring-boot.actuator.v2+json;charset=UTF-8\"
执行上述命令之前,查看Nacos对应实例状态为:
比方案1 多了一个步骤 需要配置一下开启一下才行;
其本质就是如下代码,去关闭了Nacos控制的状态
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
@Endpoint
(id =
\"service-registry\"
)
public
class
ServiceRegistryEndpoint {
private
final
ServiceRegistry serviceRegistry;
private
Registration registration;
public
ServiceRegistryEndpoint(ServiceRegistry serviceRegistry) {
this
.serviceRegistry = serviceRegistry;
}
public
void
setRegistration(Registration registration) {
this
.registration = registration;
}
@WriteOperation
public
ResponseEntity setStatus(String status) {
Assert.notNull(status,
\"status may not by null\"
);
if
(
this
.registration ==
null
) {
return
ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(
\"no registration found\"
);
}
this
.serviceRegistry.setStatus(
this
.registration, status);
return
ResponseEntity.ok().build();
}
@ReadOperation
public
ResponseEntity getStatus() {
if
(
this
.registration ==
null
) {
return
ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(
\"no registration found\"
);
}
return
ResponseEntity.ok()
.body(
this
.serviceRegistry.getStatus(
this
.registration));
}
}
调用的Endpoint便是通过上面代码实现的。所以不仅Nacos,只要基于Spring Cloud集成的注册中心,本质上都是支持这种方式的服务下线的。
方案3 个性化定义下线方式,本质还是调用方案2的
不需要配置,实现钩子方法即可
在实例启动的时默认都会进行注册实例到注册中心,如下官方实现方式:NacosServiceRegistryAutoConfiguration
@Configuration(proxyBeanMethods = false)@EnableConfigurationProperties@ConditionalOnNacosDiscoveryEnabled@ConditionalOnProperty(value = \"spring.cloud.service-registry.auto-registration.enabled\", matchIfMissing = true)@AutoConfigureAfter({ AutoServiceRegistrationConfiguration.class, AutoServiceRegistrationAutoConfiguration.class, NacosDiscoveryAutoConfiguration.class })public class NacosServiceRegistryAutoConfiguration { @Bean public NacosServiceRegistry nacosServiceRegistry( NacosDiscoveryProperties nacosDiscoveryProperties) { return new NacosServiceRegistry(nacosDiscoveryProperties); } @Bean @ConditionalOnBean(AutoServiceRegistrationProperties.class) public NacosRegistration nacosRegistration( NacosDiscoveryProperties nacosDiscoveryProperties, ApplicationContext context) { return new NacosRegistration(nacosDiscoveryProperties, context); } @Bean @ConditionalOnBean(AutoServiceRegistrationProperties.class) public NacosAutoServiceRegistration nacosAutoServiceRegistration( NacosServiceRegistry registry, AutoServiceRegistrationProperties autoServiceRegistrationProperties, NacosRegistration registration) { return new NacosAutoServiceRegistration(registry, autoServiceRegistrationProperties, registration); }}
你只需要知道如何拿到注册实例即可,默认就可以获取,实现自己的对外接口即可
@Resource
private
NacosServiceRegistry nacosServiceRegistry;
@Resource
private
NacosRegistration nacosRegistration;
@GetMapping
(value =
\"/api/nacos/{status}\"
)
public
String deregisterInstanceStatus(
@PathVariable
String status) {
if
(!status.equalsIgnoreCase(
\"UP\"
) && !status.equalsIgnoreCase(
\"DOWN\"
)) {
log.warn(
\"can\'t support status {},please choose UP or DOWN\"
, status);
return
\"please choose UP or DOWN,can\'t support status: \"
+status;
}
try
{
nacosServiceRegistry.setStatus(nacosRegistration,status);
}
catch
(Exception e) {
log.error(
\" deregisterInstanceStatus nacos error\"
, e);
return
\"error:\"
+e.getMessage();
}
return
\"success\"
;
}
参考资源:
https://zhuanlan.zhihu.com/p/586909971 部分可以参考,他是直接注销实例,不是下线
微服务架构:Nacos本地缓存 PK 微服务优雅下线_nacos下线相当于kill服务吗-CSDN博客 Nacos本地缓存 PK 微服务优雅下线
https://blog.51cto.com/u_9177933/3013415 eureka、consul的其他注册中心的方案
[微服务]nacos停服方案实践(nacos多个微服务实例) - 站长素材网
https://segmentfault.com/a/1190000043819832#item-3-9 spring boot 2.2.1以上版本的方式