feign Load balancer does not have available server for client

Posted Architect剑

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了feign Load balancer does not have available server for client相关的知识,希望对你有一定的参考价值。

记录一个问题,

搭建Spring cloud 使用 feign 发现一个困扰了我一个小时的问题: feign Load balancer does not have available server for client 

对于这个错误,网上相关帖子怎么说的都有,我只是记录一下我怎么解决,各位大神不喜勿喷

首先这个错误 (如果前面步骤,自己检查没问题,那么依次看下一个)

第一步,检查Eureka 服务列表 服务名字配置的是什么 (网上帖子,有说配置instance.appname/hostname的都是无效的)

spring:
  application:
    name: xxx
// 该注解不区分大小写
@FeignClient(name = "xxx/XXX")

第二步:检查是否引入 Ribbon(必须)

<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-ribbon -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
            <version>2.2.6.RELEASE</version>
        </dependency>

原本我引入的是Openfeign,我以为feign底层就是Ribbon就不需要额外引入(而且查看了Maven确实引入了)

 

 第三步: 如果原本引入Eureka-client 

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>3.0.0</version>
        </dependency>

请替换

        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.5.RELEASE</version>
        </dependency>

 

通过上面几步就可以解决掉这个报错

另外延伸几点

第一: 网上有说可以使用

  ribbon:
    listOfServers: http://localhost:8081

上面这段配置,是给那些没有使用Eureka的项目 手动设置的ribbon请求地址。这样相当于给了一个很明确的地址,所以解决掉最开始说的这个错误是可以的(但是不根本)Eureka维护提供者/消费者列表,消费者可以去获得服务列表,如果是靠这种手动的配置去获取,那相当于失去了Eureka一个功能

第二: 有人说通过 如下配置,解决最开始的错误信息,首先这个配置自行百度是干嘛的,其次即使不设置这个值,默认就是true

eureka:
  client:
    register-with-eureka: true
    fetch-registry: true

 

load balancer does not have available server for client: provider

I‘m trying to use Feign client. Below is my feing client:

import com.eprogrammerz.examples.domain.Movie;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * Created by Yogen on 12/26/2016.
 */
@FeignClient(name = "movie-api")
public interface MovieApi {
    @RequestMapping(method = RequestMethod.GET, value = "/movies/{id}")
    Movie getMovie(@PathVariable("id") Long id);
}

I‘m calling it from simple service as below:

@Service
public class MovieService {

    @Autowired
    MovieApi movieApi;

    public Movie findMovie(Long id){
        Movie movieOfTheDay = movieApi.getMovie(id);
        return movieOfTheDay;
    }
}

My spring boot app is as below:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.feign.EnableFeignClients;

@EnableFeignClients(basePackages = {"com.eprogrammerz.examples"})
@EnableCircuitBreaker
@SpringBootApplication
public class ClientAppApplication {

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

build.gradle

buildscript {
    ext {
        springBootVersion = ‘1.4.3.RELEASE‘
    }
    repositories {
        jcenter()
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

apply plugin: ‘java‘
apply plugin: ‘eclipse‘
apply plugin: ‘org.springframework.boot‘

jar {
    baseName = ‘client-app‘
    version = ‘0.0.1-SNAPSHOT‘
}
sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
    jcenter()
    mavenCentral()
    maven { url "https://repo.spring.io/snapshot" }
    maven { url "https://repo.spring.io/milestone" }
}


dependencies {
    compile(‘org.springframework.cloud:spring-cloud-starter-feign‘)
    // https://mvnrepository.com/artifact/com.netflix.hystrix/hystrix-core
    compile(‘org.springframework.cloud:spring-cloud-starter-hystrix‘)
    compile("org.springframework.boot:spring-boot-starter-web"){
        exclude group: ‘org.springframework.boot‘, module: ‘spring-boot-starter-logging‘
    }
    compileOnly(‘org.projectlombok:lombok‘)
    testCompile(‘org.springframework.boot:spring-boot-starter-test‘)
}

dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:Camden.BUILD-SNAPSHOT"
        mavenBom "org.springframework.boot:spring-boot-starter-parent:${springBootVersion}"
    }
}

I‘m getting error as below:

2016-12-30 13:07:16.894  INFO 6748 --- [nio-8082-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet ‘dispatcherServlet‘: initialization completed in 39 ms
2016-12-30 13:07:16.939  INFO 6748 --- [nio-8082-exec-1] c.e.e.controllers.RequestController      : Calling findMovie(1203)
2016-12-30 13:07:17.240  INFO 6748 --- [rix-movie-api-1] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.[email protected]: startup date [Fri Dec 30 13:07:17 EST 2016]; parent: org.springframework.boot.context.embedded.[email protected]
2016-12-30 13:07:17.318  INFO 6748 --- [rix-movie-api-1] f.a.AutowiredAnnotationBeanPostProcessor : JSR-330 ‘javax.inject.Inject‘ annotation found and supported for autowiring
2016-12-30 13:07:17.619  INFO 6748 --- [rix-movie-api-1] c.netflix.config.ChainedDynamicProperty  : Flipping property: movie-api.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
2016-12-30 13:07:17.670  INFO 6748 --- [rix-movie-api-1] c.n.u.concurrent.ShutdownEnabledTimer    : Shutdown hook installed for: NFLoadBalancer-PingTimer-movie-api
2016-12-30 13:07:17.727  INFO 6748 --- [rix-movie-api-1] c.netflix.loadbalancer.BaseLoadBalancer  : Client:movie-api instantiated a LoadBalancer:DynamicServerListLoadBalancer:{NFLoadBalancer:name=movie-api,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null
2016-12-30 13:07:17.739  INFO 6748 --- [rix-movie-api-1] c.n.l.DynamicServerListLoadBalancer      : Using serverListUpdater PollingServerListUpdater
2016-12-30 13:07:17.746  INFO 6748 --- [rix-movie-api-1] c.n.l.DynamicServerListLoadBalancer      : DynamicServerListLoadBalancer for client movie-api initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=movie-api,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:com.netflix.loadbalancer.[email protected]2016-12-3013:07:18.191 ERROR 6748---[nio-8082-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]:Servlet.service()for servlet [dispatcherServlet]in context with path [] threw exception [Request processing failed; nested exception is com.netflix.hystrix.exception.HystrixRuntimeException:MovieApi#getMovie(Long) failed and no fallback available.] with root cause

com.netflix.client.ClientException:Load balancer does not have available server for client: movie-api
    at com.netflix.loadbalancer.LoadBalancerContext.getServerFromLoadBalancer(LoadBalancerContext.java:468)~[ribbon-loadbalancer-2.2.0.jar:2.2.0]
    at com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:184)~[ribbon-loadbalancer-2.2.0.jar:2.2.0]
    at com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:180)~[ribbon-loadbalancer-2.2.0.jar:2.2.0]
    at rx.Observable.unsafeSubscribe(Observable.java:10211)~[rxjava-1.1.10.jar:1.1.10]
    at rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:94)~[rxjava-1.1.10.jar:1.1.10]
    at rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:42)~[rxjava-1.1.10.jar:1.1.10]
    at rx.Observable.unsafeSubscribe(Observable.java:10211)~[rxjava-1.1.10.jar:1.1.10]
    at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber$1.call(OperatorRetryWithPredicate.java:127)~[rxjava-1.1.10.jar:1.1.10]
    at rx.internal.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.enqueue(TrampolineScheduler.java:73)~[rxjava-1.1.10.jar:1.1.10]
    at rx.internal.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.schedule(TrampolineScheduler.java:52)~[rxjava-1.1.10.jar:1.1.10]
    at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber.onNext(OperatorRetryWithPredicate.java:79)~[rxjava-1.1.10.jar:1.1.10]
    at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber.onNext(OperatorRetryWithPredicate.java:45)~[rxjava-1.1.10.jar:1.1.10]
    at rx.internal.util.ScalarSynchronousObservable$WeakSingleProducer.request(ScalarSynchronousObservable.java:276)~[rxjava-1.1.10.jar:1.1.10]
    at rx.Subscriber.setProducer(Subscriber.java:209)~[rxjava-1.1.10.jar:1.1.10]
    at rx.internal.util.ScalarSynchronousObservable$JustOnSubscribe.call(ScalarSynchronousObservable.java:138)~[rxjava-1.1.10.jar:1.1.10]
    at rx.internal.util.ScalarSynchronousObservable$JustOnSubscribe.call(ScalarSynchronousObservable.java:129)~[rxjava-1.1.10.jar:1.1.10]
    at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)~[rxjava-1.1.10.jar:1.1.10]
    at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)~[rxjava-1.1.10.jar:1.1.10]
    at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)~[rxjava-1.1.10.jar:1.1.10]
    at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)~[rxjava-1.1.10.jar:1.1.10]
    at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)~[rxjava-1.1.10.jar:1.1.10]
    at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)~[rxjava-1.1.10.jar:1.1.10]
    at rx.Observable.subscribe(Observable.java:10307)~[rxjava-1.1.10.jar:1.1.10]
    at rx.Observable.subscribe(Observable.java:10274)~[rxjava-1.1.10.jar:1.1.10]
    at rx.observables.BlockingObservable.blockForSingle(BlockingObservable.java:445)~[rxjava-1.1.10.jar:1.1.10]
    at rx.observables.BlockingObservable.single(BlockingObservable.java:342)~[rxjava-1.1.10.jar:1.1.10]
    at com.netflix.client.AbstractLoadBalancerAwareClient.executeWithLoadBalancer(AbstractLoadBalancerAwareClient.java:102)~[ribbon-loadbalancer-2.2.0.jar:2.2.0]
    at org.springframework.cloud.netflix.feign.ribbon.LoadBalancerFeignClient.execute(LoadBalancerFeignClient.java:63)~[spring-cloud-netflix-core-1.2.4.BUILD-SNAPSHOT.jar:1.2.4.BUILD-SNAPSHOT]
    at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:97)~[feign-core-9.3.1.jar:na]
    at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:76)~[feign-core-9.3.1.jar:na]
    at feign.hystrix.HystrixInvocationHandler$1.run(HystrixInvocationHandler.java:108)~[feign-hystrix-9.3.1.jar:na]
    at com.netflix.hystrix.HystrixCommand$2.call(HystrixCommand.java:301)~[hystrix-core-1.5.6.jar:1.5.6]
    at com.netflix.hystrix.HystrixCommand$2.call(HystrixCommand.java:297)~[hystrix-core-1.5.6.jar:1.5.6]
    at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:46)~[rxjava-1.1.10.jar:1.1.10]
    at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:35)~[rxjava-1.1.10.jar:1.1.10]
    at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)~[rxjava-1.1.10.jar:1.1.10]
    at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)~[rxjava-1.1.10.jar:1.1.10]
    at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)~[rxjava-1.1.10.jar:1.1.10]
    at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)~[rxjava-1.1.10.jar:1.1.10]
    at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)~[rxjava-1.1.10.jar:1.1.10]
    at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)~[rxjava-1.1.10.jar:1.1.10]
    at rx.Observable.unsafeSubscribe(Observable.java:10211)~[rxjava-1.1.10.jar:1.1.10]
    at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:51)~[rxjava-1.1.10.jar:1.1.10]
    at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:35)~[rxjava-1.1.10.jar:1.1.10]
    at rx.Observable.unsafeSubscribe(Observable.java:10211)~[rxjava-1.1.10.jar:1.1.10]
    at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:41)~[rxjava-1.1.10.jar:1.1.10]
    at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:30)~[rxjava-1.1.10.jar:1.1.10]
    at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)~[rxjava-1.1.10.jar:1.1.10]
    at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)~[rxjava-1.1.10.jar:1.1.10]
    at rx.Observable.unsafeSubscribe(Observable.java:10211)~[rxjava-1.1.10.jar:1.1.10]
    at rx.internal.operators.OperatorSubscribeOn$1.call(OperatorSubscribeOn.java:94)~[rxjava-1.1.10.jar:1.1.10]
    at com.netflix.hystrix.strategy.concurrency.HystrixContexSchedulerAction$1.call(HystrixContexSchedulerAction.java:56)~[hystrix-core-1.5.6.jar:1.5.6]
    at com.netflix.hystrix.strategy.concurrency.HystrixContexSchedulerAction$1.call(HystrixContexSchedulerAction.java:47)~[hystrix-core-1.5.6.jar:1.5.6]
    at com.netflix.hystrix.strategy.concurrency.HystrixContexSchedulerAction.call(HystrixContexSchedulerAction.java:69)~[hystrix-core-1.5.6.jar:1.5.6]
    at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)~[rxjava-1.1.10.jar:1.1.10]
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)~[na:1.8.0_51]
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)~[na:1.8.0_51]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)~[na:1.8.0_51]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)~[na:1.8.0_51]
    at java.lang.Thread.run(Thread.java:745)[na:1.8.0_51]

I tried different way. But couldn‘t figure out the solution. I couldn‘t find any information about this on Spring Cloud Netflix too. I couldn‘t find any information on discussion thread on StackOverflow too.

What I‘m missing here? TIA.

Further Details:

application.yml for movie-api microservice is as below:

server:
  port: 8090
logging:
  config: classpath:log4j2.yml
spring:
  application:
    name: movie-api

Spring boot app on movie-api module:

@SpringBootApplication
public class MovieApiApplication {

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

And controller is as below:

@RestController
@Slf4j
public class MovieController {
    @Autowired
    private MovieRepository movieRepository;

    @RequestMapping("/movies/{id}")
    public ResponseEntity<Movie> getBook(@PathVariable("id") Long id){
        log.trace("getBook({})",id);
        Optional<Movie> movie = Optional.of(movieRepository.findOneById(id));
        if(movie.isPresent())
            return new ResponseEntity(movie.get(), HttpStatus.OK);
        return new ResponseEntity<Movie>(HttpStatus.NOT_FOUND);
    }
}
  • 1
    Are you using a service discovery such as Eureka or Consul? If so, have you defined the configuration in your Spring Boot app‘s application.yml to register the app as a client to Eureka? Basically, Feign is complaining that it could not find the service registered anywhere. You can very easily configure a service discovery like Eureka using Spring Cloud. See projects.spring.io/spring-cloud – Bloodysock Dec 30 ‘16 at 22:37
  • 1
    @Bloodysock so on which side should i use discovery service? Here on client side or api side? – Yogen RaiJan 1 ‘17 at 2:09
  • 1
    You‘d register your API (better term would be "service") with a unique name to the service discovery. The client simply discovers the service and invokes it. Spring Cloud makes it real easy for the developer especially with Spring Boot. Go through the example documented at the site I linked above. You will on your way making the service calls in 15 minutes :) – Bloodysock Jan 1 ‘17 at 16:04
  •  
    @Bloodysock yes you are right! i was missing ‘service‘ registration. Thank you!. – Yogen Rai Jan 3 ‘17 at 6:44

3 Answers

After doing research, and with help of @Bloodysock, I found that I was missing registration of remote server in ‘client-app‘ micro-service. The document is at Spring Cloud Netflix.

I used Ribbon without Eureka with configuration in application.yml in ‘client-app‘ micro-service as:

movie-api:
  ribbon:
    listOfServers: http://localhost:8090
 

The problem is that your service doesn‘t know the host of requested service. If you are using Eureka, put this line on your .properties or .yml file:

eureka.client.fetchRegistry=true

OR

eureka: client: fetchRegistry: true

It‘ll make your service talk with Eureka and discovers host of requested service.

If you Spring Cloud set up does not support specifying the servers in application.properties/application.yml, you have to configure the services URL in a Configuration class.

Pls, note the warning message in my application.properties [Spring Boot v2.0.0RELEASE, spring-cloud-starter-feign & spring-cloud-starter-ribbon v 1.4.3.RELEASE]

技术分享图片

So what I did was to write a Configuration class as follows:

@Configuration
class LocalRibbonClientConfiguration {
    @Bean
    public ServerList<Server> ribbonServerList() {
        // return new ConfigurationBasedServerList();
        StaticServerList<Server> staticServerList = new StaticServerList<>((new Server("localhost", 8001)),
                new Server("localhost", 8000));
        return staticServerList;
    }
}

Then, configured the Spring Boot Application to use this configuration as follows:

@SpringBootApplication
@EnableFeignClients("my-package.currencyconversionservice")
@RibbonClient(name = "currency-conversion-service", configuration = LocalRibbonClientConfiguration.class)
public class CurrencyConversionServiceApplication {
 // nothing new here...
}

No need to change the Feign Proxy class. Posting just for this post to be served as a complete solution to the problem:

@FeignClient(name="currency-exchange-service")
@RibbonClient(name="currency-exchange-service")
public interface CurrencyExchangeServiceProxy {
    @GetMapping("/currency-exchange/from/{from}/to/{to}")
    public CurrencyConversionBean retrieveExchangeValue(@PathVariable("from") String from, @PathVariable("to") String to);
}

That‘s all. The problem was fixed.

以上是关于feign Load balancer does not have available server for client的主要内容,如果未能解决你的问题,请参考以下文章

迁移 Feign Load Balancer 实现以兼容 Spring cloud 2020.0.0

Load balancer does not have available server for client

getway API网关报错:Load balancer does not have available server for client: vat-core

FeignLoad balancer does not contain an instance for the service xxx-service

FeignLoad balancer does not contain an instance for the service xxx-service

Load Balancer