04.SpringCloud Ribbon (负载均衡服务调用)

1.Ribbon的概述

是什么

官网资料
Ribbon目前也进入维护模式
未来替换方案 LoadBalancer  现在还是ribbon用的多

能干嘛

LB(负载均衡)


集中式LB


进程内LB


前面我们讲解过了80通过轮询负载访问8001/8002
一句话
ribbon = 负载均衡+RestTemplate调用

2.Ribbon负载均衡演示

架构说明

总结:Ribbon其实就是一个软负载均衡的客户端组件,他可以和其他所需请求的客户端结合使用,和eureka结合只是其中的一个实例。

eureka的客户端集成了ribbon

pom说明

RestTemplate的使用

官网
  • 返回的object       
      
  • 返回的entity
    

getForObject和getForEntity


postForObject和postForEntity


3.Ribbon核心组件IRule

IRule基本说明

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

替换负载均衡组件步骤

修改cloud-consumer-order80
注意配置细节
新建package  com.chl.myrule

上面包下新建MySelfRule规则类
/**
 * 切换负载均衡的算法
 */
@Configuration
public class MyselfRule {
   
    //切换为随机
    @Bean
    public IRule myRule(){
        return new RandomRule();
    }
}
主启动类添加@RibbonClient
@EnableEurekaClient
@SpringBootApplication
//自定义CLOUD-PAYMENT-SERVICE 的ribbon负载均衡算法
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MyselfRule.class)
public class OrderMain80 {
    public static void main(String[] args) {
        SpringApplication.run(OrderMain80.class,args);
    }
}
测试

4.Ribbon负载均衡算法(轮询说明)

原理


源码

public class RoundRobinRule extends AbstractLoadBalancerRule {
    private AtomicInteger nextServerCyclicCounter; //原子类
    private static final boolean AVAILABLE_ONLY_SERVERS = true;
    private static final boolean ALL_SERVERS = false;
    private static Logger log = LoggerFactory.getLogger(RoundRobinRule.class);

    public RoundRobinRule() {
        this.nextServerCyclicCounter = new AtomicInteger(0);
    }

    public RoundRobinRule(ILoadBalancer lb) {
        this();
        this.setLoadBalancer(lb);
    }
    
    
    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) {
        int current;
        int next;
        do {
            current = this.nextServerCyclicCounter.get();
            next = (current + 1) % modulo;
        } while(!this.nextServerCyclicCounter.compareAndSet(current, next));

        return next;
    }
   
    //
    public Server choose(Object key) {
        return this.choose(this.getLoadBalancer(), key);
    }

    public void initWithNiwsConfig(IClientConfig clientConfig) {
    }
}

手写轮询负载均衡

7001/7002集群启动
8001/8002微服务改造   PaymentController  添加测试方法
//获取端口 用于测试手写的ribbon轮训算法
    @GetMapping(value = "/payment/lb")
    public String getPaymentLB(){
        return serverPort;
    }
80订单微服务改造
1.ApplicationContextBean去掉@LoadBalanced  (去掉ribbon负载均衡实现的注解)
2.新建立LoadBalancer接口 
public interface LoadBalancer {
     //收集服务器总共有多少台能够提供服务的机器,并放到list里面,实现类,实现负载均衡算法
    //返回一个实例
    ServiceInstance instances(List<ServiceInstance> serviceInstances);

}
3.MyLB
/**
 * 手写的轮询算法
 */
@Component
public class MyLB implements LoadBalancer {

    private AtomicInteger atomicInteger = new AtomicInteger(0);

    //坐标  自旋锁实现
    private final int getAndIncrement(){
        int current;
        int next;
        do {
            current = this.atomicInteger.get();
            next = current >= 2147483647 ? 0 : current + 1; //访问一次,加1
        }while (!this.atomicInteger.compareAndSet(current,next));  //第一个参数是期望值,第二个参数是修改值是
        System.out.println("*******第几次访问,次数next: "+next);
        return next;
    }

    //放全部实例列表,然后自旋锁获取下标,余数得到坐标 
    //根据坐标,从实例中获取实例返回去
    @Override 
    public ServiceInstance instances(List<ServiceInstance> serviceInstances) {  //得到机器的列表
       int index = getAndIncrement() % serviceInstances.size(); //得到服务器的下标位置
        return serviceInstances.get(index);
    }
}

4.OrderController
 /**
     *
     * 测试手写的轮训算法
     * 就是根据服务名,获取某个服务的全部实例总数
     * 传到手写的负载均衡算法里面,返回一个实例
     * 获取返回实例的uri,访问服务提供方
     * @return
     */
    @GetMapping(value = "/consumer/payment/lb")
    public String getPaymentLB(){
        List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
        if (instances == null || instances.size() <= 0){
            return null;
        }
        ServiceInstance serviceInstance = loadBalancer.instances(instances);
        URI uri = serviceInstance.getUri();
        return restTemplate.getForObject(uri+"/payment/lb",String.class);
    }
5.测试
http://localhost/consumer/payment/lb   8001 8002 端口交替出现

posted @ 2020-12-31 09:39  超极本online  阅读(154)  评论(0)    收藏  举报