1.背景
在工作中,有个服务B开发测试完一个需求后需要上线,我们的上线机制是先启动新服务,在停掉老服务,上线的过程中发现服务B的调用方服务A出现了报警,我们的服务治理是通过euraka做的,于是就研究了下eurake的机制:
分析原因:
通过分析发现,服务A每隔30s拉取一次服务信息缓存到本地,Eurake的客户端停掉之后eurake不会立即移除该服务,Eureka Server 在启动的时候会创建一个定时任务进行探活,默认每隔一段时间(默认为 60 秒) 将当前清单中超时 (默认为 90秒)没有续约的服务剔除出去。基于这两点可以看出,如果服务提供方停了,此时服务消费方从注册中心还能拉取到该服务信息,缓存到本地,然后继续调用停掉的服务,就会有问题;
解决方案:
- 保证服务提供方停掉后eurake能立即移除注册信息,这样就拉不到停掉的服务。(服务停掉前,主动调用eurake的接口让服务立即down)
- 保证服务消费方缓存的注册信息能正常调用。(服务停掉前,sleep30秒)
脚本如下(在服务退出前执行):
wget --header "Content-Type: application/json" --post-data '{"status":"DOWN"}' http://127.0.0.1:8080/actuator/serviceregistry
sleep 180
//注意:需要引人以下依赖,8080端口是actuator的端口,可以自行配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2.疑问:为什么服务B停掉前不能给告诉eurake把B移除掉并清理注册表缓存?
通过研究发现,euraka提供了自动移除服务的功能的,前提是服务必须是通过kill -15下线,详情如下:
eurake提供的正常下线流程
(1) eurake客户端收到 kill -15, 会执行com.netflix.discovery.DiscoveryClient的 shutdown() 方法, shutdown() 方法中会调用, unregister() 方法来通知 eureka集群对自身进行反注册.
(2)eureka服务集群收到cancel请求之后, 会更新注册表,以达到 /eureka/apps 接口能拉到最新注册表的效果, 缓存失效的逻辑如下:com.netflix.eureka.registry.AbstractInstanceRegistry 中的 com.netflix.eureka.registry.AbstractInstanceRegistry#cancel 方法
以上说的是如果是kill -15来关掉客户端的,此时eurake才会主动去摘除服务并刷新注册表,如果不是kill -15的话可以使用上边我提供的方法来解决。
eurake三级缓存:https://new-developer.aliyun.com/article/1058290
https://www.infoq.cn/article/y_1bcrblonu61s1gbgsu