SpringCloud Ribbon的介绍及使用

Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现。通过Spring Cloud的封装,可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡的服务调用

Ribbon本地负载均衡和Nginx负载均衡的区别

  • Nginx是服务器负载均衡,客户端所有请求都会交给nginx,然后由nginx实现转发请求。即负载均衡是由服务器实现的。
  • Ribbon本地负载均衡,在调用微服务接口时候,会在注册中心上获取注册信息服务列表之后缓存到本地,从而在本地实现RPC远程服务调用技术。由客户端进行负载,根据负载均衡策略发送请求。

Ribbon引入

Eureka Client自动带着Ribbon的依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

自己手动添加依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
    <!--<version>2.1.1.RELEASE</version>-->
</dependency>

注册RestTemplate的bean上添加@LoadBalanced注解开启负载均衡

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

Ribbon负载均衡规则

  • 轮询(RoundRobinRule):com.netflix.loadbalancer.RoundRobinRule
  • 随机(RoundRobinRule):com.netflix.loadbalancer.RoundRobinRule
  • RetryRule:默认使用了RoudRobinRule实例,如果服务获取失败则在指定时间内进行重试,获取可用的服务
  • WeightedResponseTimeRule:对RoundRobinRule的扩展,响应速度越快的实例选择权重越大,越容易被选择
  • BestAvailableRule:会先过滤掉由于多次访问故障而处于断路跳闸状态的服务,然后选择一个并发最小的服务
  • AvailabilityFilteringRule:先过滤掉故障实例,再选择并发较小的实例
  • ZoneAvoidanceRule:判断server所在区域的性能和server的可用性选择服务

Ribbon负载均衡规则替换

自定义值类不能放在@ComponentScan所扫描的当前包下以及子包下。否则自定义的这个配置类会被所有的Ribbon客户端所共享,达不到特殊化定制的目的。

  1. 自定义配置类,配置类所在的包不要在**@ComponentScan所扫描的当前包下以及子包下**

    @Configuration
    public class MyRibbonRule {
          
          
    
        @Bean
        public IRule selfRule(){
          
          
            return new RandomRule();
        }
    }
    
  2. 启动类型添加@RibbonClient注解,配置调哪个服务使用什么负载均衡规则

    @SpringBootApplication
    @EnableEurekaClient
    @RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MyRibbonRule.class)
    //@RibbonClients
    public class OrderApplication {
          
          
    
        public static void main(String[] args) {
          
          
            SpringApplication.run(OrderApplication.class,args);
        }
    }
    

负载均衡算法(轮询):调用接口的次数(t) % 服务器集群的总数量c = 实际调用服务器位置下标(i)。(取模) t % c= i。服务重启 t = 0

手写轮询算法

  1. 创建接口,定义传入全部服务信息方法

    public interface LoadBalancer {
          
          
    
        /**
         * 传入全部服务实例
         * @param instanceList
         * @return
         */
        ServiceInstance instances(List<ServiceInstance> instanceList);
    }
    
  2. 创建算法实现类,集成定义的LoadBalancer接口

    @Component //注册成spring的bean
    public class MyRoundRobinRule implements LoadBalancer{
          
          
    
        /**
         * 线程安全的变量
         */
        private AtomicInteger atomicInteger = new AtomicInteger(0);
    
        private int getAndIncrement(){
          
          
            int current,next;
            do {
          
          
                current = this.atomicInteger.get();
                //防止int月结,把下个值赋给next,去做比较交换cas
                next = current >= Integer.MAX_VALUE ? 0 : current + 1;
                //cas比较交换,不成功继续循环
            }while (!this.atomicInteger.compareAndSet(current,next));
            return next;
        }
    
        /**
         * @param instanceList 服务信息
         * @return
         */
        @Override
        public ServiceInstance instances(List<ServiceInstance> instanceList) {
          
          
            int times = 0;
            //没有服务信息重试,还没有报错
            while (instanceList == null || instanceList.size() == 0){
          
          
                System.out.println("没有服务信息,三秒后重试======");
                times ++;
                try {
          
          
                    Thread.sleep(3 * 1000);
                } catch (InterruptedException e) {
          
          
                    e.printStackTrace();
                }
                if(times > 2){
          
          
                    throw new RuntimeException("No service information");
                }
            }
            //取模,算出请求的服务的下标
            int index = getAndIncrement() % instanceList.size();
            return instanceList.get(index);
        }
    }
    
  3. 调用服务测试

    @Resource
    private LoadBalancer loadBalancer;
    
    /**
     * 获取注册中心服务信息,需要springboot启动类添加@EnableDiscoveryClient注解
     */
    @Resource
    private DiscoveryClient discoveryClient;
    
    @GetMapping(value = "payment")
    public String getPayment(){
          
          
        List<ServiceInstance> instanceList = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
        ServiceInstance serviceInstance = loadBalancer.instances(instanceList);
        //获取轮序算法返回的服务的uri
        URI uri = serviceInstance.getUri();
        //restTemplate(去掉@LoadBalanced注解)发送请求
        return restTemplate.getForObject(uri + "/payment",String.class);
    }
    

猜你喜欢

转载自blog.csdn.net/zhaoqingquanajax/article/details/114554663