什么是Ribbon?
Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现,通过Spring Cloud的封装,可以让我们轻松地将面向服务的Rest模板请求自动转换成客户端负载均衡的服务调用。
Ribbon只具有负载均衡的能力,并不具有发送请求的能力。所以,需要配合服务通信组件,如:RestTemplate
Ribbon在微服务中扮演的角色
Ribbon实现了从注册中心中获取服务列表的能力。
然后通过获取到的服务列表,采用负载均衡算法(Ribbon默认采用的是轮训方式),利用通信框架(RestTemplate或Feign等)进行服务调用。
通信的三种方式
有三种方式可以实现基于服务名+负载均衡的服务间通信方式。分别是:
DiscoveryClient + 自己实现负载均衡 + RestTemplate
LoadBalanceClient + RestTemplate
@LoadBalanced + RestTemplate
下面就来介绍一下这三种通信方式如何实现
准备工作
首先启动Nacos,两个项目都加入Nacos的依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
由于Nacos已经集成了Ribbon,所以,我们就不需要额外引入Ribbon了
其次,在application.yml配置文件中加入Nacos的配置信息
server:
port: 7000
spring:
application:
name: ribbon-producer
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
server:
port: 7002
spring:
application:
name: ribbon-consumer
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
方式一:DiscoveryClient
优点:客户获得指定服务名称下的所有服务实例。
缺点:没有负载均衡,需要通过获取服务列表,来编程实现负载均衡。
DiscoveryClient的实现类是NacosDiscoveryClient
实现方式 (【注意】不能加@LoadBalanced,否则请求失败)
@Resource
private DiscoveryClient discoveryClient;
/**
* 使用DiscoveryClient获取服务列表进行随机服务调用(http://localhost:7002/consumer/discoveryClient)
*/
@GetMapping("/discoveryClient")
public String discoveryClient() {
log.info("discoveryClient invoke!");
// 获得服务id下的服务信息
List<ServiceInstance> serviceInstanceList = discoveryClient.getInstances("ribbon-producer");
serviceInstanceList.forEach(serviceInstance -> log.info("host={}, port={}, uri={}",
serviceInstance.getHost(), serviceInstance.getPort(), serviceInstance.getUri()));
// 自实现具体服务的请求
int num = new Random().nextInt(serviceInstanceList.size());
URI uri = serviceInstanceList.get(num).getUri();
log.info("num={}, uri={}", num, uri);
return restTemplate.getForObject( uri + "/provider/hello", String.class);
}
方式二:LoadBlanceClient
优点:自带负载均衡算法,不需要自己实现了。
缺点:使用时需要每次先根据服务id获取一个负载均衡机器,然后再通过RestTemplate调用服务。
LoadBalanceClient的实现类是RibbonLoadBalancerClient
实现方式 (【注意】不能加@LoadBalanced,否则请求失败)
@Resource
private LoadBalancerClient loadBalancerClient;
/**
* 使用LoadBalancerClient自带的负载均衡功能执行服务调用
*(http://localhost:7002/consumer/loadBalancerClient)
*/
@GetMapping("/loadBalancerClient")
public String loadBalancerClient() {
log.info("loadBalancerClient invoke!");
// 获得负载均衡实例
ServiceInstance serviceInstance = loadBalancerClient.choose("ribbon-producer");
log.info("uri={}", serviceInstance.getUri());
return restTemplate.getForObject(serviceInstance.getUri()+"/provider/hello", String.class);
}
方式三:@LoadBalanced
基于LoadBalanceClient,提供了使用更方便的@LoadBalanced注解。
优点:使得RestTemplate实例具有了负载均衡的能力,不需要特殊调用loadBalanceClient实例的choose方法获得负载均衡计算出的实例了。使用方式,跟普通RestTemplate一样。非常简单。
缺点:依然还需要指定请求的uri和返回值类型。调用依然没有基于rpc方式简洁和直观。
修饰范围:方法上。
作用:让restTemplate具有ribbon负载均衡特性。使用更简单。
实现方式
@Bean
@LoadBalanced // 增加LoadBalanced注解
public RestTemplate restTemplate() {
return new RestTemplate();
}
/**
* 使用@LoadBalanced修饰的RestTemplate来执行具有负载均衡功能的服务调用
*(http://localhost:7002/consumer/loadBalancerAnnotation)
*/
@GetMapping("/loadBalancerAnnotation")
public String loadBalancerAnnotation() {
log.info("loadBalancerAnnotation invoke!");
// 获得负载均衡实例
return restTemplate.getForObject("http://ribbon-producer/provider/hello", String.class);
}
今天的文章内容就这些了:
写作不易,笔者几个小时甚至数天完成的一篇文章,只愿换来您几秒钟的 点赞 & 分享 。
更多技术干货,欢迎大家关注公众号“爪哇缪斯” ~ (^o^)/ ~ 「干货分享,每天更新」