SpringCloud实战Ribbon完全脱离Eureka实现自定义负载均衡出错【使用@RibbonClient注解后找不到实例】的解决方案

错误堆栈信息

java.lang.NullPointerException: null
	at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:213) ~[guava-16.0.1.jar:na]
	at com.google.common.cache.LocalCache.get(LocalCache.java:3933) ~[guava-16.0.1.jar:na]
	at com.google.common.cache.LocalCache.getOrLoad(LocalCache.java:3938) ~[guava-16.0.1.jar:na]
	at com.google.common.cache.LocalCache$LocalLoadingCache.get(LocalCache.java:4821) ~[guava-16.0.1.jar:na]
	at com.netflix.loadbalancer.LoadBalancerStats.getServerStats(LoadBalancerStats.java:185) ~[ribbon-loadbalancer-2.3.0.jar:2.3.0]
	at com.netflix.loadbalancer.LoadBalancerStats.getSingleServerStat(LoadBalancerStats.java:372) ~[ribbon-loadbalancer-2.3.0.jar:2.3.0]
	at com.netflix.loadbalancer.AvailabilityPredicate.apply(AvailabilityPredicate.java:73) ~[ribbon-loadbalancer-2.3.0.jar:2.3.0]
	at com.netflix.loadbalancer.AvailabilityPredicate.apply(AvailabilityPredicate.java:35) ~[ribbon-loadbalancer-2.3.0.jar:2.3.0]
	
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw 
exception [Request processing failed; nested exception is 
java.lang.IllegalStateException: No instances available for user-service] with root 
cause

从以上提示信息中可以发现错误原因为java.lang.IllegalStateException: No instances available for user-service] with root cause,无法找到该实例,导致这个出错的原因在于我们使用@RibbonClient指定了自定义的负载均衡配置实现类,可见该类中一定有错误,我们可以通过查看相关实现类以及配置文件控制台输出的一些提示信息来找出原因;

  • application.properties,SpringBoot主配置文件
server.port=8090

spring.application.name=api-getaway

#eureka.client.service-url.defaultZone=http://127.0.0.1:8666/eureka

#消费者无需注册
eureka.client.register-with-eureka=false

logbook.write.level=info
logbook.format.style=curl


ribbon.eureka.enabled=false
#every 15 seconds
server.ribbon.ServerListRefreshInterval=15000

user-service.ribbon.listOfServers=127.0.0.1:8081,127.0.0.1:8082
  • SpringBoot启动类
package com.qingyun.house.api;

import com.qingyun.house.api.config.NewRuleConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.cloud.netflix.ribbon.RibbonClients;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;

//@EnableDiscoveryClient
@RibbonClients(value = {@RibbonClient(name = "user-service",configuration = NewRuleConfig.class)})
@SpringBootApplication
@Controller
public class ApiGetawayApplication {

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

    @Autowired
    public DiscoveryClient discoveryClient;

    @ResponseBody
    @RequestMapping(value = "/get")
    public List<ServiceInstance> getRegister(){
        return discoveryClient.getInstances("user-service");
    }
}
  • Ribbon自定义负载均衡配置类
package com.qingyun.house.api.config;

import com.netflix.loadbalancer.*;
import org.springframework.context.annotation.Bean;

public class NewRuleConfig {

    @Bean
    public IPing ribbonPing(){
        return new PingUrl(false,"/health");
    }

    @Bean
    public IRule ribbonRule(){
        //return new RandomRule();

        return new AvailabilityFilteringRule();
    }
}
  • 发现的可疑日志打印信息
2020-01-07 17:11:32.202  WARN 13272 --- [nio-8090-exec-6] 
com.netflix.loadbalancer.RoundRobinRule  : No up servers available from load balancer: 
DynamicServerListLoadBalancer:{NFLoadBalancer:name=user-service,current list of 
Servers=[127.0.0.1:8081, 127.0.0.1:8082],Load balancer stats=Zone stats: {unknown=
[Zone:unknown;	Instance count:2;	Active connections count: 0;	Circuit breaker 
tripped count: 0;	Active connections per server: 0.0;]

从以上日志中可以发现我们在配置文件中配置的节点信息是不可用的,由此可以确定以上路径是Ping不通的,由此我们去检查服务提供者的日志打印信息。

  • 服务提供者日志打印【需要加入logbook才能查看http请求日志,或者自定义过滤器实现日志打印】:
2020-01-07 17:39:57.693  INFO 13212 --- [nio-8081-exec-9] org.zalando.logbook.Logbook              : Incoming Request: 85a2a255ae3346f4
GET http://127.0.0.1:8081/health HTTP/1.1
host: 127.0.0.1:8081
connection: Keep-Alive
user-agent: Apache-HttpClient/4.5.10 (Java/1.8.0_121)
2020-01-07 17:39:57.696  INFO 13212 --- [nio-8081-exec-9] org.zalando.logbook.Logbook              : Outgoing Response: 85a2a255ae3346f4
Duration: 3 ms
HTTP/1.1 404 Not Found

分析以上日志可以发现http://127.0.0.1:8081/health无法访问,原因在于SpringBoot Actuator健康监测有一个默认前缀为/actuator,所以我们的解决方案有两种:

  1. 直接修改监测默认地址为/,在配置文件中修改
management.endpoints.web.base-path=/
  1. 修改服务调用者的Ping方法中的访问路径为actuator/health
 @Bean
 public IPing ribbonPing(){
     return new PingUrl(false,"/actuator/health");
 }

以上问题被完美解决!
在这里插入图片描述

发布了56 篇原创文章 · 获赞 17 · 访问量 6185

猜你喜欢

转载自blog.csdn.net/qq_43199016/article/details/103878184