前言

最近在学习 SpringCloud 的东西,在使用 RestTemplate 结合 Ribbon 时,自己写的demo死活不过去。

在 Server 的 demo 里,我提供了一个对外的 Controller 。而里面调用的,则是用了这次说的实现软负载均衡的调用方法。

但,其中遇到一个问题,就是下面的:

No instances available for XXX

主要是刚学习,稀里糊涂的,经过一天的测试,终于摸清了原因。待我慢慢道来。

环境

  • mac
  • idea
  • maven
  • springcloud - Hoxton.SR1

第一次demo

第一次的 demo 结构图如下:

Eureka+Ribbon+RestTemplate实现客户端软负载均衡的两种方式_ide

建立 demo 工程,直接用 idea 自行建立即可 ,eureka-server:

Eureka+Ribbon+RestTemplate实现客户端软负载均衡的两种方式_负载均衡_02

eureka-client:

Eureka+Ribbon+RestTemplate实现客户端软负载均衡的两种方式_ide_03

包结构:

Eureka+Ribbon+RestTemplate实现客户端软负载均衡的两种方式_负载均衡_04

在 server 端提供的 Controller ,代码如下:

/**
* @author sy
* @Date 2020/1/16 6:04 下午
* @Desc
**/
@RestController
@RequestMapping("/")
public class ServerController {

@Autowired
private LoadBalancerClient loadBalancerClient;

@Autowired
private RestTemplate restTemplates;

@GetMapping("/msg")
public String testRestTemplate() {
//1. 直接使用 restTemplate 地址写死
RestTemplate restTemplate = new RestTemplate();
return restTemplate.getForObject("http://localhost:8081/hello", String.class);
}

@GetMapping("/msg2")
public String testRestTemplate2() {
//2. loadBalancerClient 获取实例名
RestTemplate restTemplate = new RestTemplate();
ServiceInstance instance = loadBalancerClient.choose("EUREKA-PROVIDER");
String url = String.format("http://%s:%s/hello", instance.getHost(), instance.getPort());
return restTemplate.getForObject(url, String.class);
}

@GetMapping("/msg3")
public String testRestTemplate3() {
//3. 利用 @LoadBalanced 负载均衡动态加载
String url = String.format("http://%s/hello","EUREKA-PROVIDER");
return restTemplates.getForObject(url, String.class);
}
}

其中,msg 是单节点调用,意味着 url 写死的请求。

msg2和msg3则是客户端的软负载,去进行调用。结构图中有2个client注册到服务中心,所以当其中一台挂掉,那就会请求到另一台。

msg2利用了 loadBalancerClient 动态获取主机名和端口。

msg3则是需要用以下的 @LoaderBalance 来进行配置注入:

/**
* @author sy
* @Date 2020/1/17 9:40 上午
* @Desc
**/
@Configuration
public class RestTemplateConfig {

@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}

当时想本意是,为了省事,让 server 端自己充当消费者的情况,但事实上,这种想法是错误的。

服务端里本身去消费 client 的角色,所以上述代码直接发出请求,msg1是可以成功的,但 msg2和msg3则会报错:

No instances available for EUREKA-PROVIDER

第二次 demo

Eureka+Ribbon+RestTemplate实现客户端软负载均衡的两种方式_负载均衡_05

把服务端的 Controller 迁移出来到新的 eureka-client 工程中,再次实现原来的 restTemplate 调用,发现无报错信息。

注意 :

通过上述方法的 testRestTemplate2 和 testRestTemplate3 调用时,他们的服务实例名,都是和下图对等。

//testRestTemplate2
loadBalancerClient.choose("EUREKA-PROVIDER");
//testRestTemplate3
String url = String.format("http://%s/hello","EUREKA-PROVIDER");
return restTemplates.getForObject(url, String.class);

Eureka+Ribbon+RestTemplate实现客户端软负载均衡的两种方式_负载均衡_06

总结

看了许多 No instances available for 这样的错误,但没有一篇是和我遇到的情况是相关的,可能大家遇到的都不是初学遇到的场景,应该没有人会像我一样,demo写入 eureka-server中去吧。。。

反正我是把全网的类似这种错误的解决方案全试了一遍…都没效果,最后还是自己的锅。。。