2

I am working in an microservices architecture that works as follows

enter image description here

I have two service web applications (REST services) that register themselves correctly in an eureka server, then I have a client application that fetches the eureka registry and using ribbon as a client side load balancer, determines to which service application go (at the moment, a simple Round Robin is being used).

My problem is that when I stop one of the service applications (they currently run in docker containers btw), eureka does not remove them from their registry (seems to take a few minutes) so ribbon still thinks that there are 2 available services, making around 50% of the calls fail.

Unfortunately I am not using Spring Cloud (reasons out of my control). So my config for eureka is as follows.

For the service applications:

eureka.registration.enabled=true
eureka.name=skeleton-service
eureka.vipAddress=skeleton-service
eureka.statusPageUrlPath=/health/ping
eureka.healthCheckUrlPath=/health/check

eureka.port.enabled=8042
eureka.port=8042

eureka.appinfo.replicate.interval=5

## configuration related to reaching the eureka servers
eureka.preferSameZone=true
eureka.shouldUseDns=false
eureka.serviceUrl.default=http://eureka-container:8080/eureka/v2/

eureka.decoderName=JacksonJson

For the client application (eureka + ribbon)

###Eureka Client configuration for Sample Eureka Client


eureka.registration.enabled=false 
eureka.name=skeleton-web
eureka.vipAddress=skeleton-web
eureka.statusPageUrlPath=/health/ping
eureka.healthCheckUrlPath=/health/check

eureka.port.enabled=8043
eureka.port=8043

## configuration related to reaching the eureka servers
eureka.preferSameZone=true
eureka.shouldUseDns=false
eureka.serviceUrl.default=http://eureka-container:8080/eureka/v2/

eureka.decoderName=JacksonJson

eureka.renewalThresholdUpdateIntervalMs=3000


#####################
# RIBBON STUFF HERE #
#####################

sample-client.ribbon.NIWSServerListClassName=com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList

# expressed in milliseconds
sample-client.ribbon.ServerListRefreshInterval=3000

# movieservice is the virtual address that the target server(s) uses to register with Eureka server
sample-client.ribbon.DeploymentContextBasedVipAddresses=skeleton-service
g00glen00b
  • 41,995
  • 13
  • 95
  • 133
Juan Antonio Gomez Moriano
  • 13,103
  • 10
  • 47
  • 65
  • 1
    I think you should add eureka unregister step to your JVM shutdown hook manually – Azarea Oct 18 '17 at 02:55
  • I suspect @SakuraKyouko is correct in that if you are killing one of your services, then eureka probably never gets your instance's deregistration call(https://github.com/Netflix/eureka/wiki/Eureka-REST-operations) and then has to wait until it fails renewal for 90s (defualt - https://github.com/Netflix/eureka/wiki/Understanding-eureka-client-server-communication#renew). Out of curiosity, how many instances are you typically dealing with? I'm also wondering if self preservation mode may be a factor here. – Nick DeFazio Nov 07 '17 at 14:59

1 Answers1

0

I had faced similar issue in my development , There are multiple things I tried and worked for me .

1)Instead of using eureka registry ,use only underlying ribbon and modify it's health check mechanism as per our need ,for doing this provide own implementation for IPing

public class PingUrl implements com.netflix.loadbalancer.IPing {

public boolean isAlive(Server server) {
        String urlStr = "";
        if (isSecure) {
            urlStr = "https://";
        } else {
            urlStr = "http://";
        }
        urlStr += server.getId();
        urlStr += getPingAppendString();

        boolean isAlive = false;
        try {
            ResponseEntity response = getRestTemplate().getForEntity(urlStr, String.class);
            isAlive = (response.getStatusCode().value()==200);

        } catch (Exception e) {
            ;
        }
        return isAlive;
    }
}

override the load balancing behaviour

@SpringBootApplication
@EnableZuulProxy
@RibbonClients(defaultConfiguration = LoadBalancer.class)
@ComponentScan(basePackages = {"com.test"})
public class APIGateway {   

    public static void main(String[] args) throws Exception {
        SpringApplication.run(APIGateway .class, args);
    }

}

    public class LoadBalancer{

    @Autowired
        IClientConfig ribbonClientConfig;

    @Bean
        public IPing ribbonPing() {

            return new PingUrl(getRoute() + "/ping");
        }
    }

  private String getRoute() {
        return RequestContext.getCurrentContext().getRequest().getServletPath();
}

providing availability filtering rule

public class AvailabilityBasedServerSelectionRule extends AvailabilityFilteringRule {

    @Override
    public Server choose(Object key) {

        Server chosenServer = super.choose(key);

        int count = 1;
        List<Server> reachableServers = this.getLoadBalancer().getReachableServers();
        List<Server> allServers = this.getLoadBalancer().getAllServers();

        if(reachableServers.size() > 0) {
            while(!reachableServers.contains(chosenServer) && count++ < allServers.size()) {
                chosenServer = reachableServers.get(0);
            }
        }
        return chosenServer;
    }

} 2)You can specify the time interval for refreshing the list

ribbon.eureka.ServerListRefreshInterval={time in ms}