什么是Ribbon?它的作用是什么?

892 阅读3分钟

什么是Ribbon?

Spring Cloud Ribbon是一个基于HTTPTCP的客户端负载均衡工具,它基于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^)/ ~ 「干货分享,每天更新」