【springcloud】Ribbon详解

本文涉及的产品
网络型负载均衡 NLB,每月750个小时 15LCU
应用型负载均衡 ALB,每月750个小时 15LCU
传统型负载均衡 CLB,每月750个小时 15LCU
简介: Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现。简单点说,其主要功能是提供客户端的软件负载均衡算法和服务调用。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接,权重等)去连接这些机器。

一、概述



Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现。简单点说,其主要功能是提供客户端的软件负载均衡算法和服务调用。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接,权重等)去连接这些机器。


  1. LB负载均衡(Load Balance)是什么?


简单的说就是将用户的请求平摊的分配到多个服务器上,从而达到系统的HA(高可用)。常见的负载均衡的软件有Nginx、LVS和硬件F5等。

  1. Ribbon本地负载均衡客户端与Nginx服务端负载均衡区别?
  • Nginx是服务器负载均衡,客户端所有请求都会交给nginx,然后由nginx实现转发请求,即负载均衡是由服务端实现的。即「集中式LB」,在服务端消费方和提供方之间使用独立的LB设施(可以是硬件,如F5,也可以是软件,如nginx),由该设施负责把访问请求通过某种策略转发至服务的提供方。
  • Ribbon本地负载均衡,在调用微服务接口时候,会在注册中心上获取注册信息服务列表之后缓存到本地JVM中,从而在本地实现RPC远程服务调用技术。即「进程内LB」,将LB逻辑集成到消费方,消费方从服务服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择出一个合适的服务器。



二、基本使用



  1. 服务提供者只需要启动多个服务实例并注册到一个注册中心或多个相关联的服务注册中心。
  2. 服务消费者直接通过调用被@LoadBalanced注解修饰的Restemplate来实现面向服务的接口调用。


1. 使用@LoadBalanced


import org.springframework.cloud.client.loadbalancer.LoadBalanced;
  import org.springframework.context.annotation.Bean;
  import org.springframework.context.annotation.Configuration;
  import org.springframework.web.client.RestTemplate;
  @Configuration
  public class RemoteClientConfiguration {
      @Bean
      @LoadBalanced
      public RestTemplate restTemplate(){
          return new RestTemplate();
      }
  }


2. 调用服务提供者


公用java资源


public class ResultDto<T> {
      private Integer msgCode;
      private String msgTip;
      private T data;
      public Integer getMsgCode() {
          return msgCode;
      }
      public void setMsgCode(Integer msgCode) {
          this.msgCode = msgCode;
      }
      public String getMsgTip() {
          return msgTip;
      }
      public void setMsgTip(String msgTip) {
          this.msgTip = msgTip;
      }
      public T getData() {
          return data;
      }
      public void setData(T data) {
          this.data = data;
      }
      public static ResultDto error(Integer msgCode, String msgTip){
          ResultDto objectResultDto = new ResultDto();
          objectResultDto.setMsgCode(msgCode);
          objectResultDto.setMsgTip(msgTip);
          return objectResultDto;
      }
      public static <T> ResultDto success(Integer msgCode,String msgTip,T data){
          ResultDto objectResultDto = new ResultDto();
          objectResultDto.setMsgCode(msgCode);
          objectResultDto.setMsgTip(msgTip);
          objectResultDto.setData(data);
          return objectResultDto;
      }
  }


I、 GET请求


  1. 基本使用示例
//服务提供者名称
private static final String REMOTE_URL = "http://CLOUD-PAYMENT-SERVICE";
// getForEntity
@GetMapping("/payment/list")
public ResultDto listPayment(){
    ResponseEntity<ResultDto> forEntity = restTemplate.getForEntity(REMOTE_URL + "/payment/list", ResultDto.class);
    return forEntity.getBody();
}
// getForObject
@GetMapping("/payment/list")
public ResultDto listPayment(){
    return restTemplate.getForObject(REMOTE_URL + "/payment/list", ResultDto.class);
}


  1. getForEntity方法详解
/** 
  * 一、 getForEntity(String url, Class<T> responseType, Object... uriVariables)
  * url: 为请求地址
  * responseType: 响应结果类型
  * uriVariables: url中参数绑定,为变长参数(即数组),可以多个;它的顺序对应url中占位符定义的数字顺序。
  */
  @GetMapping("/payment/listEntity")
  public ResultDto listEntity(@RequestParam String uuid,@RequestParam String paymentType){
      //占位符中的数字对应变长参数的顺序
      ResponseEntity<ResultDto> forEntity = restTemplate.getForEntity(REMOTE_URL + "/payment/list?uuid={1}&paymentType={2}", ResultDto.class,uuid,paymentType);
      return forEntity.getBody();
  }
  /**
  * 二、 getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables)
  * url: 为请求地址
  * responseType: 响应结果类型
  * uriVariables: url中参数绑定,为map类型,key为url中占位符的值
  */
  @GetMapping("/payment/listEntity")
  public ResultDto listEntity(@RequestParam String uuid,@RequestParam String paymentType){
      Map<String,String> queryParams = new HashMap<>();
      queryParams.put("uuid",uuid);
      queryParams.put("paymentType",paymentType);
      //key为url中占位符的值
      ResponseEntity<ResultDto> forEntity = restTemplate.getForEntity(REMOTE_URL + "/payment/list?uuid={uuid}&paymentType={paymentType}", ResultDto.class,queryParams);
      return forEntity.getBody();
  }
  /**
  *三、getForEntity(URI url, Class<T> responseType)
  * url: 指定访问地址和参数绑定
  * responseType: 响应结果类型
  */
  @GetMapping("/payment/listEntity")
  public ResultDto listEntity(@RequestParam String uuid,@RequestParam String paymentType){
      UriComponents uriComponents = UriComponentsBuilder.fromUriString(REMOTE_URL + "/payment/list?uuid={uuid}&paymentType={paymentType}")
              .build()
              .expand(uuid)
              .expand(paymentType)
              .encode();
      URI uri = uriComponents.toUri();
      ResponseEntity<ResultDto> forEntity = restTemplate.getForEntity(uri, ResultDto.class);
      return forEntity.getBody();
  }


  1. getForObject详解
//参数及其示例同getForEntity,不在重复写
  1. getForObject(String url, Class<T> responseType, Object... uriVariables)
  2. getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables)
  3. getForObject(URI url, Class<T> responseType)


II、POST请求


  1. 请求示例
// 1. postForObject
    @PostMapping("/save")
    public ResultDto save(@RequestBody Orders orders){
        Payment payment = new Payment();
        payment.setCreateTime(orders.getCreateTime());
        payment.setSerialPayment(orders.getSerialOrder());
        ResultDto resultDto = restTemplate.postForObject("http://localhost:8888" + "/payment/add", payment, ResultDto.class);
        return resultDto;
    }
    //2. postForEntity
    @PostMapping("/save")
    public ResultDto save(@RequestBody Orders orders){
        Payment payment = new Payment();
        payment.setCreateTime(orders.getCreateTime());
        payment.setSerialPayment(orders.getSerialOrder());
        ResultDto resultDto = restTemplate.postForObject("http://localhost:8888" + "/payment/add", payment, ResultDto.class);
        return resultDto;
    }
    //3. postForLocation,暂时没有想到应用场景,先只给一个使用方法
    URI uri = restTemplate.postForLocation(REMOTE_URL + "/save", payment);


III、PUT请求


1. void put(String var1, @Nullable Object var2, Object... var3)
2. void put(String var1, @Nullable Object var2, Map<String, ?> var3)
3. void put(URI var1, @Nullable Object var2)
//其用法和postForObject基本类似,不再赘述


XI、DELETE请求


1. void delete(String var1, Object... var2);
2. void delete(String var1, Map<String, ?> var2);
3. void delete(URI var1);
//其用法和postForObject基本类似,不再赘述


三、Ribbon工作流程



  1. 选择EurekaServer(注册中心),优先选择同一个区域内负载最少的EurekaServer
  2. 根据用户指定的策略,从注册中心获取的服务列表中选择一个服务地址并执行


其中Ribbon提供了多种策略,如下:


名称 功能
RoundRobinLoadBalancer 轮询
RandomRule 随机
RetryRule 先按照RoundRobinLoadBalancer的策略获取服务,如果获取服务失败,则在指定时间内重试,获取可用的服务
WeightedResponseTimeRule 对RoundRobinLoadBalancer的拓展,响应速度越快的实例权重越大,越容易被选择
BestAvailableRule 优先过滤掉由于访问故障而处于断路状态器跳闸的服务,然后选一个并发量最小的服务
AvailabilityFilteringRule 先过滤掉故障服务,再选择并发小的实例
ZoneAvoidanceRule 默认规则,复合判断server所在区域的性能和server的可用性选择服务器


四、Ribbon更换默认策略



  1. java bean
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RemoteClientConfiguration {
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
    //更换策略为随机
    @Bean
    public IRule myRule(){
        return new RandomRule();
    }
}


  1. application.yml
#设置负载均衡策略 cloud-payment-service 为调用的服务的名称  value为策略全限定名
cloud-payment-service:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule


五、自定义负载均衡策略



注意:官方文档明确指出,自定义配置类不能放在@ComponentScan所扫描的当前包下及其子包下,否则我们自定义的配置类就会被所有的Ribbon客户端所共享,达步到特殊化定制的目的。


  1. 在Order(ComponentScan能扫描到的最跟目录)上新建同级目录myrule


  1. 在myrule包下新建MySelfRule
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MySelfRule {
    @Bean
    public IRule myRule(){
        //这里可以自定义规则,为了演示方便,直接使用了随机策略
        return new RandomRule(); //随机
    }
}


  1. 在主启动类上添加@RibbonClient
@EnableSwagger2 //swagger
@EnableEurekaClient //eureka
@EnableDiscoveryClient //服务发现
@SpringBootApplication //springboot启动注解
@RibbonClient(name = "cloud-payment-service",configuration = MySelfRule.class) //name为要使用的服务名字,configuration指向自己定义的配置
@MapperScan("com.yuyue.online.springcloud.order.mapper")
public class OrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class,args);
    }
}
相关实践学习
SLB负载均衡实践
本场景通过使用阿里云负载均衡 SLB 以及对负载均衡 SLB 后端服务器 ECS 的权重进行修改,快速解决服务器响应速度慢的问题
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
目录
相关文章
|
22天前
|
负载均衡 监控 网络协议
SpringCloud之Ribbon使用
通过以上步骤,就可以在Spring Cloud项目中有效地使用Ribbon来实现服务调用的负载均衡,提高系统的可靠性和性能。在实际应用中,根据具体的业务场景和需求选择合适的负载均衡策略,并进行相应的配置和优化,以确保系统的稳定运行。
40 15
|
22天前
|
负载均衡 算法 Java
除了 Ribbon,Spring Cloud 中还有哪些负载均衡组件?
这些负载均衡组件各有特点,在不同的场景和需求下,可以根据项目的具体情况选择合适的负载均衡组件来实现高效、稳定的服务调用。
43 5
|
3月前
|
负载均衡 Java Nacos
SpringCloud基础1——远程调用、Eureka,Nacos注册中心、Ribbon负载均衡
微服务介绍、SpringCloud、服务拆分和远程调用、Eureka注册中心、Ribbon负载均衡、Nacos注册中心
SpringCloud基础1——远程调用、Eureka,Nacos注册中心、Ribbon负载均衡
|
4月前
|
负载均衡 算法 Java
SpringCloud之Ribbon使用
通过 Ribbon,可以非常便捷的在微服务架构中实现请求负载均衡,提升系统的高可用性和伸缩性。在实际使用中,需要根据实际场景选择合适的负载均衡策略,并对其进行适当配置,以达到更佳的负载均衡效果。
83 13
|
6月前
|
负载均衡 算法 Java
Spring Cloud Netflix 之 Ribbon
Spring Cloud Netflix Ribbon是客户端负载均衡器,用于在微服务架构中分发请求。它与RestTemplate结合,自动在服务发现(如Eureka)注册的服务之间进行调用。配置包括在pom.xml中添加依赖,设置application.yml以连接Eureka服务器,并在配置类中创建@LoadBalanced的RestTemplate。通过这种方式,当调用如`/user/userInfoList`的接口时,Ribbon会自动处理到多个可用服务实例的负载均衡。
|
6月前
|
缓存 负载均衡 Java
Java一分钟之-Spring Cloud Netflix Ribbon:客户端负载均衡
【6月更文挑战第9天】Spring Cloud Netflix Ribbon是客户端负载均衡器,用于服务间的智能路由。本文介绍了Ribbon的基本概念、快速入门步骤,包括添加依赖、配置服务调用和使用RestTemplate。此外,还讨论了常见问题,如服务实例选择不均、超时和重试设置不当、服务列表更新不及时,并提供了相应的解决策略。最后,展示了如何自定义负载均衡策略。理解并正确使用Ribbon能提升微服务架构的稳定性和效率。
215 3
|
7月前
|
负载均衡 算法
SpringCloud&Ribbon负载均衡原理与实践
SpringCloud&Ribbon负载均衡原理与实践
78 3
|
7月前
|
负载均衡
【SpringCloud】Ribbon负载均衡原理、负载均衡策略、饥饿加载
【SpringCloud】Ribbon负载均衡原理、负载均衡策略、饥饿加载
81 0
|
7月前
|
负载均衡 算法 Java
第五章 Spring Cloud Netflix 之 Ribbon
第五章 Spring Cloud Netflix 之 Ribbon
55 0
|
7月前
|
负载均衡 算法 Java
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(四)Ribbon的使用
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(四)Ribbon的使用
148 0