Spring Cloud Ribbon学习笔记

Spring Cloud Ribbon

SpringCloudRibbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具,主要提供客户端的软件负载均衡算法和服务调用。Ribbon客户端提供一系列完善的配置项如连接超时,重试等。

In simple termsRibbon就是再配置文件中列出Load Balancer后面所有的机器,自动帮你基于某种规则(如简单轮询,随坤连接)去连接这些机器。

LB负载均衡是什么

简单来说就是将用户的请求平摊到多个服务上,从而达到系统的HA(高可用)。常用的负载均衡有软件Nginx,LVS,硬件F5等。

Ribbon本地负载均衡客户端 VS Nginx服务端负载均衡的区别

Nginx是服务器负载均衡,客户端所有请求都会交给Nginx,然后由Nginx实现转发请求,及负载均衡是由服务器实现的。

Ribbon本地负载均衡,在调用服务接口时候,会在注册中心获取信息服务列表之后缓存到JVM本地,从而在本地实现RPC远程服务调用技术。

集中式LB:即在服务的消费方和提供方之间使用独立的LB设施(硬件:F5;软件:Nginx),由该设施负责把访问请求通过某种策略转发至服务的提供方

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

Ribbon架构


Ribbon在工作时分成两步

第一步选择EurekaServer,它优先选择在同一个区域内负载较少的server

第二步再根据用户指定的策略,在从server取到的服务注册列表中选择一个地址,其中Ribbon提供了许多种策略,如轮询,随机和根据响应时间加权

RestTemplate

在这里插入图片描述
在这里插入图片描述

Ribbon接口在这里插入图片描述

IRule:根据特定算法从服务列表中选取一个要访问的服务

Ribbon配置

在这里插入图片描述

所以在main/java目录下新建一个package myrule

package com.swh.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 MySelfRule {

    @Bean
    public IRule myRule() {
        // 定义为随机
        return new RoundRobinRule();
    }
}

主启动类添加@RibbonClient

package com.swh.springcloud;swh

import com.atguigu.myrule.MySelfRule;
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 = "CLOUD-PAYMENT-SERVICE", configuration = MySelfRule.class)
public class OrderMain80 {
    public static void main(String[] args) {
        SpringApplication.run(OrderMain80.class, args);
    }
}

Ribbon负载均衡算法

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

负载均衡算法:rest接口第几次请求%服务器集群总数量=实际调用服务器位置下标,每次服务启动后rest接口计数从1开始。

List<ServiceInstance> instance = discoveryClient.getinstances("CLOUD-PAYMENT-SERVICE");

如:

  List[0] instance=127.0.0.1:8001
  List[1] instance=127.0.0.1:8002
当请求数为1时,1%2=1,对应下标位置为1,则获得服务地址为127.0.0.18001
当请求数为2时,2%2=2,对应下标位置为0,则获得服务地址为127.0.0.18002
当请求数为3时,3%2=1,对应下标位置为1,则获得服务地址为127.0.0.18001
当请求数为4时,4%2=1,对应下标位置为0,则获得服务地址为127.0.0.18002
。。。。。。

源码:

   private AtomicInteger nextServerCyclicCounter;
   public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            log.warn("no load balancer");
            return null;
        } else {
            Server server = null;
            int count = 0;

            while(true) {
                if (server == null && count++ < 10) {
                    List<Server> reachableServers = lb.getReachableServers();
                    List<Server> allServers = lb.getAllServers();
                    int upCount = reachableServers.size();
                    int serverCount = allServers.size();
                    if (upCount != 0 && serverCount != 0) {
                        int nextServerIndex = this.incrementAndGetModulo(serverCount);
                        server = (Server)allServers.get(nextServerIndex);
                        if (server == null) {
                            Thread.yield();
                        } else {
                            if (server.isAlive() && server.isReadyToServe()) {
                                return server;
                            }

                            server = null;
                        }
                        continue;
                    }

                    log.warn("No up servers available from load balancer: " + lb);
                    return null;
                }

                if (count >= 10) {
                    log.warn("No available alive servers after 10 tries from load balancer: " + lb);
                }

                return server;
            }
        }
    }

    private int incrementAndGetModulo(int modulo) {
       for(;;){
           int current = nextServerCyclicCounter.get();
           int next = (current+1)%modulo;
            if(nextServerCyclicCounter.compareAndSet(current,next))
                return next;
       }
        //自旋锁
    }

简单自定义实现:

  private AtomicInteger atomicInteger=new AtomicInteger(0);
    public final int getAndIncrement(){
           int current;
           int next;
           do{
               current=this.atomicInteger.get();
               next=current>=2147483647?0:current+1;
           }while (!this.atomicInteger.compareAndSet(current,next));
        //自旋锁,防止高并发场景下这个数字已经被其他进程占用过。
        // 2147483647Integer最大值Max_Value
        System.out.println(next);
        return next;
    }
    @Override
    public ServiceInstance instance(List<ServiceInstance> serviceInstances){
              return serviceInstances.get(getAndIncrement()%serviceInstances.size());
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值