2

Recently I've been working on an API gateway project. However, for service registry and discovery I run into some issues regarding to Zuul failover and dynamically deploy of multiple Eureka instances. The following is my project.

eureka server project

EurekaBootstrap.java

package com.plateno.cloud.netflix.eureka;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class EurekaBootstrap {
public static void main(String[] args) {
    SpringApplication.run(EurekaBootstrap.class, args);
 }
}

config:application.yml

#spring.application.name=plateno-cloud-netflix-eureka
#server.port=9000
#eureka.instance.hostname=localhost
#eureka.client.registerWithEureka=false
#eureka.client.fetchRegistry=false
#eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/
#spring.profiles.active: dev

server:
    port: 9000
spring.application.name: localhost
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:${server.port}/eureka/
  instance:
    hostname: localhost
eureka.client.register-with-eureka: false
eureka.client.fetch-registry: false
---
spring:
    profiles: peer1
server:
    port: 9001
peer2:
    port: 9002    
spring.application.name: peer1
eureka:
  client:
    serviceUrl:
      defaultZone: http://peer2:${peer2.port}/eureka/  
  instance:
    hostname: peer1
eureka.client.register-with-eureka: true
eureka.client.fetch-registry: true
---
spring:
    profiles: peer2
server:
    port: 9002
spring.application.name: peer2
peer1:
    port: 9001 
eureka:
  client:
    serviceUrl:
      defaultZone: http://peer1:${peer1.port}/eureka/
  instance:
    hostname: peer2
eureka.client.register-with-eureka: true
eureka.client.fetch-registry: true
---
spring:
  profiles:
    active: peer1

I configured peer1 and peer2 to localhost in host

zuul with ribbon project

ZuulBootstrap.java

package com.plateno.cloud.netflix.zuul;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.cloud.netflix.zuul.filters.discovery.PatternServiceRouteMapper;
import org.springframework.context.annotation.Bean;

import com.netflix.zuul.exception.ZuulException;

@SpringBootApplication
@EnableZuulProxy
public class ZuulBootstrap {
    public static void main(String[] args) {
        SpringApplication.run(ZuulBootstrap.class, args);
    }

    @Bean
    public SimpleFilter simpleFilter() {
        return new SimpleFilter();
    }

    @Bean
    public PatternServiceRouteMapper serviceRouteMapper() {
        return new PatternServiceRouteMapper("(?<name>^.+)", "${name}") {
            @Override
            public String apply(final String serviceId) {
                String route = super.apply(serviceId);
                return route;
            }
        };
    }

    @RefreshScope
    @ConfigurationProperties("zuul")
    public ZuulProperties zuulProperties() {
        ZuulProperties zuulProperties = new ZuulProperties();
        return zuulProperties;
    }
}

PreFilter: SimpleFilter.java

package com.plateno.cloud.netflix.zuul;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;

public class SimpleFilter extends ZuulFilter {

    private static Logger log = LoggerFactory.getLogger(SimpleFilter.class);

    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 1;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        log.info(String.format("%s request to %s", request.getMethod(), request.getRequestURL().toString()));
        return null;
    }
}

zuul config:application.yml

#default_charset=utf-8
#spring.application.name=plateno-cloud-netflix-zuul
#server.port=9030
#ribbon.eureka.enabled=true
#eureka.client.serviceUrl.defaultZone=http\://localhost\:9001/eureka/

---
default_charset: utf-8
spring:
  application:
    name: plateno-cloud-netflix-zuul
server:
  port: 9030
ribbon: 
  eureka:
    enabled: true

eureka:
  client:
    service-url:
      defaultZone: http://localhost:9001/eureka/,http://localhost:9002/eureka/

target service project just common project with yml config

I didn't parse the source code of this project but config profile

#default_charset=utf-8
#spring.application.name=plateno-app0
#server.port=9010
#eureka.client.serviceUrl.defaultZone=http\://localhost\:9000/eureka/
server:
    port: 8080
default_charset: utf-8
spring:
  application:
    name: plateno-app0

eureka.client.serviceUrl.defaultZone: http://peer1:9001/eureka/,http://peer2:9002/eureka/

end of sourece, the attachment is the source code

I started 2 eureka instances by changing active, then I started the zuul server. Lastly, I started 2 target service via changing server port. I ran some tests using JMeter. I stopped one target service in the middle of a concurrency test, then some requests failed about socket closed.

So the question is why zuul and ribbon couldn't handle failover or how should I configure to reach that effect?

The second question is every time I deploy another eureka server, I need to edit eureka server configuration, zuul configuration and the target service configuration. Therefor all of that projects need to restart. I can't accept that, so is there a way to dynamically change the number of eureka server without editing configuration of other projects and restarting them?

In the end,I am hoping Pivotal team could update the documentation of spring cloud to provide more detailed information.

g00glen00b
  • 41,995
  • 13
  • 95
  • 133
rejoice
  • 21
  • 2
  • With regard to "dynamically changing the number of eureka server without editing config of other projects and restarting them" the answer is no. Netflix uses elastic ip's and dns for a basically static list of eureka servers. – spencergibb Jul 06 '16 at 02:44
  • thanks ,i will look for it – rejoice Jul 06 '16 at 09:28

1 Answers1

0

You have to provide all instance(comma saperated list) as below for all client applications - bootstrap.properties- eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka,http://localhost:8762/eureka

Because if you let only eureka servers aware of each other then they can replicate all the instances which is one part perfect. Now suppose in client app if you pass only one instance suppose - eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka And suppose this application will restart and at that time your this instance of eureka is down So what happend in that case will it check the other eureka server instance , but how you have provided only one instance in your client app.

So for this reason you have to provide all instances of eureka server in your client app. Thanks

  • This is exactly what I am doing, passing in **defaultZone** all the Eureka servers. I'm trying to make the microservice to discover the config server, but whenver the first Eureka is down, the ms doesn't even try to connect to the second one since at startup it tries only the first one. The ms launch an ERROR due to missing property (that has to be retrieved from the config server). Is it possible to make the client test all Eureka serverrs at startup? – Xfox Oct 13 '21 at 10:30