Spring Cloud 微服务之Ribbon(五)

22 篇文章 1 订阅
18 篇文章 0 订阅

一、什么是Spring Cloud Ribbon?

  • Spring Cloud Ribbon 是Spring Cloud Netflix 子项目的核心组件之一,主要给服务间调用及API网关转发提供负载均衡的功能。
  • 在微服务架构中,很多服务都会部署多个,其他服务去调用该服务的时候,如何保证负载均衡是个不得不去考虑的问题。负载均衡可以增加系统的可用性和扩展性,当我们使用RestTemplate来调用其他服务时,Ribbon可以很方便的实现负载均衡功能。
  • Ribbon 的客户端组件提供一系列完整的配置项如:连接超时、重试等等。简单的说,就是在配置文件中列出LoadBalancer后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等等)去连接这些机器,我们也很容易使用Ribbon实现自定义的负载均衡算。
  • 负载均衡简单分类:
    • 集中式LB:即在服务的消费方和提供方之间使用独立的LB设施,如反向代理服务器,由该设施负责把访问请求通过某种策略转发至服务的提供方。
    • 进程式LB:将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选出一个合适的服务器。
  • Ribbon就属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址。

二、案例演示

  • 添加依赖

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        <version>2.2.0.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        <version>2.2.0.RELEASE</version>
    </dependency>
    
  • 添加配置

    启动类

    @SpringBootApplication
    @EnableEurekaClient
    public class RibbonClientApplication {
        public static void main(String[] args) {
            SpringApplication.run(RibbonClientApplication.class, args);
        }
    }
    

    自定义配置类

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

    application.yml文件

    server:
      port: 8080
      servlet:
        context-path: /
    
    spring:
      application:
        name: ribbon-client
    
    eureka:
      client:
        register-with-eureka: false
        fetch-registry: true
        service-url:
          defaultZone: http://localhost:8010/eureka
    
    # 服务访问地址
    user-service-url: http://ribbon-service/
    
  • 测试使用

    • 编写控制器类

      @RestController
      public class UserController {
      
          @Autowired
          private RestTemplate restTemplate;
      
          @Value("${user-service-url}")
          private static String SERVICE_URL;
      
          @GetMapping("/get/{id}")
          public Map<String, Object> getUser(@PathVariable Long id){
              Map result = restTemplate.getForObject(SERVICE_URL + "get/" + id, 
                                                     Map.class);
      
              return result;
          }
      
          @GetMapping("/add")
          public Map<String, Object> addUser(User user){
              Map result = restTemplate.postForObject(SERVICE_URL + "add", user, 
                                                      Map.class);
      
              return result;
          }
      }
      
    • 访问

      访问:http://localhost:8010/
      

      在这里插入图片描述

      访问:http://localhost:8080/get/1
      

      发现Ribbon默认采用轮询算法依次在每一个服务方进行访问

三、负载均衡策略

  • 已定义的策略

    Ribbon默认使用的是轮询算法

    • com.netflix.loadbalancer.RandomRule

      从提供服务的实例中以随机的方式;

    • com.netflix.loadbalancer.RoundRobinRule

      以线性轮询的方式,就是维护一个计数器,从提供服务的实例中按顺序选取,第一次选第一个,第二次选第二个,以此类推,到最后一个以后再从头来过;

    • com.netflix.loadbalancer.RetryRule

      在RoundRobinRule的基础上添加重试机制,即在指定的重试时间内,反复使用线性轮询策略来选择可用实例;

    • com.netflix.loadbalancer.WeightedResponseTimeRule

      对RoundRobinRule的扩展,响应速度越快的实例选择权重越大,越容易被选择;

    • com.netflix.loadbalancer.BestAvailableRule

      选择并发较小的实例;

    • com.netflix.loadbalancer.AvailabilityFilteringRule

      先过滤掉故障实例,再选择并发较小的实例;

    • com.netflix.loadbalancer.ZoneAwareLoadBalancer

      采用双重过滤,同时过滤不是同一区域的实例和故障实例,选择并发较小的实例。

  • 自定义均衡策略

    • 启动类添加注解

      @SpringBootApplication
      @EnableEurekaClient
      @RibbonClient(name = "ribbon-service", configuration = RuleConfig.class)
      public class RibbonClientApplication {
          public static void main(String[] args) {
              SpringApplication.run(RibbonClientApplication.class, args);
          }
      }
      
    • 自定义配置类

      public class MyRule extends AbstractLoadBalancerRule {
      
          public MyRule() {
          }
      
          private int total = 1;
          private int current = 0;
      
          @SuppressWarnings({"RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE"})
          public Server choose(ILoadBalancer lb, Object key) {
              if (lb == null) {
                  return null;
              } else {
                  Server server = null;
      
                  while(server == null) {
                      if (Thread.interrupted()) {
                          return null;
                      }
      
                      List<Server> upList = lb.getReachableServers();
                      List<Server> allList = lb.getAllServers();
                      int serverCount = allList.size();
                      if (serverCount == 0) {
                          return null;
                      }
                      
                      //-******************************
                      if(total <= 3){
                          server = upList.get(current);
                          total++;
                      }else{
                          total = 1;
                          current += 1;
                          if(current > upList.size()-1){
                              current = 0;
                          }
                          server = upList.get(current);
                      }
                      //-******************************
      
                      if (server == null) {
                          Thread.yield();
                      } else {
                          if (server.isAlive()) {
                              return server;
                          }
      
                          server = null;
                          Thread.yield();
                      }
                  }
      
                  return server;
              }
          }
      
          protected int chooseRandomInt(int serverCount) {
              return ThreadLocalRandom.current().nextInt(serverCount);
          }
      
          public Server choose(Object key) {
              return this.choose(this.getLoadBalancer(), key);
          }
      
          public void initWithNiwsConfig(IClientConfig clientConfig) {
          }
      }
      
      @Configuration
      public class RuleConfig {
      
          @Bean
          public IRule myRule(){
              return new MyRule();
          }
      }
      

五、常用配置

  • 全局配置

    ribbon:
      ConnectTimeout: 1000 #服务请求连接超时时间(毫秒)
      ReadTimeout: 3000 #服务请求处理超时时间(毫秒)
      OkToRetryOnAllOperations: true #对超时请求启用重试机制
      MaxAutoRetriesNextServer: 1 #切换重试实例的最大个数
      MaxAutoRetries: 1 # 切换实例后重试最大次数
      NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #修改负载均衡算法
    
  • 局部配置

    user-service:
      ribbon:
        ConnectTimeout: 1000 #服务请求连接超时时间(毫秒)
        ReadTimeout: 3000 #服务请求处理超时时间(毫秒)
        OkToRetryOnAllOperations: true #对超时请求启用重试机制
        MaxAutoRetriesNextServer: 1 #切换重试实例的最大个数
        MaxAutoRetries: 1 # 切换实例后重试最大次数
        NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #修改负载均衡算法
    

【源码地址】:GitHub

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程小吉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值