详解Ribbon

本文涉及的产品
网络型负载均衡 NLB,每月750个小时 15LCU
应用型负载均衡 ALB,每月750个小时 15LCU
传统型负载均衡 CLB,每月750个小时 15LCU
简介: 1.概述Ribbon是Netflix开源的一个客户端负载均衡库,也是Spring Cloud Netflix项目的核心组件之一。它主要用于在微服务架构中对服务进行负载均衡,以提高系统的可用性和性能。ribbon不是通信组件,而是服务调用者和通信组件之间的中间层,主要就是用来做负载均衡,选择出适合处理本次请求的服务节点。

1.概述

Ribbon是Netflix开源的一个客户端负载均衡库,也是Spring Cloud Netflix项目的核心组件之一。它主要用于在微服务架构中对服务进行负载均衡,以提高系统的可用性和性能。ribbon不是通信组件,而是服务调用者和通信组件之间的中间层,主要就是用来做负载均衡,选择出适合处理本次请求的服务节点。


现在整个spring cloud体系中的通信组件其实就是封装了负载均衡组件+HTTP通信组件,HTTP通信组件没什么好说的,就是用来发起HTTP请求的,市面上的HTTP通信组件也很多,诸如spring boot自带的RestTemplate,apache的Apache HttpClient等等。值得去探究一下的是负载均衡组件,其作为负载均很组件决定了请求的分发,可以说是整个通信组件的核心。


从Spring Cloud 2020.0版本开始,Spring Cloud官方已经将Ribbon标记为过时(deprecated),推荐使用Spring Cloud LoadBalancer作为替代方案。这样做是基于标准化的考虑,整个spring生态历来都是希望“包容万物”,所以社区自然不希望在负载均衡组件上直接就采用一个固定的实现,而是希望能让三方的解决方案可以平滑的接入、切换。


虽然ribbon以后不再是负载均衡组件的首选,但是作为最经典的负载均衡组件,其底层的一些思想仍然被后面的方案沿用,其实看明白ribbon的源码基本上也就明白负载均衡的原理了,万变不离其宗。


2.使用

2.1.引入

博主的上篇文章详细介绍了怎么使用eureka+通信组件来完成服务的注册、调用,其中也详细的介绍了ribbon的使用,可以移步:


详解Eureka服务注册和调用__BugMan的博客-CSDN博客


总的来说就是:


eureka集成了ribbon,导入eureka后不用单独导入ribbon,但是要注意的是一定要选对版本号,不要选到一个已经把ribbon移除的高版本,本文使用的依赖版本:

423488827561484e8ae5a7869dcb5a23.png

当然你也可以直接降级整个spring cloud的版本号,关于spring cloud版本号的问题,可以移步博主的另一篇文章,会有详细讲解:


详解Spring Cloud版本问题__BugMan的博客-CSDN博客


2.2.启用

引入依赖后在承载HTTP通信组件上开启负载均衡即可,此处以spring boot自带的RestTemplate为例,这样在每次客户端(消费者)发起http请求的时候都会在本端进行负载均衡运算后再进行服务访问。

4d3e5fbdbcd84d79a992d70a23922283.png

2.3.切换负载均衡算法

负载均衡的核心接口Irule有多个实现类,每个实现类实现不同的负载均衡算法,


常用的有,轮询、随机、可获得、重试等几种:


RoundRobinRule,轮询


RandomRule,随机


AvailabilityFilteringRule,会过滤掉,跳闸,访问故障的服务,对剩下的进行轮询


RetryRule,会按照轮询获取服务,如果服务获取失败,则会在指定的时间内进行重试


需要切换的时候直接在@Configuration中注入@Bean即可:

cac83a27564c46ed92693531245665fa.png

3.负载均衡源码分析

3.1.接口

IRule接口:

  • choose:选举出一个服务器
  • get/setLoadBalancer:获取、修改均衡器

ILoadBalancer:

与服务器打交道,负责寻找、登记服务器

2fc2cc0b923c48d0af86d9ca2cd9be20.png

3.2.抽象类

AbstractLoadBalancer实现了Irule接口,重写了均衡器的get/set方法,只留下一个抽象方法——choose,待子类重写。

315d23a6ec9541e3b9e8c803d8b2c379.png

3.3.选择服务器

所有实现类都继承抽象类AbstractLoadBalancer。各自去重写choose方法,即各自实现不同的负载均衡规则(此处以ribbon默认的负载均衡规则,RoundRobinRule为例):

0ded51b79d3140aebb2e066ec5be8699.png

choose方法即负载均衡策略,是各负载均衡类的核心方法(此处以ribbon默认的负载均衡规则,RoundRobinRule为例):


均衡器会和注册中心交互,然后记录下当前整个系统中所有服务器的相关信息,包含服务器总数,可用总数等。


向均衡器所要服务器总数、服务器可用总数,然后根据这两个值进行运算,挑选出承载该此流量的服务器。

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

整个过程中封装服务器相关信息的Server类,其中有服务器的详细参数:

f4b7354f53744ccda32088939907160c.png

3.4.原子性

挑选过程中,为了保证原子性,使用了自旋锁(CAS),保证每次处理的只有一个访问线程,其余线程处于自选等待状态:


compareAndSet(期望值,修改值)


期望值,即版本号。


修改值,即要将版本号更新为的值。


判断期望值是否改变(前后是否相同),如果期望值未改变,则将期望值更新为修改值。


返回true,否则返回false。

6df4966344a447609c018081e1df66c4.png

4.自定义负载均衡算法

存在顶级接口并且可以切换负载均衡算法,那自然可以自定义负载均衡算法,以下是一个根据服务器权重进行负载均衡的一个负载均衡算法:

public class CustomWeightedRandomRule extends AbstractLoadBalancerRule {
    private AtomicInteger totalWeight = new AtomicInteger(0);
    @Override
    public Server choose(Object key) {
        ILoadBalancer lb = getLoadBalancer();
        if (lb == null) {
            return null;
        }
        List<Server> allServers = lb.getAllServers();
        int serverCount = allServers.size();
        if (serverCount == 0) {
            return null;
        }
        int randomWeight = ThreadLocalRandom.current().nextInt(totalWeight.get());
        int currentWeight = 0;
        for (Server server : allServers) {
            currentWeight += getWeight(server);
            if (randomWeight < currentWeight) {
                return server;
            }
        }
        // Fallback to the default server if no server is selected
        return super.choose(key);
    }
    private int getWeight(Server server) {
        // Return the weight of the server (custom logic)
        // Example: return server.getMetadata().getWeight();
        return 1; // Default weight is 1
    }
    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
        super.initWithNiwsConfig(clientConfig);
        // Calculate the total weight of all servers
        List<Server> allServers = getLoadBalancer().getAllServers();
        totalWeight.set(allServers.stream().mapToInt(this::getWeight).sum());
    }
}


相关实践学习
SLB负载均衡实践
本场景通过使用阿里云负载均衡 SLB 以及对负载均衡 SLB 后端服务器 ECS 的权重进行修改,快速解决服务器响应速度慢的问题
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
目录
相关文章
|
负载均衡 Java 微服务
OpenFeign原来是这么基于Ribbon来实现负载均衡的
大家好,我是三友~~ 前面我已经剖析了OpenFeign的动态代理生成原理和Ribbon的运行原理,这篇文章来继续剖析SpringCloud组件原理,来看一看OpenFeign是如何基于Ribbon来实现负载均衡的,两组件是如何协同工作的。
OpenFeign原来是这么基于Ribbon来实现负载均衡的
|
21天前
|
负载均衡 监控 网络协议
SpringCloud之Ribbon使用
通过以上步骤,就可以在Spring Cloud项目中有效地使用Ribbon来实现服务调用的负载均衡,提高系统的可靠性和性能。在实际应用中,根据具体的业务场景和需求选择合适的负载均衡策略,并进行相应的配置和优化,以确保系统的稳定运行。
40 15
|
7月前
|
负载均衡 Java 应用服务中间件
Ribbon、Feign和OpenFeign的区别来了
Ribbon、Feign和OpenFeign的区别来了
283 2
|
7月前
Springcloud-ribbon和hystrix配置
Springcloud-ribbon和hystrix配置
46 0
|
负载均衡 网络协议 算法
【springcloud】Ribbon详解
Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现。简单点说,其主要功能是提供客户端的软件负载均衡算法和服务调用。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接,权重等)去连接这些机器。
280 0
|
7月前
|
负载均衡 Java 应用服务中间件
springcloud3-服务到服务调用ribbon及openfeign
springcloud3-服务到服务调用ribbon及openfeign
79 0
|
缓存 负载均衡 Java
深入剖析ribbon源码
深入剖析ribbon源码
168 0
深入剖析ribbon源码
|
缓存 负载均衡 Java
原来这就是大名鼎鼎的SpringCloud Ribbon
大家好,我是三友~~ 本文我将继续来剖析SpringCloud中负载均衡组件Ribbon的源码。本来我是打算接着OpenFeign动态代理生成文章直接讲Feign是如何整合Ribbon的,但是文章写了一半发现,如果不把Ribbon好好讲清楚,那么有些Ribbon的细节理解起来就很困难,所以我还是打算单独写一篇文章来剖析Ribbon的源码,这样在讲Feign整合Ribbon的时候,我就不再赘述这些细节了。
|
负载均衡 算法 网络协议
08SpringCloud - Ribbon介绍
08SpringCloud - Ribbon介绍
63 0
|
负载均衡 Java 微服务
详解ribbon
详解ribbon
124 0