【云原生】springcloud09——但愿发长久,空手撕Ribbon

本文涉及的产品
网络型负载均衡 NLB,每月750个小时 15LCU
应用型负载均衡 ALB,每月750个小时 15LCU
传统型负载均衡 CLB,每月750个小时 15LCU
简介: 【云原生】springcloud09——但愿发长久,空手撕Ribbon

1.Ribbon默认轮询算法原理

先将注解@RibbonClient注释掉。让它恢复到最开始的轮询算法。

7340122859da4402b01b3e4751238939.png

轮询算法的原理如下。妙不妙?

051a75a08a3544f6a36141fb7d99f051.png

2.RoundRobinRule源码解读

我们先解读下RoundRobinRule轮询算法的源码实现,方便后面仿照轮询算法实现默认的负载均衡算法。

31ea352c38734330ad97337743e75781.png

先看接口IRule

public interface IRule {
    Server choose(Object var1);
    void setLoadBalancer(ILoadBalancer var1);
    ILoadBalancer getLoadBalancer();
}

里面有一个choose方法,看看在RoundRobinRule中的具体实现吧。

  public Server choose(Object key) {
        return this.choose(this.getLoadBalancer(), key);
    }
  public Server choose(ILoadBalancer lb, Object key) {
  // 如果没有负载均衡算法,返回null
        if (lb == null) {
            log.warn("no load balancer");
            return null;
        } else {
            Server server = null;
            int count = 0;
            while(true) {
                if (server == null && count++ < 10) {
                //获取状态为up(活着的)服务器
                    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;
            }
        }
    }

看看incrementAndGetModulo方法

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

3.手写轮询算法

3.1 8001和8002微服务改造

在8001和8002的PaymentController中加上这个方法,用于测试我们的自定义轮询:

@GetMapping("/lb")
public String getPaymentLB(){
    return serverPort;
}

3.2 订单微服务改造

将订单微服务的负载均衡注解去掉

5a7fcce0674f4821aa6b4d3709d1816b.png

在springcloud包下新建lb.ILoadBalancer接口(自定义负载均衡机制(面向接口))

public interface LoadBalancer {
    // 传入具体的服务集合,返回服务实例
    ServiceInstance instances(List<ServiceInstance> instances);
}

在lb包下新建自定义ILoadBalancer接口的实现类,实现负载均衡的核心逻辑。下面用到了CAS自旋锁的知识,让代码很健壮。

@Component
public class MyLB implements LoadBalancer {
    // 新建一个原子整形实例,记录访问次数,使线程安全
    private AtomicInteger visitCount = new AtomicInteger(0);
    public final int getAndIncrement() {
        int current;
        int next;
        do {
            current = visitCount.get();
            //如果current是最大值,重新计算,否则加1(防止越界),
            // 正常情况肯定不会出现越界的情况,但是我们可以学习源码这种方式,提升代码健壮性
            next = current >= Integer.MAX_VALUE ? 0 : current + 1;
            // 当visitCount与current相等时,说明cas成功将visitCount更新为next,终止循环
            // 当visitCount与current不相等时,说明有其他线程操作atomicInteger,返回true,取反为false,循环操作
        } while (!this.visitCount.compareAndSet(current, next));
        System.out.println("****访问次数:" + next);
        // 返回的next即visitCount自增成功后的值
        return next;
    }
    @Override
    public ServiceInstance instances(List<ServiceInstance> instances) {
        // 轮询算法
        int index = getAndIncrement() % instances.size();
        return instances.get(index);
    }
}

接着在我们的OrderController代码逻辑里来引入自己的自旋锁吧。

    @Resource
    private ILoadBalancer iLoadBalancer;
    @Resource
    private DiscoveryClient discoveryClient;
    @GetMapping("/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();
        System.out.println(uri);
        return restTemplate.getForObject(uri+"/payment/lb",String.class);
    }

3.3 测试

启动Eureka Server集群7001,7002,支付微服务集群8001,8002,订单80微服务。

4feee647ecde4e27971ebf88101c2727.png

相关实践学习
SLB负载均衡实践
本场景通过使用阿里云负载均衡 SLB 以及对负载均衡 SLB 后端服务器 ECS 的权重进行修改,快速解决服务器响应速度慢的问题
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
相关文章
|
7月前
|
缓存 Java API
【云原生】Spring Cloud Gateway的底层原理与实践方法探究
【云原生】Spring Cloud Gateway的底层原理与实践方法探究
|
7月前
|
消息中间件 Cloud Native Java
【Spring云原生系列】SpringBoot+Spring Cloud Stream:消息驱动架构(MDA)解析,实现异步处理与解耦合
【Spring云原生系列】SpringBoot+Spring Cloud Stream:消息驱动架构(MDA)解析,实现异步处理与解耦合
|
3月前
|
Cloud Native Java 对象存储
面向未来的架构设计:Spring Cloud和Netflix OSS在云原生环境下的发展趋势
展望未来,随着5G、边缘计算等新技术的兴起,微服务架构的设计理念将会更加深入人心,Spring Cloud和Netflix OSS也将继续引领技术潮流,为企业带来更为高效、灵活且强大的解决方案。无论是对于初创公司还是大型企业而言,掌握这些前沿技术都将是在激烈市场竞争中脱颖而出的关键所在。
71 0
|
4月前
|
Cloud Native Java Nacos
微服务时代的新宠儿!Spring Cloud Nacos实战指南,带你玩转服务发现与配置管理,拥抱云原生潮流!
【8月更文挑战第29天】Spring Cloud Nacos作为微服务架构中的新兴之星,凭借其轻量、高效的特点,迅速成为服务发现、配置管理和治理的首选方案。Nacos(命名和配置服务)由阿里巴巴开源,为云原生应用提供了动态服务发现及配置管理等功能,简化了服务间的调用与依赖管理。本文将指导你通过五个步骤在Spring Boot项目中集成Nacos,实现服务注册、发现及配置动态管理,从而轻松搭建出高效的微服务环境。
310 0
|
1月前
|
负载均衡 监控 网络协议
SpringCloud之Ribbon使用
通过以上步骤,就可以在Spring Cloud项目中有效地使用Ribbon来实现服务调用的负载均衡,提高系统的可靠性和性能。在实际应用中,根据具体的业务场景和需求选择合适的负载均衡策略,并进行相应的配置和优化,以确保系统的稳定运行。
73 15
|
1月前
|
负载均衡 算法 Java
除了 Ribbon,Spring Cloud 中还有哪些负载均衡组件?
这些负载均衡组件各有特点,在不同的场景和需求下,可以根据项目的具体情况选择合适的负载均衡组件来实现高效、稳定的服务调用。
87 5
|
2月前
|
Cloud Native Java 对象存储
面向未来的架构设计:Spring Cloud和Netflix OSS在云原生环境下的发展趋势
面向未来的架构设计:Spring Cloud和Netflix OSS在云原生环境下的发展趋势
56 1
|
3月前
|
负载均衡 Java Nacos
SpringCloud基础1——远程调用、Eureka,Nacos注册中心、Ribbon负载均衡
微服务介绍、SpringCloud、服务拆分和远程调用、Eureka注册中心、Ribbon负载均衡、Nacos注册中心
SpringCloud基础1——远程调用、Eureka,Nacos注册中心、Ribbon负载均衡
|
4月前
|
负载均衡 算法 Java
SpringCloud之Ribbon使用
通过 Ribbon,可以非常便捷的在微服务架构中实现请求负载均衡,提升系统的高可用性和伸缩性。在实际使用中,需要根据实际场景选择合适的负载均衡策略,并对其进行适当配置,以达到更佳的负载均衡效果。
122 13
|
3月前
|
Cloud Native Java 对象存储
揭秘微服务架构之争:Spring Cloud与Netflix OSS巅峰对决,谁将称霸弹性云原生时代?
近年来,微服务架构成为企业应用的主流设计模式。本文对比了两大热门框架Spring Cloud和Netflix OSS,探讨其在构建弹性微服务方面的表现。Spring Cloud依托Spring Boot,提供全面的微服务解决方案,包括服务注册、配置管理和负载均衡等。Netflix OSS则由一系列可独立或组合使用的组件构成,如Eureka、Hystrix等。两者相比,Spring Cloud更易集成且功能完善,而Netflix OSS则需自行整合组件,但灵活性更高。实际上,两者也可结合使用以发挥各自优势。通过对两者的对比分析,希望为企业在微服务架构选型上提供参考。
83 0