简介

SpringCloud Ribbon是一个基于HTTP和TCP的客户端的负载均衡工具,它基于Netflix Ribbon实现。通过SpringCloud 的封装,可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡的服务调用。

注意这里的两个关键词:

客户端:Ribbon需要将注册中心的服务示例拉去到本地进行缓存,并在本地完成负载均衡的动作,默认使用轮询的方式。负载均衡:Ribbon只是进行负载均衡的操作,选取合适的微服务示例来提供给RestTemplate,请求的操作由后者完成。

项目准备

必要准备

引入依赖

如果使用的是eureka client 和 consul client,无须引入依赖。因为在eureka、consul中默认集成了ribbon组件

org.springframework.cloud

spring-cloud-starter-netflix-ribbon

2.2.8.RELEASE

创建RestTemplate配置类

这样我们只需要在需要调用其他服务的控制器中使用@Autowired注解注入即可

@Configuration

public class BeansConfig {

@Bean

public RestTemplate restTemplate(){

return new RestTemplate();

}

}

我使用8083、8084、8085同时运行了订单服务来构成订单服务集群。

编写测试接口

Ribbon提供简单的三种方式来获取配置中心的服务示例或者完成负载均衡

DiscoveryClient

DiscoveryClient可以指定服务的名称来获取配置中心上的实例列表,这个对象是没有实现负载均衡的。

@Slf4j

@RestController

@RequestMapping("/users")

public class UserController {

/**

* 服务注册发现客户端对象

*/

@Autowired

private DiscoveryClient discoveryClient;

@Autowired

private RestTemplate restTemplate;

/**

* 获取用户的订单

*/

@GetMapping("/id/{id}/orders")

public String getUserOrders(@PathVariable("id") Integer id){

// 获取注册中心指定服务全部的示例

List instances = discoveryClient.getInstances("ORDERS");

instances.forEach(instance -> log.info("DiscoveryClient获取到[ORDERS]服务示例 -> 主机[{}],端口[{}],Uri[{}]", instance.getHost(), instance.getPort(), instance.getUri()));

// 这里注意,取得是实例列表里面的第一个实例(可能为空),这里可以手动写一个算法,从instances随机获取一个实例

return restTemplate.getForObject(instances.get(0).getUri+"/orders/uId/"+id, String.class);

}

}

浏览器访问http://localhost:8082/users/id/2/orders

返回数据:20210726120030X2P8083

多次请求发现还是返回同样的数据,因为我们没有进行负载均衡,在代码中写死了,instances.get(0).getUri,始终都是向第一个实例发送请求的。

LoadBalancerClient

LoadBalancerClient这是一个负载均衡的客户端对象,使用它提供的choose方法可以使用负载均衡来获取一个服务的实例,这里返回的是单个对象,默认的方式也是沦陷。

@Slf4j

@RestController

@RequestMapping("/users")

public class UserController {

/**

* 负载均衡客户端对象

*/

@Autowired

private LoadBalancerClient loadBalancerClient;

@Autowired

private RestTemplate restTemplate;

/**

* 获取用户的订单

*/

@GetMapping("/id/{id}/orders")

public String getUserOrders(@PathVariable("id") Integer id){

// 使用负载均衡获取服务示例对象,默认轮询

ServiceInstance instance = loadBalancerClient.choose("ORDERS");

log.info("LoadBalancerClient获取到[ORDERS]服务示例 -> 主机[{}],端口[{}],Uri[{}]", instance.getHost(), instance.getPort(), instance.getUri());

return restTemplate.getForObject(instance.getUri+"/orders/uId/"+id, String.class);

}

}

多次在浏览器访问http://localhost:8082/users/id/2/orders

返回数据:

20210726120030X2P8085

20210726120030X2P8084

20210726120030X2P8083

这里可以看到,这样就实现了负载均衡。

@LoadBalanced

@LoadBalanced注解可以对上面的LoadBalancerClient进行再一次的简化,省掉编写loadBalancerClient.choose("ORDERS");这个语句,将这个对象声明在RestTemplate的生成方法上面可以让生成的对象具有负载均衡的能力。

@Configuration

public class BeansConfig {

/**

* LoadBalanced 为restTemplate对象赋予负载均衡的职责

*/

@Bean

@LoadBalanced

public RestTemplate restTemplate(){

return new RestTemplate();

}

}

@Slf4j

@RestController

@RequestMapping("/users")

public class UserController {

@Autowired

private RestTemplate restTemplate;

/**

* 获取用户的订单

*/

@GetMapping("/id/{id}/orders")

public String getUserOrders(@PathVariable("id") Integer id){

// ORDERS为注册中心服务的名称,框架会进行处理

return restTemplate.getForObject("http://ORDERS/orders/uId/"+id, String.class);

}

}

多次在浏览器访问http://localhost:8082/users/id/2/orders

返回数据:

20210726120030X2P8085

20210726120030X2P8084

20210726120030X2P8083

这里可以看到,这样也实现了负载均衡。

查看原文