Spring 当第一个 eureka 服务器关闭时,Boot App 没有启动

Spring Boot App doesn't start when the first eureka server is down

我有多个服务器的 Eureka 集群:

#ENV 
EUREKA_URL=http://host1:8761/eureka/,http://host2:8761/eureka/,http://host3:8761/eureka/

#boostrap.yml
eureka:
 client:
  registryFetchIntervalSeconds: 5
  serviceUrl:
   defaultZone: ${EUREKA_URL:http://127.0.0.1:8761/eureka/}

万一当 host1 出现故障时,我的应用程序不会以异常启动:

13410 2021-01-14 11:28:34,994 ERROR [ main ] o.s.b.SpringApplication                                 | Application run failed 
org.springframework.web.client.ResourceAccessException: I/O error on GET request for "http://host1:8761/eureka/apps/": Connection refused (Connection refused); nested exception is java.net.ConnectException: Connection refused (Connection refused)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:748)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:674)
    at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:583)
    at org.springframework.cloud.netflix.eureka.http.RestTemplateEurekaHttpClient.getApplicationsInternal(RestTemplateEurekaHttpClient.java:154)
    at org.springframework.cloud.netflix.eureka.http.RestTemplateEurekaHttpClient.getApplications(RestTemplateEurekaHttpClient.java:142)
    at org.springframework.cloud.netflix.eureka.config.EurekaConfigServerBootstrapConfiguration.lambda$eurekaConfigServerInstanceProvider[=12=](EurekaConfigServerBootstrapConfiguration.java:112)
    at org.springframework.cloud.config.client.ConfigServerInstanceProvider.getConfigServerInstances(ConfigServerInstanceProvider.java:50)
    at org.springframework.cloud.config.client.ConfigServerInstanceProvider$$FastClassBySpringCGLIB$$facbf882.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)
    at 

这对我来说很奇怪,因为我预计尤里卡会尝试连接到其他服务器,但事实并非如此。我在 spring-cloud-netflix-eureka-client-2.2.3.RELEASE.jar:

中找到了它
       // EurekaConfigServerBootstrapConfiguration.java
        private String getEurekaUrl(EurekaClientConfigBean config) {
            List<String> urls = EndpointUtils.getServiceUrlsFromConfig(config,
                    EurekaClientConfigBean.DEFAULT_ZONE, true);
            return urls.get(0);
        }

    // DefaultEurekaClientConfig.java
    @Override
    public List<String> getEurekaServerServiceUrls(String myZone) {
        String serviceUrls = configInstance.getStringProperty(
                namespace + CONFIG_EUREKA_SERVER_SERVICE_URL_PREFIX + "." + myZone, null).get();
        if (serviceUrls == null || serviceUrls.isEmpty()) {
            serviceUrls = configInstance.getStringProperty(
                    namespace + CONFIG_EUREKA_SERVER_SERVICE_URL_PREFIX + ".default", null).get();

        }
        if (serviceUrls != null) {
            return Arrays.asList(serviceUrls.split(URL_SEPARATOR));
        }

        return new ArrayList<String>();
    }

最后:

    // RestTemplateEurekaHttpClient.java
    private EurekaHttpResponse<Applications> getApplicationsInternal(String urlPath,
            String[] regions) {
        String url = serviceUrl + urlPath;

        if (regions != null && regions.length > 0) {
            url = url + (urlPath.contains("?") ? "&" : "?") + "regions="
                    + StringUtil.join(regions);
        }

        // There is no exception handling here and above!
        ResponseEntity<EurekaApplications> response = restTemplate.exchange(url,
                HttpMethod.GET, null, EurekaApplications.class);

        return anEurekaHttpResponse(response.getStatusCodeValue(),
                response.getStatusCode().value() == HttpStatus.OK.value()
                        && response.hasBody() ? (Applications) response.getBody() : null)
                                .headers(headersOf(response)).build();
    }

我有 java11springBootVersion = '2.3.4.RELEASE'spring-cloud-netflix-eureka-client-2.2.3.RELEASEeureka-client-1.9.21

如何让eureka在第一台服务器注册失败的情况下,继续在后面的服务器上尝试?有什么想法吗?

我找到了解决方法。 我只是覆盖 bean:

@Slf4j
@Configuration
public class EurekaMultiClientBoostrapConfig {
    @Bean
    @Primary
    public RestTemplateEurekaHttpClient configDiscoveryRestTemplateEurekaHttpClient(EurekaClientConfigBean config) {
        List<String> urls = EndpointUtils.getServiceUrlsFromConfig(config,
                EurekaClientConfigBean.DEFAULT_ZONE, true);
        for (String url : urls) {
            try {
                RestTemplateEurekaHttpClient client = (RestTemplateEurekaHttpClient) new RestTemplateTransportClientFactory()
                        .newClient(new DefaultEndpoint(url));
                client.getApplications(config.getRegion());
                log.info("Registered on Eureka host '{}' is successful.", url);
                return client;
            } catch (Exception e) {
                log.warn("Eureka host '{}' is unavailable(reason: {})", url, e.getMessage());
            }
        }
        throw new IllegalStateException("Failed to register on any eureka host.");
    }

P.S。由于此配置属于 Bootstrap 配置,请不要忘记将以下参数添加到 resources/META-INF/spring.factories

org.springframework.cloud.bootstrap.BootstrapConfiguration=your.app.package.EurekaMultiClientBoostrapConfig