【问题标题】:Load balancer does not have available server for client负载均衡器没有可供客户端使用的服务器
【发布时间】:2017-05-15 00:52:34
【问题描述】:

我正在尝试使用 Feign 客户端。下面是我的客户:

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

我从以下简单服务中调用它:

@Service
public class MovieService {

    @Autowired
    MovieApi movieApi;

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

我的 spring boot 应用如下:

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

我收到如下错误:

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.AnnotationConfigApplicationContext@547496c2: startup date [Fri Dec 30 13:07:17 EST 2016]; parent: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@542e560f
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.ConfigurationBasedServerList@45bcfd5
2016-12-30 13: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]

我尝试了不同的方法。但想不出解决办法。我在Spring Cloud Netflix 上也找不到任何相关信息。我也找不到关于discussion thread on StackOverflow 的任何信息。

我在这里缺少什么? TIA。

更多细节:

movie-api微服务的application.yml如下:

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

movie-api 模块上的 Spring Boot 应用:

@SpringBootApplication
public class MovieApiApplication {

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

控制器如下:

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

【问题讨论】:

  • 你在使用 Eureka 或 Consul 之类的服务发现吗?如果是这样,您是否在 Spring Boot 应用程序的 application.yml 中定义了配置以将应用程序注册为 Eureka 的客户端?基本上,Feign 抱怨它在任何地方都找不到注册的服务。您可以使用 Spring Cloud 非常轻松地配置像 Eureka 这样的服务发现。见projects.spring.io/spring-cloud
  • @Bloodysock 所以我应该在哪一侧使用发现服务?在客户端还是 api 端?
  • 您将使用唯一名称注册您的 API(更好的术语是“服务”)到服务发现。客户端只是发现服务并调用它。 Spring Cloud 使开发人员非常容易,尤其是使用 Spring Boot。浏览我在上面链接的网站上记录的示例。您将在 15 分钟内拨打服务电话:)
  • @Bloodysock 是的,你是对的!我错过了“服务”注册。谢谢!。

标签: spring spring-boot spring-cloud-netflix netflix-feign


【解决方案1】:

经过研究,在@Bloodysock 的帮助下,我发现我在“client-app”微服务中缺少远程服务器的注册。该文档位于Spring Cloud Netflix

我在 'client-app' 微服务中使用 application.yml 配置的不带 Eureka 的 Ribbon:

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

【讨论】:

  • 你如何设置它,以便不必硬编码 movie-api 的 url,而是让功能区使用 eureka 找出 movie-api 的 url ??
  • @xpz 据我所知,我们应该做服务器端负载平衡来实现这一点!
  • @xpz 请查看py4u.net/discuss/1754436 了解更多详情
【解决方案2】:

如果您的 Spring Cloud 设置不支持在 application.properties/application.yml 中指定服务器,则必须在 Configuration 类中配置服务 URL。

请注意我的 application.properties [Spring Boot v2.0.0RELEASE, spring-cloud-starter-feign & spring-cloud-starter-中的警告消息功能区 v 1.4.3.RELEASE]

所以我所做的就是写一个配置类如下:

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

然后,将 Spring Boot 应用程序配置为使用此配置,如下所示:

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

无需更改 Feign Proxy 类。仅发布此帖子以作为问题的完整解决方案:

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

就是这样。问题已解决。

【讨论】:

    【解决方案3】:

    问题是您的服务不知道所请求服务的主机。如果您使用的是 Eureka,请将此行放在您的 .properties 文件中:

    eureka.client.fetchRegistry=true

    OR .yml 文件:

    eureka:
        client:
            fetch-registry: true
    

    它将使您的服务与 Eureka 对话并发现所请求服务的主机。

    【讨论】:

    • 获取注册表*
    【解决方案4】:

    我几乎浪费了 2 个小时来寻找根本原因。我错误地在客户端应用程序中导入了 EnableEurekaClient,这是问题的根本原因。我终于通过删除导入解决了这个问题。令我惊讶的是,@EnableDiscoveryClient 不需要以下依赖项。 但是,如果您使用的是 Eureka 命名服务器,则必须使用它。

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

    【讨论】:

    • 谢谢它使用您的解决方案解决了同样的问题。
    【解决方案5】:

    需要在 Eureka Client 的同时添加 Ribbon,否则无法获取服务。

    在我的 pom.xml 我有:

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

    在我的服务代理中:

    @FeignClient(name = "movie-api")
    @RibbonClient(name = "movie-api")
    public interface MovieApi {
        @RequestMapping(method = RequestMethod.GET, value = "/movies/{id}")
        Movie getMovie(@PathVariable("id") Long id);
    }
    

    【讨论】:

    • 把你的项目分享给 github 或 gitlab,这样我可以检查它并做 PR
    【解决方案6】:

    问题是您的服务不知道所请求服务的主机。如果您使用的是 Eureka 和 zuul,请将此行放在您的 zuul .properties 或 .yml 文件中:

    eureka.client.fetch-registry=true

    【讨论】:

      【解决方案7】:

      ClientAppApplication 似乎不知道您的 eureka 服务器地址。 你可以检查你的 applation.yml

      eureka
        instance:
          hostname: cloud-feignorder-consume
        client:
          register-with-eureka: false #default true     
          fetch-registry: true #default true
      

      最后一行你应该检查属性'eureka.client.fetch-registry'。它应该是true或不签名。然后你的客户端可以从eureka服务器获取服务器列表。

      【讨论】:

        【解决方案8】:

        如果没有 eureka,在客户端应用程序中,如果您没有 application.yml 而不是 application.properties 文件,那么您可以在客户端应用程序重新启动之前将属性设置如下:

        currency-exchange-service.ribbon.listOfServers : http://localhost:8000,http://localhost:8001

        【讨论】:

          【解决方案9】:

          在你的 Zuul 网关的 application.properties 文件中添加这一行。

          movie-api.ribbon.listOfServers=http://localhost:8080

          一般来说 - {{name-of-the-service}}.ribbon.listOfServers={{url-of-the-service}}

          这对我有用。

          【讨论】:

            猜你喜欢
            • 2018-06-07
            • 2019-02-09
            • 2017-12-25
            • 2019-04-09
            • 2019-03-23
            • 2016-04-02
            • 2017-06-05
            • 1970-01-01
            • 2021-04-20
            相关资源
            最近更新 更多