Spring Cloud:Eureka 客户端注册/注销周期

Posted

技术标签:

【中文标题】Spring Cloud:Eureka 客户端注册/注销周期【英文标题】:Spring Cloud: Eureka Client registration/deregistration cycle 【发布时间】:2015-05-30 12:55:21 【问题描述】:

为了熟悉 Spring Cloud 的 Eureka 客户端/服务器机制,我尝试将客户端连接到 Eureka 服务器,并每 5 分钟打开/关闭连接,以查看 Eureka 服务器如何处理此问题。

我有两个 Eureka 客户端。

首先是使用此代码向我提供有关已注册应用程序的信息:

@Autowired
private DiscoveryClient discoveryClient;

@RequestMapping(value = "/services", produces = MediaType.APPLICATION_JSON)
public ResponseEntity<ResourceSupport> applications() 
    ResourceSupport resource = new ResourceSupport();

    Set<String> regions = discoveryClient.getAllKnownRegions();

    for (String region : regions) 
        Applications allApps = discoveryClient.getApplicationsForARegion(region);
        List<Application> registeredApps = allApps.getRegisteredApplications();
        Iterator<Application> it = registeredApps.iterator();

        while (it.hasNext()) 
            Application app = it.next();

             List<InstanceInfo> instancesInfos = app.getInstances();

             if (instancesInfos != null && !instancesInfos.isEmpty()) 
                 //only show one of the instances
                 InstanceInfo info = instancesInfos.get(0);
                 resource.add(new Link(info.getHomePageUrl(), "urls"));
             
        
    

    return new ResponseEntity<ResourceSupport>(resource, HttpStatus.OK);

第二个 Eureka 客户端每 5 分钟注册/注销一次:

private static final long EUREKA_INTERVAL = 5 * 60000;

public static void main(String[] args) 
    ConfigurableApplicationContext context = SpringApplication.run(MyServiceApplication.class);

    long currentTime = System.currentTimeMillis();
    long lastToggleTime = System.currentTimeMillis();
    boolean connected = true;
    while (true) 
        if (currentTime - lastToggleTime > EUREKA_INTERVAL) 
            if (connected) 
                System.err.println("disconnect");
                DiscoveryManager.getInstance().shutdownComponent();
                connected = false;
                lastToggleTime = System.currentTimeMillis();
            
            else 
                System.err.println("connect");
                DiscoveryManager.getInstance().initComponent(
                        DiscoveryManager.getInstance().getEurekaInstanceConfig(),
                        DiscoveryManager.getInstance().getEurekaClientConfig());
                connected = true;
                lastToggleTime = System.currentTimeMillis();
            
        
        currentTime = System.currentTimeMillis();
    


第二个Eureka客户端的日志输出如下:

disconnect
2015-03-26 13:59:23.713  INFO 3452 --- [           main] com.netflix.discovery.DiscoveryClient    : DiscoveryClient_MYAPPNAME/MYMEGAHOSTNAME - deregister  status: 200
connect
2015-03-26 14:04:23.870  INFO 3452 --- [           main] com.netflix.discovery.DiscoveryClient    : Disable delta property : false
2015-03-26 14:04:23.870  INFO 3452 --- [           main] com.netflix.discovery.DiscoveryClient    : Single vip registry refresh property : null
2015-03-26 14:04:23.870  INFO 3452 --- [           main] com.netflix.discovery.DiscoveryClient    : Force full registry fetch : false
2015-03-26 14:04:23.870  INFO 3452 --- [           main] com.netflix.discovery.DiscoveryClient    : Application is null : false
2015-03-26 14:04:23.870  INFO 3452 --- [           main] com.netflix.discovery.DiscoveryClient    : Registered Applications size is zero : true
2015-03-26 14:04:23.870  INFO 3452 --- [           main] com.netflix.discovery.DiscoveryClient    : Application version is -1: true
2015-03-26 14:04:23.889  INFO 3452 --- [           main] com.netflix.discovery.DiscoveryClient    : Getting all instance registry info from the eureka server
2015-03-26 14:04:23.892  INFO 3452 --- [           main] com.netflix.discovery.DiscoveryClient    : The response status is 200
2015-03-26 14:04:23.894  INFO 3452 --- [           main] com.netflix.discovery.DiscoveryClient    : Starting heartbeat executor: renew interval is: 30
2015-03-26 14:04:53.916  INFO 3452 --- [ool-11-thread-1] com.netflix.discovery.DiscoveryClient    : DiscoveryClient_MYAPPNAME/MYMEGAHOSTNAME - Re-registering apps/MYAPPNAME
2015-03-26 14:04:53.916  INFO 3452 --- [ool-11-thread-1] com.netflix.discovery.DiscoveryClient    : DiscoveryClient_MYAPPNAME/MYMEGAHOSTNAME: registering service...
2015-03-26 14:04:53.946  INFO 3452 --- [ool-11-thread-1] com.netflix.discovery.DiscoveryClient    : DiscoveryClient_MYAPPNAME/MYMEGAHOSTNAME - registration status: 204

第一次启动两个 Eureka 客户端时,效果很好。第二个客户端由第一个客户端显示,第二个客户端在 Eureka 服务器控制台中可见。 当第二个客户端与 Eureka 服务器断开连接时,它不再列在那里,第一个客户端也不再显示它。

不幸的是,当第二个客户端重新连接到 Eureka 服务器时,Eureka 服务器控制台只显示一个大红色突出显示的“DOWN (1)”,而第一个客户端不再显示第二个客户端。我在这里错过了什么?


解决方案:

基于 Dave Sayer 的 answer,我的解决方案是添加一个自定义 @Configuration,它具有自动装配的 EurekaDiscoveryClientConfiguration 并启动一个用于切换注册的线程。请注意,这仅用于测试目的,因此它可能是一个非常丑陋的解决方案;-)

@Configuration
static public class MyDiscoveryClientConfigServiceAutoConfiguration 

    @Autowired
    private EurekaDiscoveryClientConfiguration lifecycle;

    @PostConstruct
    public void init() 
        new Thread(new Runnable() 
            @Override
            public void run() 
                long currentTime = System.currentTimeMillis();
                long lastToggleTime = System.currentTimeMillis();
                boolean connected = true;

                while (true) 
                    if (currentTime - lastToggleTime > EUREKA_INTERVAL) 
                        if (connected) 
                            System.err.println("disconnect");

                            lifecycle.stop();
                            DiscoveryManager.getInstance().getDiscoveryClient().shutdown();
                            connected = false;
                            lastToggleTime = System.currentTimeMillis();
                        
                        else 
                            System.err.println("connect");
                            DiscoveryManager.getInstance().initComponent(
                                    DiscoveryManager.getInstance().getEurekaInstanceConfig(),
                                    DiscoveryManager.getInstance().getEurekaClientConfig());

                            lifecycle.start();
                            connected = true;
                            lastToggleTime = System.currentTimeMillis();
                        
                    
                    currentTime = System.currentTimeMillis();
                
            
        ).start();
    


【问题讨论】:

【参考方案1】:

您对DiscoveryManager.getInstance().initComponent() 的调用不会设置状态(默认为DOWN)。在 Spring Cloud 中,我们在一个特殊的 EurekaDiscoveryClientConfiguration.start() 生命周期中处理它。您可以像这样注入并重新使用它:

@Autowired
private EurekaDiscoveryClientConfiguration lifecycle;

@PostConstruct
public void init() 
    this.lifecycle.stop();
    if (DiscoveryManager.getInstance().getDiscoveryClient() != null) 
        DiscoveryManager.getInstance().getDiscoveryClient().shutdown();
    
    ApplicationInfoManager.getInstance().initComponent(this.instanceConfig);
    DiscoveryManager.getInstance().initComponent(this.instanceConfig,
            this.clientConfig);
    this.lifecycle.start();

(取自这里的代码:https://github.com/spring-cloud/spring-cloud-netflix/blob/master/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/config/DiscoveryClientConfigServiceAutoConfiguration.java#L58)。

【讨论】:

试试这个,谢谢戴夫!

以上是关于Spring Cloud:Eureka 客户端注册/注销周期的主要内容,如果未能解决你的问题,请参考以下文章

Spring Cloud Eureka服务注册与发现

二Spring Cloud之注册中心 Eureka

Spring Cloud Eureka 服务注册中心

Spring Cloud 2-Eureka服务发现注册

Spring Cloud Eureka

Spring Cloud-Eureka 服务注册中心