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.