Ribbon:负载均衡

1 Ribbon是什么?

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

2 Ribbon能干什么?

  • LB,即负载均衡(Load Balance),在微服务或分布式集群中经常用的一种应用。
  • 负载均衡简单地说就是将用户的请求平摊到多个服务上,从而导到系统的HA(高可用)。
  • 常见的负载均衡软件有Nginx、Lvs等。
  • Dubbo、SpringCloud中均给我们提供了负载均衡,SpringCloud的负载均衡算法可以自定义。

3 负载均衡的简单分类

1、集中式

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

2、进程式

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

4 起步

1、springcloud-consumer-dept-80

  • pom.xml(导入Ribbon、Eureka依赖)

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>springcloud</artifactId>
            <groupId>com.xianhuii</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>springcloud-consumer-dept-80</artifactId>
    
        <dependencies>
            <!--Ribbon-->
            <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-ribbon -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-ribbon</artifactId>
                <version>1.4.7.RELEASE</version>
            </dependency>
            <!--Eureka-->
            <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-eureka</artifactId>
                <version>1.4.7.RELEASE</version>
            </dependency>
            <!-- 实体类 -->
            <dependency>
                <groupId>com.xianhuii</groupId>
                <artifactId>springcloud-api</artifactId>
                <version>1.0-SNAPSHOT</version>
            </dependency>
            <!-- Web -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <!-- 热部署 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
            </dependency>
        </dependencies>
    </project>
  • application.yaml

    server:
      port: 80

    Eureka配置

    eureka:
      client:
        register-with-eureka: false  # 不向Eureka注册
        service-url: 
          defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/,http://localhost:7003/eureka/
  • DeptConsumer_80(@EnableEurekaClient)

    package com.xianhuii.springcloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    
    @EnableEurekaClient
    @SpringBootApplication
    public class DeptConsumer_80 {
        public static void main(String[] args) {
            SpringApplication.run(DeptConsumer_80.class, args);
        }
    }
  • ConfigBean(@LoadBalanced)

    package com.xianhuii.springcloud.config;
    
    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;
    
    /**
    
     * 相当于Spring里的applicationContext.xml
       */
       @Configuration
       public class ConfigBean {
       // 配置负载均衡实现RestTemplate
       @LoadBalanced   // Ribbon
       @Bean
       public RestTemplate getRestTemplate() {
           return new RestTemplate();
       }
    
    }
  • DeptConsumerController

    package com.xianhuii.springcloud.controller;
    
    import com.xianhuii.springcloud.pojo.Dept;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;
    
    import java.util.List;
    
    /**
    
     * 消费者:不应该有Service
    
     * RestTemplate:提供多种便捷访问远程http服务的方法,简单的RESTful服务模板
    
     * (url, 参数, responseType)
       */
       @RestController
       public class DeptConsumerController {
       @Autowired
       private RestTemplate restTemplate;
    
       //    private static final String REST_URL_PREFIX = "http://localhost:8001";
       //    Ribbon,通过服务名来访问
       private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";
    
       @RequestMapping("/consumer/dept/get/{id}")
       public Dept get(@PathVariable("id") Long id) {
           return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get/" + id, Dept.class);
       }
    
       @RequestMapping("/consumer/dept/add")
       public boolean add(Dept dept) {
           return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", dept, Boolean.class);
       }
    
       @RequestMapping("/consumer/dept/list")
       public List<Dept> list() {
           return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list", List.class);
       }
       }

5 自定义负载均衡算法

  • MyRandomRule

    package com.xianhuii.myrule;
    
    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 MyRandomRule extends AbstractLoadBalancerRule {
        public MyRandomRule() {
        }
    
        @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;
                    }
    
                    int index = this.chooseRandomInt(serverCount);  // 生成随机数
                    server = (Server)upList.get(index); // 从存活的服务中随机获取
                    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) {
        }
    
    }
  • MyRule

    package com.xianhuii.myrule;
    
    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 MyRule {
        @Bean
        public IRule myRule() {
            return new MyRandomRule();
        }
    }
  • DeptConsumer_80(@RibbonClient)

    package com.xianhuii.springcloud;
    
    import com.xianhuii.myrule.MyRule;
    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;
    
    @EnableEurekaClient
    @SpringBootApplication
    // 在微服务启动的时候,加载自定义的Ribbon类
    @RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT", configuration = MyRule.class)
    public class DeptConsumer_80 {
        public static void main(String[] args) {
            SpringApplication.run(DeptConsumer_80.class, args);
        }
    }
全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务