目录
  • 一、Ribbon简介
    • 1、什么是Ribbon
    • 2、Ribbon能干什么
  • 二、使用Ribbon
    • 1、客户端导入依赖
    • 2、application.yml配置
    • 3、Controller配置
    • 4、Config的配置
    • 5、启动类的配置
  • 三、Ribbon实现负载均衡
    • 四、设计负载均衡算法
      • 1、80启动类的改动
      • 2、自定义路由类
      • 3、负载均衡算法的实现

    一、Ribbon简介

    1、什么是Ribbon

    Spring Cloud Ribbon 是基于Netflix Ribbon 实现的一套客户端负载均衡的工具,它可以很好地控制HTTP和TCP客户端的行为。

    简单的说,Ribbon 是 Netflix 发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将 Netflix 的中间层服务连接在一起。Ribbon 的客户端组件提供一系列完整的配置项,如:连接超时、重试等。简单的说,就是在配置文件中列出 LoadBalancer (简称LB:负载均衡) 后面所有的及其,Ribbon 会自动的帮助你基于某种规则 (如简单轮询,随机连接等等) 去连接这些机器。我们也容易使用 Ribbon 实现自定义的负载均衡算法!

    2、Ribbon能干什么

    SpringCloud Netflix Ribbon超详细讲解

    • LB,即负载均衡 (LoadBalancer) ,在微服务或分布式集群中经常用的一种应用。
    • 负载均衡简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA (高用)。
    • 常见的负载均衡软件有 Nginx、Lvs(中国人研发的) 等等。

    其中lvs是中国技术专家章文嵩发明的

    • Dubbo、SpringCloud 中均给我们提供了负载均衡,SpringCloud 的负载均衡算法可以自定义。

    负载均衡简单分类:

    • 集中式LB

    即在服务的提供方和消费方之间使用独立的LB设施,如Nginx(反向代理服务器),由该设施负责把访问请求通过某种策略转发至服务的提供方!

    • 进程式 LB

    将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选出一个合适的服务器。 Ribbon就属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址!

    二、使用Ribbon

    1、客户端导入依赖

         <!--引入Eureka的依赖-->
         <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-eureka</artifactId>
                <version>1.4.6.RELEASE</version>
            </dependency>
            <!--引入ribbon-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-ribbon</artifactId>
                <version>1.4.6.RELEASE</version>
            </dependency>
        </dependencies>
    

    2、application.yml配置

    server:
      port: 801

    eureka:
      client:
        register-with-eureka: false  #不向eureka注册自己
        service-url:
          defaultZone: http://localhost:7001/eureka/ #去哪个地方获取

    3、Controller配置

    和前面两节不一样的是,用Ribbon做负载均衡,地址不能写死,也就是不能和前面的一样写成一个具体的值如:localhost:8001,而是这个微服务的名字,也就是这个名字,如下。

    SpringCloud Netflix Ribbon超详细讲解

    package com.you.controller;
    import com.you.pojo.Dept;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.*;
    import org.springframework.web.client.RestTemplate;
    import java.util.List;
    @RestController
    @ResponseBody
    public class DeptComsumerController {
        @Autowired
        RestTemplate restTemplate;
    //    public static final String REST_URL_PREFIX = "http://localhost:8001";
        public static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";
        @GetMapping("/consumer/dept/getDept/{id}")
        public Dept getDeptOfId(@PathVariable("id") Long id)
        {
            System.out.println(REST_URL_PREFIX+"/dept"+"/aDept/"+id);
            return restTemplate.getForObject(REST_URL_PREFIX + "/dept" + "/aDept/"+id, Dept.class);
        }
    }

    4、Config的配置

    在此文件里,增加了@LoadBalanced注解,该注解的作用是让RestTemplate有了负载均衡的能力,而且默认的负载均衡算法是轮询(也就是一个一个的尝试),可以使用系统配备的负载均衡算法,也可以自己写自己的负载均衡算法。

    package com.you.config;
    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 ConfigBean {
        @Bean
        @LoadBalanced  //ribbon
        /*配置负载均衡实现RestTemplate*/
        /*IRule*/
        /*RoundRobinRule 轮询 */
        /*RandomRule 随机*/
        /*AvailabilityFilteringRule 优先过滤掉跳闸、访问故障的服务,对剩下的进行轮询 */
        public RestTemplate getRestTemplate() {
            return new RestTemplate();
        }
    }

    5、启动类的配置

    package com.you;
    import com.tan.tanRule;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    import org.springframework.cloud.netflix.ribbon.RibbonClient;
    @SpringBootApplication
    @EnableEurekaClient
    /*下面是处理负载均衡算法*/
    @RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT",configuration = tanRule.class)
    public class DeptConsumer_80 {
        public static void main(String[] args) {
            SpringApplication.run(DeptConsumer_80.class,args);
        }
    }

    三、Ribbon实现负载均衡

    SpringCloud Netflix Ribbon超详细讲解

    为了实现负载均衡,扩充一下服务提供者,将原来的一个服务提供者,改为三个。

    • 新建三个module,springboot-provider-8002、springboot-provider-8003。
    • 参考springboot-provider-8001,修改application.xml(主要是端口号,数据库名,instance-id),其中application-name要保持一致。和微服务的名字一样。

    SpringCloud Netflix Ribbon超详细讲解

    • 启动Eureka_7001,启动这个三个提供者,根据自己的情况,如果电脑性能比较差,可以少启动一个。启动consumer_80。

    访问consumer_80配置的Getmapping地址,然后不断的刷新,会看到依次访问三个数据库,并且一直重复,这就是默认的负载均衡算法:轮询

    四、设计负载均衡算法

    1、80启动类的改动

    @RibbonClient()注释的应用,在psvm上面添加该注释,其具体内容为@RibbonClient(name = “SPRINGCLOUD-PROVIDER-DEPT”,configuration = tanRule.class),其中name的值即为微服务的名字,configuration的值对应的就是自己写的路由类

    SpringCloud Netflix Ribbon超详细讲解

    2、自定义路由类

    需要注意,自定义的路由类,不可以用启动类放在同一目录,一般要比启动类高一级目录,放在同一目录下,需要配置CompentScan。

    SpringCloud Netflix Ribbon超详细讲解

    package com.tan;
    import com.netflix.loadbalancer.IRule;
    import com.netflix.loadbalancer.RandomRule;
    import org.springframework.context.annotation.Bean;
    public class tanRule {
        @Bean
        public IRule myRule()
        {
            return new tanRandomRule();
        }
    }

    3、负载均衡算法的实现

    可以模仿系统中的负载均衡算法,撰写自己的负载均衡算法,如下面的例子即为:每个端口的提供者访问5次,然后切换下一个端口,全部访问完成后则重新开始,代码如下:

    package com.tan;
    import com.netflix.client.config.IClientConfig;
    import com.netflix.loadbalancer.AbstractLoadBalancerRule;
    import com.netflix.loadbalancer.ILoadBalancer;
    import com.netflix.loadbalancer.Server;
    import java.util.List;
    import java.util.concurrent.ThreadLocalRandom;
    public class tanRandomRule extends AbstractLoadBalancerRule {
       int total = 0;
       int currentIndex = 0;
       public tanRandomRule() {
       }
       @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();
                   if(total<5)
                   {
                       server = (Server)upList.get(currentIndex);
                       total++;
                   }else{
                       total = 0;
                       currentIndex++;
                       if(currentIndex>2)
                       {
                           currentIndex = 0;
                       }
                       server = (Server)upList.get(currentIndex);
                   }
                   System.out.println("CurrentIndex:"+currentIndex);
                   System.out.println("Total:"+total);
                   System.out.println("sever 的值是:"+server);
                   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) {
       }
    }
    声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。