将Spring Cloud Eureka客户端连接到多个Eureka服务器

9
我可以让eureka服务器以点对点的方式运行。但我对如何使服务发现客户端向多个eureka服务器注册感到好奇。
我的应用场景是这样的:假设我有一个服务注册到其中一个eureka服务器(例如,服务器A),并且该注册正在被复制到其同级。该服务实际上指向服务器A。如果服务器A崩溃,客户端期望与服务器A进行续订,那么如果客户端无法与服务器A通信,续订会如何工作?
我需要同时注册吗?如果不需要,则在客户端无法与服务器A通信时,如何进行续订操作?它是否具有关于服务器B的某些知识(来自与A的初始和/或随后的通信),并故障转移以在那里进行注册续订?文档中没有明确说明这一点,因此我需要进行验证。
基于答案,我将以下内容添加到我的application.yml文件中:
eureka:
  # these are settings for the client that gets services
  client:
    # enable these two settings if you want discovery to work
    registerWithEureka: true
    fetchRegistry: true
    serviceUrl:
      defaultZone: http://localhost:8762/eureka/, http://localhost:8761/eureka/

它仅注册逗号分隔列表中的第一个。如果我交换它们,注册将在eureka服务器之间翻转。

我可以看到它确实基于逗号分隔符对这些进行分离,但我猜测Eureka在底层不使用这个(来自EurekaClientConfigBean.java)

    @Override
    public List<String> getEurekaServerServiceUrls(String myZone) {
        String serviceUrls = this.serviceUrl.get(myZone);
        if (serviceUrls == null || serviceUrls.isEmpty()) {
            serviceUrls = this.serviceUrl.get(DEFAULT_ZONE);
        }
        if (serviceUrls != null) {
            return Arrays.asList(serviceUrls.split(","));
        }

        return new ArrayList<>();
    }
5个回答

11

我刚刚审查了Eureka 1.1.147的源代码。它的工作方式与我的预期不同,但至少现在我知道了。

你可以在集合中放置多个服务网址

serviceUrl:
      defaultZone: http://localhost:8762/eureka/, http://localhost:8761/eureka/

但是注册操作只使用第一个进行注册。当尝试联系第一个失败时,才使用其余的。

来自(DiscoveryClient.java)。

   /**
     * Register with the eureka service by making the appropriate REST call.
     */
    void register() {
        logger.info(PREFIX + appPathIdentifier + ": registering service...");
        ClientResponse response = null;
        try {
            response = makeRemoteCall(Action.Register);
            isRegisteredWithDiscovery = true;
            logger.info(PREFIX + appPathIdentifier + " - registration status: "
                    + (response != null ? response.getStatus() : "not sent"));
        } catch (Throwable e) {
            logger.error(PREFIX + appPathIdentifier + " - registration failed"
                    + e.getMessage(), e);
        } finally {
            if (response != null) {
                response.close();
            }
        }
    }

这个调用

private ClientResponse makeRemoteCall(Action action) throws Throwable {
    return makeRemoteCall(action, 0);
}

只有在上面的makeRemoteCall(action, 0)调用中抛出异常时,才会调用备份。
   } catch (Throwable t) {
            closeResponse(response);
            String msg = "Can't get a response from " + serviceUrl + urlPath;
            if (eurekaServiceUrls.get().size() > (++serviceUrlIndex)) {
                logger.warn(msg, t);
                logger.warn("Trying backup: " + eurekaServiceUrls.get().get(serviceUrlIndex));
                SERVER_RETRY_COUNTER.increment();
                return makeRemoteCall(action, serviceUrlIndex);
            } else {
                ALL_SERVER_FAILURE_COUNT.increment();
                logger.error(
                        msg
                                + "\nCan't contact any eureka nodes - possibly a security group issue?",
                        t);
                throw t;
            }

所以从这段代码来看,你不能同时将自己注册到两个eureka服务器。除非我遗漏了什么。


FYI给未来读者,当使用区域亲和性时,这不是真实的;它会随机重排列表。https://github.com/Netflix/eureka/blob/efc1cf6017f13f5f2491838bde894630a37dfd75/eureka-client/src/main/java/com/netflix/discovery/shared/resolver/aws/ZoneAffinityClusterResolver.java#L69 - Steve

2

是的,根据文档,流程如下:

  1. 客户端注册到第一个可用的 eureka 服务器
  2. 注册信息在 eureka 服务器节点之间进行复制。

因此,不仅不需要多次注册,而且应该避免这样做。


1

你的客户端应用程序应该提供一个Eureka URL列表。这些URL以逗号分隔。


根据答案,我在第一次回复中添加了更新。 - EvilJinious1

0
请在 application.property 或 application.yml 文件中添加以下属性:

eureka.client.service-url.defaultZone = http://localhost:8761/eureka,http://localhost:8762/eureka

服务将在两个 Eureka 服务器上注册。如果一个 Eureka 服务器宕机,则请求将从另一个 Eureka 服务器提供服务。


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接