Search code examples
spring-cloud

Spring cloud eureka client to multiple eureka servers


I am able to get the eureka server to operate in a peer to peer mode. But one thing I am curious about is how do I get a service discovery client to register to multiple eureka servers.

My use case is this:
Say I have a service registering to one of the eureka servers (e.g. server A) and that registration is replicated to its peer. The service is actually pointing at server A. If server A goes down, and the client expects to renew with server A, how do the renewal work if server A is no longer present. Do I need to register with both and if not then how does the renewal happen if the client cannot communicate with server A. Does it have some knowledge of server B (from its initial and/or subsequent comms with A) and fail over to do its registration renewal there? That is not clear in any of the docs and I need to verify

So based on the answer, I added the following to my 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/

It only registers to the first in the comma separated list. If I switch them around the registration flips between eureka servers.

I can see that it does separate these based on comma but my guess is that Eureka does not use this underneath (from 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<>();
    }

Solution

  • I just reviewed the source code for Eureka 1.1.147. It works differently that i expected but at least I know now.

    You can put multiple service urls in the set

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

    But the register action only uses the first one to register. There remaining are used only if attempting to contact the first fails.

    from (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();
                }
            }
        }
    

    which calls

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

    It only calls the backup when an exception is thrown in the above makeRemoteCall(action, 0) call

       } 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;
                }
    

    So you can't really register to two eureka servers simultaneously from this code. Unless I missed something.