SpringCloud微服务(四)之ribbon笔记

ribbon是什么?

  • Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现
  • Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,Ribbon是一个客户端负载均衡器,我们可以在配置文件中Load Balancer后面的所有机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器,我们也很容易使用Ribbon实现自定义的负载均衡算法
  • 常见的负载均衡软件有Nginx、Lvs 等等。
  • 负载均衡简单说就是将用户的请求平摊的分配到多个服务器上,从而达到系统的HA(高可用)
    在这里插入图片描述

入门案例

  1. 客户端引入依赖
 <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-ribbon</artifactId>
  </dependency>
  1. 客户端yml配置文件
server:
 port: 80


#Eureka配置
eureka:
 client:
   register-with-eureka: false # 不向Eureka注册自己
   service-url:
     defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
  1. 客户端config配置类
package com.kuang.springcloud.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 { //@Configuration -- spring  applicationContext.xml

   //配置负载均衡实现RestTemplate
   // IRule
   // RoundRobinRule 轮询
   // RandomRule 随机
   // AvailabilityFilteringRule : 会先过滤掉,跳闸,访问故障的服务~,对剩下的进行轮询~
   // RetryRule : 会先按照轮询获取服务~,如果服务获取失败,则会在指定的时间内进行,重试
   @Bean
   @LoadBalanced //Ribbon
   public RestTemplate getRestTemplate(){
       return new RestTemplate();
   }

}
  1. 客户端Controller层
package com.kuang.springcloud.controller;

import com.kuang.springcloud.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
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;

@RestController
public class DeptConsumerController {

   // 理解:消费者,不应该有service层~
   // RestTemplate .... 供我们直接调用就可以了! 注册到Spring中
   // (url, 实体:Map ,Class<T> responseType)
   @Autowired
   private RestTemplate restTemplate; //提供多种便捷访问远程http服务的方法,简单的Restful服务模板~

   //Ribbon。我们这里的地址,应该是一个变量,通过服务名来访问
   //private static final String REST_URL_PREFIX = "http://localhost:8001";
   private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";

   @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 get(@PathVariable("id") Long id){
       return restTemplate.getForObject(REST_URL_PREFIX+"/dept/get/"+id,Dept.class);
   }


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

}

  1. 客户端入口
package com.kuang.springcloud;

import com.kuang.myrule.KuangRule;
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
//在微服务启动的时候就能去加载我们自定义Ribbon类,SPRINGCLOUD-PROVIDER-DEPT是微服务的名字
//@RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT",configuration = KuangRule.class)
public class DeptConsumer_80 {
   public static void main(String[] args) {
       SpringApplication.run(DeptConsumer_80.class,args);
   }
}

自定义均衡负载算法

  1. 编写myrule组件,注意不可以放在主应用程序的上下文,会被componentscan扫描到。
package com.kuang.myrule;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RoundRobinRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class KuangRule {

   @Bean
   public IRule myRule(){
       return new KuangRandomRule(); //默认是轮询,现在我们定义为~ KuangRandomRule
   }

}


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

   //每个服务,访问5次~,换下一个服务(3个)

   // total=0, 默认=0,如果=5,我们指向下一个服务节点
   // index=0,默认0,如果total=5,index+1,

   private int total = 0; //被调用的次数
   private int currentIndex = 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()) {
               return null;
           }

           List<Server> upList = lb.getReachableServers(); //获得活着的服务
           List<Server> allList = lb.getAllServers(); //获得全部的服务

           int serverCount = allList.size();
           if (serverCount == 0) {
               return null;
           }

//            int index = chooseRandomInt(serverCount); //生成区间随机数
//            server = upList.get(index); //从活着的服务中,随机获取一个~


           //-=========================================================

           if (total<5){
               server = upList.get(currentIndex);
               total++;
           }else {
               total = 0;
               currentIndex++;
               if (currentIndex>upList.size()){
                   currentIndex = 0;
               }
               server = upList.get(currentIndex); //从活着的服务中,获取指定的服务来进行操作
           }



           //-=========================================================

           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);
   }

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

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

  1. 自定义主文件入口
package com.kuang.springcloud;

import com.kuang.myrule.KuangRule;
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
//在微服务启动的时候就能去加载我们自定义Ribbon类
@RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT",configuration = KuangRule.class)
public class DeptConsumer_80 {
   public static void main(String[] args) {
       SpringApplication.run(DeptConsumer_80.class,args);
   }
}

  1. 文件目录:在这里插入图片描述(myrule、springcloud、与主程序同级)
    [1]: 代码来源:狂神说Java
原创文章 4 获赞 1 访问量 134

猜你喜欢

转载自blog.csdn.net/qq_41864303/article/details/106170446