Ribbon负载均衡介绍及配置学习

  • 一、Ribbon 简介
  • 二、配置Ribbon
  • 三、注册结果
  • 四、自定义负载均衡的算法
  • 4.1 查看接口IRule的接口,哪些算法
  • 4.2 改变Ribbon的算法配置
  • 五、代码贴出
  • 5.1 pom.xml
  • 5.2 application.yml文件
  • 5.3 config下的ConfigBean
  • 5.4 DeptConsumerController.java
  • 5.5 myrule下的lhhRule
  • 5.6 myrule下的LhhRandomRule的自定义算法
  • 5.7 启动类DeptConsumerDept_80.java


一、Ribbon 简介

  • 简介:Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具
  • 负载均衡算法:轮询 【默认】,随机,常见的负载均衡软件:Nginx ,lvs{linux虚拟机}
  • 集中式:Ngnix 进程式:Ribbon,和服务注册(Eureka)挂钩

二、配置Ribbon

1.Ribbon 是客服端的负载均衡,所以配置实在客服端,即前面配置的80端口
pom.xml

<!--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.6.RELEASE</version>
        </dependency>

        <!--    eureka-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>

application.yml

eureka:
  client:
    register-with-eureka: false #不注册自己
    service-url:
      defaultZone: http://eureka.7001.com:7001/eureka/,http://eureka.7002.com:7002/eureka/,http://eureka.7003.com:7003/eureka/

2.之前用的RestTemplate调用服务端的接口,添加@LoadBalanced //ribbon

@Configuration
public class ConfigBean { //@Configuration 与spring applicationContext.xml
    //配置负载均衡实现restTemplate
    @Bean
    @LoadBalanced  //ribbon
    public RestTemplate getrestTemplate(){
        return new RestTemplate();
    }

}

3.用了负载均衡,之前固定的链接前缀可以用,服务名替换了

//提供restful服务
@RestController
public class DeptConsumerController {
    //理解:消费者不应该有service层
//    private static final String REST_URL_PREFIX="http://localhost:8001";

    private static final String REST_URL_PREFIX="http://SPRINGCLOUD-PROVIDER-DEPT";

4.在启动类添加Eureka的配置,@EnableEurekaClient

//Ribbon 和 Eureka 整合以后,客户端可以直接调用,不用关心IP地址和端口号
@SpringBootApplication
@EnableEurekaClient
public class DeptConsumerDept_80 {
    public static void main(String[] args){
        SpringApplication.run(DeptConsumerDept_80.class,args);
    }
}

5.查看自己调用的不同服务,流程

关闭 ribbon负载均衡 ribbon负载均衡配置_eureka

6.先创建8002 8003 服务端,复制8001的pom.xml文件,其他文件都复制

yml文件更改

关闭 ribbon负载均衡 ribbon负载均衡配置_eureka_02


启动类

关闭 ribbon负载均衡 ribbon负载均衡配置_java_03

三、注册结果

  • http://localhost:7001
  • 再运行,依次db01 db02 db03
  • ribbon默认是轮询方式

四、自定义负载均衡的算法

4.1 查看接口IRule的接口,哪些算法

关闭 ribbon负载均衡 ribbon负载均衡配置_ribbon_04

关闭 ribbon负载均衡 ribbon负载均衡配置_java_05

4.2 改变Ribbon的算法配置

  1. 先配置文件,创建配置类文件,不能和启动类放在一起,不能放置的原因-官方描述
  2. 创建配置类
  3. 这是配置类,可以配置,之前是把默认得轮询改成随机,现在是自定义
  4. 自定义负载均衡得方式
  • 5.启动类添加@RibbonClient的注解,指定服务与 算法配置类
    @RibbonClient(value = “SPRINGCLOUD-PROVIDER-DEPT”,configuration = LhhRandomRule.class)

    运行结果:按照设置,每次服务执行5次,切换下一个服务

五、代码贴出

5.1 pom.xml

<!--    依赖实体类+web-->
    <dependencies>
        <dependency>
            <groupId>com.lhh</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <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>

        <!--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.6.RELEASE</version>
        </dependency>

        <!--    eureka-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
    </dependencies>

5.2 application.yml文件

server:
  port: 80

eureka:
  client:
    register-with-eureka: false #不注册自己
    service-url:
      defaultZone: http://eureka.7001.com:7001/eureka/,http://eureka.7002.com:7002/eureka/,http://eureka.7003.com:7003/eureka/

5.3 config下的ConfigBean

@Configuration
public class ConfigBean { //@Configuration 与spring applicationContext.xml
    //配置负载均衡实现restTemplate
    @Bean
    @LoadBalanced  //ribbon
    public RestTemplate getrestTemplate(){
        return new RestTemplate();
    }

}

5.4 DeptConsumerController.java

package com.lhh.controller;

import com.lhh.cloud.entity.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;

//提供restful服务
@RestController
public class DeptConsumerController {
    //理解:消费者不应该有service层
//    private static final String REST_URL_PREFIX="http://localhost:8001";

    private static final String REST_URL_PREFIX="http://SPRINGCLOUD-PROVIDER-DEPT";

    @Autowired
    private RestTemplate restTemplate; //提供多种边界访问远程http服务的方法,简单的restful服务

    @RequestMapping("/consumer/dept/add")
    public boolean add(Dept dept){
        return restTemplate.postForObject(REST_URL_PREFIX+"/dept/add",dept,Boolean.class);
    }

    @RequestMapping("/consumer/dept/get/{id}")
    public Dept getById(@PathVariable(value = "id") Integer id){
        return restTemplate.getForObject(REST_URL_PREFIX+"/dept/get/"+id,Dept.class);
    }

    @RequestMapping("/consumer/dept/list")
    public List<Dept> queryDept(){
        return restTemplate.getForObject(REST_URL_PREFIX+"/dept/list", List.class);
    }
}

5.5 myrule下的lhhRule

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 lhhRule {

    //Ribbon 自带是随机  然后现在改为随机
    @Bean
    public IRule myRule(){
        return new LhhRandomRule();   // return new RandomRule();

    }
}

5.6 myrule下的LhhRandomRule的自定义算法

package com.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 LhhRandomRule extends AbstractLoadBalancerRule {

//    想要效果 :每个服务执行五次,切换下一个服务

    private int totals=0;//执行次数
    private int current=0;//当前服务

//    @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE")
    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            return null;
        }
        Server server = null;

        while (server == null) {
            if (Thread.interrupted()) { //Thread.interrupted() 主线程 false没有终端 true 中断
                return null;
            }
            List<Server> upList = lb.getReachableServers(); //获得活着得服务
            List<Server> allList = lb.getAllServers(); //获得所有服务

            int serverCount = allList.size();
            if (serverCount == 0) {
                return null;
            }
            // ==============改后 start======================
            if(totals<5){
                server=upList.get(current);
                totals++;
            }else{
                totals=0;
                current++;
                if(current<upList.size()){
                    current=0;
                }
                server=upList.get(current);
            }
            // ==============改后 end======================

            /* -------------------------------------------之前随机源码 start
            int index = chooseRandomInt(serverCount);
            server = upList.get(index);
            ------------------------------------------之前随机源码 end -*/

            if (server == null) {
                Thread.yield();
                continue;
            }

            if (server.isAlive()) {
                return (server);
            }
            server = null;
            Thread.yield();
        }

        return server;

    }

    protected int chooseRandomInt(int serverCount) {
        return ThreadLocalRandom.current().nextInt(serverCount); //线程安全随机数获取 current()获取当前实例 nextInt()获得整型随机数
    }

    @Override
    public Server choose(Object key) {
        return choose(getLoadBalancer(), key);
    }

    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
        // TODO Auto-generated method stub

    }
}

5.7 启动类DeptConsumerDept_80.java

import com.myrule.LhhRandomRule;
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;

//Ribbon 和 Eureka 整合以后,客户端可以直接调用,不用关心IP地址和端口号
@SpringBootApplication
@EnableEurekaClient
@RibbonClient(value = "SPRINGCLOUD-PROVIDER-DEPT",configuration = LhhRandomRule.class)
public class DeptConsumerDept_80 {
    public static void main(String[] args){
        SpringApplication.run(DeptConsumerDept_80.class,args);
    }
}