企业网站定制开发Spring Cloud Feign启动Load balancer does not have available server for client分析

项目场景:

Spring Cloud Feign 企业网站定制开发学习过程中遇到Feign企业网站定制开发访问的时候报错Load balancer does not have available server for client



问题描述:

企业网站定制开发完整报错日志如下

  1. path [] threw exception [Request processing failed; nested exception is java.lang.RuntimeException: com.netflix.client.ClientException: Load balancer does not have available server for client: MS-CUSTOMER] with root cause
  2. com.netflix.client.ClientException: Load balancer does not have available server for client: MS-CUSTOMER
  3. at com.netflix.loadbalancer.LoadBalancerContext.getServerFromLoadBalancer(LoadBalancerContext.java:483) ~[ribbon-loadbalancer-2.2.2.jar:2.2.2]
  4. at com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:184) ~[ribbon-loadbalancer-2.2.2.jar:2.2.2]
  5. at com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:180) ~[ribbon-loadbalancer-2.2.2.jar:2.2.2]
  6. at rx.Observable.unsafeSubscribe(Observable.java:10211) ~[rxjava-1.1.10.jar:1.1.10]
  7. at rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:94) ~[rxjava-1.1.10.jar:1.1.10]
  8. at rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:42) ~[rxjava-1.1.10.jar:1.1.10]
  9. at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) ~[rxjava-1.1.10.jar:1.1.10]
  10. at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) ~[rxjava-1.1.10.jar:1.1.10]




原因分析:

企业网站定制开发从报错信息上看Load balancer does not have available server for client: MS-CUSTOMER,表示负载均衡器没有找到有效的服务信息,此异常是 LoadBalancerContext从LoadBalancer对象中获取服务的时候,  没有找到所调用的服务信息

  1. Server svc = lb.chooseServer(loadBalancerKey);
  2. if (svc == null){
  3. throw new ClientException(ClientException.ErrorType.GENERAL,
  4. "Load balancer does not have available server for client: "
  5. + clientName);
  6. }

 我们查询lb.chooseServer 实现的功能其实是从LoadBalancer对象中的到所有的服务, 然后根据规则从服务中获取一个匹配的服务(相关规则信息可以查看文章 )

List<Server> serverList = getLoadBalancer().getAllServers();

 再看一下getAllServer接口,这个接口返回的是可用的和非可用的服务

  1. /**
  2. * @return All known servers, both reachable and unreachable.
  3. */
  4. public List<Server> getAllServers();

 查看BaseLoadBalancer 如何实现的此方法发现, 服务取自List<Server>集合

  1. protected volatile List<Server> allServerList = Collections
  2. .synchronizedList(new ArrayList<Server>());
  3. @Override
  4. public List<Server> getAllServers() {
  5. return Collections.unmodifiableList(allServerList);
  6. }
  7. /**
  8. * Add a server to the 'allServer' list; does not verify uniqueness, so you
  9. * could give a server a greater share by adding it more than once.
  10. */
  11. public void addServer(Server newServer) {
  12. if (newServer != null) {
  13. try {
  14. ArrayList<Server> newList = new ArrayList<Server>();
  15. newList.addAll(allServerList);
  16. newList.add(newServer);
  17. setServersList(newList);
  18. } catch (Exception e) {
  19. logger.error("LoadBalancer [{}]: Error adding newServer {}", name, newServer.getHost(), e);
  20. }
  21. }
  22. }
  23. /**
  24. * Add a list of servers to the 'allServer' list; does not verify
  25. * uniqueness, so you could give a server a greater share by adding it more
  26. * than once
  27. */
  28. @Override
  29. public void addServers(List<Server> newServers) {
  30. if (newServers != null && newServers.size() > 0) {
  31. try {
  32. ArrayList<Server> newList = new ArrayList<Server>();
  33. newList.addAll(allServerList);
  34. newList.addAll(newServers);
  35. setServersList(newList);
  36. } catch (Exception e) {
  37. logger.error("LoadBalancer [{}]: Exception while adding Servers", name, e);
  38. }
  39. }
  40. }



解决方案:

从上面的源码分析可知,请求处理时候会从会先从一个缓存集合List<Server>  中得到可用和不可用的服务,然后根据规则Rule 过滤获可访问的服务信息并返回Server,那么获取Server为空引起报错的可能场景有如下几个

1. 启动后还没有从注册中心得到List<Server> 的时候lb#chooseServer获取结果为空

第一种可能:客户端没有开启从Eureka 中获取服务列表 ,所以需要检查配置是否错误配置成了 false

  • eureka.client.register-with-eureka=true
  • eureka.client.fetch-registry=true

第二种可能: 客户端已经开启了从注册中心获取服务列表, 获取列表是通过任务获取,此时任务还没执行List<Server>为空, 只需要等一会应用从注册中心检索服务后,问题会自行解决。

第三种可能: 检索后发现没有得到服务, 此时很有可能是你访问的服务应用没有正确注册到注册中心引起, 正确注册后Eureka注册中心可以正确看到发布的服务信息,发布失败一般也是上面的配置出错或其他配置问题

2. 根据Rule规则过滤从List<Server>中没有找到可用的Server

第一种可能: 因为getAllServers()返回的是可用和非可用, Rule规则会过滤到可用, 所以如果你的服务已经Down那么会找不到服务, 可以通过健康检查查看服务状态是否正常

第二种可能: 检查Fegin接口配置的服务名称和要访问的服务名称是否相同,注意字母顺序

3. 其他未知原因,只能通过断点调试了

   

   

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发