负载均衡器Ribbon原理及实战演练

news2025/1/15 13:05:37

目录

一、负载均衡原理

二、Ribbon 原理及使用

三、Loadbalancer 原理及使用 


负载均衡器Ribbon在微服务领域是很常用的服务调用、负载均衡的中间件,其面包含Loadbalancer专门负载负载均衡;比如Eureka、Fegin,Nacos的注册中心jar包里面均包含Ribbon相关的jar,如图显示nacos

 今天我们详细分析一下其原理和实战内容。

一、负载均衡原理

        负载均衡(Load Balance),其含义就是指将负载(工作任务)进行平衡、分摊到多个操作单元上进行运行,例如FTP服务器、Web服务器、企业核心应用服务器和其它主要任务服务器等,从而协同完成工作任务。目前主流的负载均衡方案分为以下两种:
         集中式负载均衡,在消费者和服务提供方中间使用独立的代理方式进行负载,有硬件的(比如F5),也有软件的(比如 Nginx);客户端根据自己的请求情况做负载均衡,Ribbon 就属于客户端自己做负载均衡。

1、客户端负载均衡

 比如spring cloud中的ribbon,客户端会有一个服务器地址列表,在发送请求前通过负载均衡算法选择一个服务器,然后进行访问,这是客户端负载均衡;即在客户端就进行负载均衡算法分配,eureka 为注册中心为例,如下:

 2、服务端负载均衡

        例如Nginx,通过Nginx进行负载均衡,先发送请求,然后通过负载均衡算法,在多个服务器之间选择一个进行访问;即在服务器端再进行负载均衡算法分配。

 3、常见负载均衡算法

3.1、随机:通过随机选择服务进行执行,一般这种方式使用较少;
3.2、轮训:负载均衡默认实现方式,请求来之后排队处理;
3.3、加权轮训:通过对服务器性能的分型,给高配置,低负载的服务器分配更高的权重,均衡各个          服务器的压力;
3.4、地址hash:通过客户端请求的地址的hash值取模映射进行服务器调度。
3.5、最小连接数:即使请求均衡了,压力不一定会均衡,最小连接数法就是根据服务器的情况,比           如请求积压数等参数,将请求分配到当前压力最小的服务器上。

二、Ribbon 原理及使用

 Spring Cloud Ribbon是基于Netflix Ribbon 实现的一套客户端的负载均衡工具,Ribbon客户端组件提供一系列的完善的配置,如超时,重试等。通过Load Balancer获取到服务提供的所有机器实例,Ribbon会自动基于某种规则(轮询,随机)去调用这些服务。Ribbon也可以实现自己的负载均衡算法。

1、Spring Cloud Alibaba整合Ribbon

上篇文章有详解

2、Ribbon 内核原理

 2.1、模拟Ribbon 伪代码实现


import com.nandao.common.utils.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author nandao
 */
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping(value = "/findOrderByUserId/{id}")
    public R  findOrderByUserId(@PathVariable("id") Integer id) {
        // restTemplate调用,url写死
        //String url = "http://localhost:8020/order/findOrderByUserId/"+id;
        //模拟ribbon实现
        String url = getUri("mall-order")+"/order/findOrderByUserId/"+id;
        // ribbon实现,restTemplate需要添加@LoadBalanced注解
     //   String url = "http://mall-order/order/findOrderByUserId/"+id;
        R result = restTemplate.getForObject(url,R.class);
        return result;
    }

    @Autowired
    private DiscoveryClient discoveryClient;//cloud客户端实现

    public String getUri(String serviceName) {
        // 获取服务的实例
        List<ServiceInstance> serviceInstances = discoveryClient.getInstances(serviceName);
        if (serviceInstances == null || serviceInstances.isEmpty()) {
            return null;
        }
        int serviceSize = serviceInstances.size();
        //轮询
        int indexServer = incrementAndGetModulo(serviceSize);
        return serviceInstances.get(indexServer).getUri().toString();
    }

    private AtomicInteger nextIndex = new AtomicInteger(0);

    private int incrementAndGetModulo(int modulo) {
        for (;;) {
            int current = nextIndex.get();
            int next = (current + 1) % modulo;
            if (nextIndex.compareAndSet(current, next) && current < modulo){
                return current;
            }
        }
    }
}

2.2、@Loadbalanced原理

@LoadBalanced使用了@Qualifier,spring中@Qualifier用于筛选限定注入Bean。
@LoadBalanced利用@Qualifier作为restTemplates注入的筛选条件,筛选出具有负载均衡标识的RestTemplate。

 

被@LoadBalanced注解的restTemplate会被定制,添加LoadBalancerInterceptor拦截
器。

 注意: SmartInitializingSingleton是在所有的bean都实例化完成之后才会调用的,所以在
bean的实例化期间使用@LoadBalanced修饰的restTemplate是不具备负载均衡作用的,比如使用@PostConstruct 注解下的接口远程调用就不具备负载均衡作用,报错找不到服务。

如果不使用@LoadBalanced注解,也可以通过添加LoadBalancerInterceptor拦截器让
restTemplate起到负载均衡器的作用。

    @Bean
    public RestTemplate restTemplate(LoadBalancerInterceptor loadBalancerInterceptor) {
        RestTemplate restTemplate = new RestTemplate();
        //注入loadBalancerInterceptor拦截器
        restTemplate.setInterceptors(Arrays.asList(loadBalancerInterceptor));
        return restTemplate;
    }
    

3、Ribbon 扩展功能

3.1、Ribbon相关接口

参考: org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration 源码类:

IClientConfig:Ribbon的客户端配置,默认采用DefaultClientConfigImpl实现。
IRule:Ribbon的负载均衡策略,默认采用ZoneAvoidanceRule实现,该策略能够在多区域环境下选出最佳区域的实例进行访问。
IPing:Ribbon的实例检查策略,默认采用DummyPing实现,该检查策略是一个特殊的实现,实际上它并不会检查实例是否可用,而是始终返回true,默认认为所有服务实例都是可用的。
ServerList:服务实例清单的维护机制,默认采用ConfigurationBasedServerList实现。
ServerListFilter:服务实例清单过滤机制,默认采ZonePreferenceServerListFilter,该策略能够优先过滤出与请求方处于同区域的服务实例。
ILoadBalancer:负载均衡器,默认采用ZoneAwareLoadBalancer实现,它具备了区域感知的能力。

3.2、Ribbon 负载均衡策略


1). RandomRule: 随机选择一个Server。
2). RetryRule: 对选定的负载均衡策略机上重试机制,在一个配置时间段内当选择Server不成功,则一直尝试使用subRule的方式选择一个可用的server。
3). RoundRobinRule: 轮询选择, 轮询index,选择index对应位置的Server。
4). AvailabilityFilteringRule: 过滤掉一直连接失败的被标记为circuit tripped的后端Server,并过滤掉那些高并发的后端Server或者使用一个AvailabilityPredicate来包含过滤server的逻辑,其实就是检查status里记录的各个Server的运行状态。
5). BestAvailableRule: 选择一个最小的并发请求的Server,逐个考察Server,如果Server被         tripped了,则跳过。
6). WeightedResponseTimeRule: 根据响应时间加权,响应时间越长,权重越小,被选中的可能       性越低。
7). ZoneAvoidanceRule: 默认的负载均衡策略,即复合判断Server所在区域的性能和Server的可       用性选择Server,在没有区域的环境下,类似于轮询。
8). NacosRule: 优先调用同一集群的实例,基于随机权重。 

3.3、修改默认负载均衡策略

mall-order:
  ribbon:
    #指定使用Nacos提供的负载均衡策略(优先调用同一集群的实例,基于随机&权重)
    NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule
  

3.4、自定义负载均衡策略

全局配置


import com.alibaba.cloud.nacos.ribbon.NacosRule;
import com.netflix.loadbalancer.IRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author nandao
 */
@Configuration
public class RibbonConfig {

    /**
     * 全局配置
     * 指定负载均衡策略
     * @return
     */
    @Bean
    public IRule ribbonRule() {
        // 指定使用Nacos提供的负载均衡策略(优先调用同一集群的实例,基于随机权重)
        return new NacosRule();
    }
}

局部配置

mall-order:
  ribbon:
    #指定使用Nacos提供的负载均衡策略(优先调用同一集群的实例,基于随机&权重)
    #NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule
  # 自定义的负载均衡策略(基于随机&权重)
    NFLoadBalancerRuleClassName: com.nandao.mall.ribbondemo.rule.NacosRandomWithWeightRule

 NacosRandomWithWeightRule 类


import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.ribbon.NacosServer;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.DynamicServerListLoadBalancer;
import com.netflix.loadbalancer.Server;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * @author nandao
 */
@Slf4j
public class NacosRandomWithWeightRule extends AbstractLoadBalancerRule {

    @Autowired
    private NacosDiscoveryProperties nacosDiscoveryProperties;

    @Override
    public Server choose(Object key) {
        DynamicServerListLoadBalancer loadBalancer = (DynamicServerListLoadBalancer) getLoadBalancer();
        String serviceName = loadBalancer.getName();
        NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();

        try {
            //nacos基于随机权重的算法
            Instance instance = namingService.selectOneHealthyInstance(serviceName);
            log.info(instance.getIp()+":"+instance.getPort());
            return new NacosServer(instance);
        } catch (NacosException e) {
            log.error("获取服务实例异常:{}", e.getMessage());
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {

    }

}

4.5、饥饿加载

在进行服务调用的时候,如果网络情况不好,第一次调用会超时。Ribbon默认懒加载,意味着只有在发起调用的时候才会创建客户端,开启饥饿加载,解决第一次调用慢的问题。参数配置:

ribbon:
  eager-load:
    # 开启ribbon的饥饿加载模式
    enabled: true
    # 指定需要饥饿加载的服务名,也就是你需要调用的服务,如果有多个服务,则用逗号隔开
    clients: mall-order

客户端启动标识:

 即服务启动时就加载成功了!

三、Loadbalancer 原理及使用 

Spring Cloud LoadBalancer是Spring Cloud官方自己提供的客户端负载均衡器, 用来替代Ribbon。
Spring官方提供了两种客户端都可以使用loadbalancer如下:
RestTemplate:RestTemplate是Spring提供的用于访问Rest服务的客户端,RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。默认情况下,RestTemplate默认依赖jdk的HTTP连接工具。
WebClient:WebClient是从Spring WebFlux 5.0版本开始提供的一个非阻塞的基于响应式编程的进行Http请求的客户端工具。它的响应式编程的基于Reactor的。WebClient中提供了标准Http请求方式对应的get、post、put、delete等方法,可以用来发起相应的请求。

1、RestTemplate整合LoadBalancer

1.1、引入依赖

        <!-- nacos服务注册与发现 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring‐cloud‐starter‐netflix‐ribbon</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- LoadBalancer -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>

注意: nacos-discovery中引入了ribbon,需要移除ribbon的包如果不移除,也可以在yml中配置不使用ribbon。默认情况下,如果同时拥有RibbonLoadBalancerClient和BlockingLoadBalancerClient,为了保持向后兼容性,将使用RibbonLoadBalancerClient。

 另外要覆盖它,可以设置spring.cloud.loadbalancer.ribbon.enabled属性为false。

spring:
  application:
    name: mall-user-loadbalancer-demo  #微服务名称

  #配置nacos注册中心地址
  cloud:
    nacos:
      discovery:
        server-addr: 116.204.80.152:8848
        namespace: 2aa2111a-3470-4f69-9994-e9d288e20a62
        group: wanghuainan

    # 不使用ribbon,使用loadbalancer
    loadbalancer:
      ribbon:
        enabled: false

1.2、使用@LoadBalanced注解修饰RestTemplate,开启客户端负载均衡功能

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

1.3、接口调用

@RestController
 @RequestMapping("/user")
 public class UserController {
 
 @Autowired
 private RestTemplate restTemplate;
 
 @RequestMapping(value = "/findOrderByUserId/{id}")
 public R findOrderByUserId(@PathVariable("id") Integer id) {
    String url = "http://mall‐order/order/findOrderByUserId/"+id;
    R result = restTemplate.getForObject(url,R.class);
    return result;
  }
}

2、WebClient整合LoadBalancer

2.1、引入依赖

在上面依赖的基础上添加

       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>

2.2、配置WebClient作为负载均衡器的client


import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;

@Configuration
public class WebClientConfig {

  @LoadBalanced
  @Bean
  WebClient.Builder webClientBuilder() {
    return WebClient.builder();
  }

  @Bean
  WebClient webClient() {
    return webClientBuilder().build();
  }

}

2.3、接口调用

    @Autowired
    private WebClient webClient;

    @RequestMapping(value = "/findOrderByUserId2/{id}")
    public Mono<R> findOrderByUserIdWithWebClient(@PathVariable("id") Integer id) {

        String url = "http://mall-order/order/findOrderByUserId/"+id;
        //基于WebClient
        Mono<R> result = webClient.get().uri(url).retrieve().bodyToMono(R.class);
        return result;
    }

原理: 底层会使用ReactiveLoadBalancer,类图显示:

引入webFlux

    @Autowired
    private ReactorLoadBalancerExchangeFilterFunction lbFunction;

    @RequestMapping(value = "/findOrderByUserId3/{id}")
    public Mono<R> findOrderByUserIdWithWebFlux(@PathVariable("id") Integer id) {

        String url = "http://mall-order/order/findOrderByUserId/"+id;
        //基于WebClient+webFlux
        Mono<R> result = WebClient.builder()
                .filter(lbFunction)
                .build()
                .get()
                .uri(url)
                .retrieve()
                .bodyToMono(R.class);
        return result;
    }

 到此、负载均衡器Ribbon原理及实战演练分享完毕,有时间一定要多多练习。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/156212.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python实战案例:采集某漫客《网游之近战法师》所有章节

前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! 环境使用: Python 3.8 Pycharm 模块使用: requests >>> pip install requests 数据请求模块 parsel >>> pip install parsel 数据解析模块 如果安装python第三方模块: win R 输入 cmd 点击确定, 输…

C++学习之旅 第五章(字符应用:小写字母转大写字母)

开头&#xff1a; 上一节我们讲了关于char类型许多知识&#xff0c;今天我们来更深层的学习一下字符实际上面的应用&#xff01; ASCII码简介&#xff1a; 我们要进行字符的应用&#xff0c;首先就是要了解一下ACSII码: ASCII(全名&#xff1a;American Standard Code for Inf…

win10如何安装多个jdk并实时进行切换【建议收藏】

在windows10的系统中&#xff0c;如何安装jdk或者安装多个jdk版本&#xff0c;博主在这里整理了一份非常完美的jdk版本安装教程&#xff0c;且jdk版本可以随时切换&#xff0c;切换过程不超过10秒&#xff0c;让你在jdk版本中穿梭自如&#xff0c;直接可以食用&#xff0c;掌握…

【前端】ES6

let 和 const 类似var定义变量&#xff0c;但是let修饰的变量仅在声明的代码块中有效&#xff1b; var声明的变量&#xff0c;在全局有效 for (let i 0; i < 3; i) {let i abc;console.log(i); }js中的for循环声明循环变量的部分也作为一个父作用域&#xff0c;即(let i…

虹科方案|数据中心虚拟化和 HK-ATTO 产品—旨在协同工作的端到端解决方案

一、概述虚拟化技术正迅速成为现代数据中心的基础&#xff0c;因为IT 管理寻求显着提 高资源和运营效率以及对业务需求的响应能力。三个关键技术非常重要&#xff1a;服务器虚拟化、结构虚拟化和存储虚拟化。 本次介绍了 HK-ATTO 产品如何作为这些虚拟化解决方案中 每一个的关键…

【图像处理OpenCV(C++版)】——4.1 对比度增强之灰度直方图

前言&#xff1a; &#x1f60a;&#x1f60a;&#x1f60a;欢迎来到本博客&#x1f60a;&#x1f60a;&#x1f60a; &#x1f31f;&#x1f31f;&#x1f31f; 本专栏主要结合OpenCV和C来实现一些基本的图像处理算法并详细解释各参数含义&#xff0c;适用于平时学习、工作快…

声纹识别与声源定位(二)

一、引言 什么是声源定位(Sound Source Localization&#xff0c;SSL)技术&#xff1f;声源定位技术是指利用多个麦克风在环境不同位置点对声信号进行测量&#xff0c;由于声信号到达各麦克风的时间有不同程度的延迟&#xff0c;利用算法对测量到的声信号进行处理&#xff0c;由…

【瑞萨RA4系列】使用TinyMaix识别手写数字

文章目录一、TinyMaix简介1.1 TinyMaix开源项目1.2 下载TinyMaix源码二、TinyMaix移植2.1 创建TinyMaix移植项目2.2 添加TinyMaix源码三、TinyMaix测试准备3.1 SysTick计时3.2 printf打印3.4 修改tm_port.h文件3.6 增大堆内存空间四、手写数字识别4.1 添加示例源码4.2 运行示例…

突破6.8关口 人民币汇率快速升值,释放什么信号?

近期以来&#xff0c;人民币表现强劲。2023年开年6个交易日&#xff0c;人民币对美元汇率中间价实现“六连涨”&#xff0c;累计上调2035个基点&#xff0c;升破6.8关口&#xff0c;展现出全新面貌。哪些因素影响近期人民币对美元汇率上涨&#xff1f;人民币兑美元汇率未来走势…

漏洞复现--xss

目录 一、实验目的 二、实验环境 三、 实验过程 搭建XSS平台 制作XSS脚本并注入 利用Cookie登录用户账号 一、实验目的 实验目的 本实验学习如何搭建个人的XSS平台以及如何使用XSS平台盗用用户Cookie登录。 二、实验环境 服务器&#xff1a;Windows 7 Target IP:10.1.…

【笔记:第5课】学习开发一个RISC-V上的操作系统 - 汪辰 - 2021春

文章目录前言来源正文小结前言 创作开始时间&#xff1a;2023年1月11日16:55:32 如题&#xff0c;学习一下RISC-V。 来源 https://www.bilibili.com/video/BV1Q5411w7z5?p5&vd_source73a25632b4f745be6bbcfe3c82bb7ec0 刚刚才知道老师是PLCT实验室的&#xff0c;牛。…

C 程序设计教程(16)—— 循环结构程序设计

C 程序设计教程&#xff08;16&#xff09;—— 循环结构程序设计 该专栏主要介绍 C 语言的基本语法&#xff0c;作为《程序设计语言》课程的课件与参考资料&#xff0c;用于《程序设计语言》课程的教学&#xff0c;供入门级用户阅读。 目录C 程序设计教程&#xff08;16&…

Vue3之对Dialog的简单封装

之前使用的UI框架,无论是Element UI/Plus 还是 Ant design&#xff0c;其中Dialog组件中的结构和样式都难以修改&#xff0c;无论是使用less、deep还是其他方法&#xff0c;对其组件中css的修改都不生效&#xff08;不确定是否有其他解决方法&#xff09;&#xff0c;所以我就自…

【小白必看】2023年PMP考试报名时间,报考条件,超全PMP备考指南

PMP 考试一年能考四次&#xff0c;分别是3月、6月、9月、12月&#xff0c;提前 2 个月开始报名&#xff0c;但还是要关注PMI/基金会官网的信息&#xff0c;有特殊情况的会在官网公布。现在放开了&#xff0c;2023年PMP 考试应该不会再延期了&#xff0c;之前没考上的&#xff0…

重装系统win11的步骤和详细教程

想要给电脑重装系统win11使用&#xff0c;但是自己对于相关的重装操作不熟悉怎么样?我们可以网上的小白装机工具实现&#xff0c;那么具体怎么重装系统win11?下面就演示下重装系统win11的步骤和详细教程。 工具/原料&#xff1a; 系统版本&#xff1a;Windows 11 品牌型号…

js使用小顶堆构建优先级队列

什么是优先级队列? 优先级队列是队列的一个变种,队列是一个先进先出的结构,在头部出队元素在尾部入队元素, 优先级队列顾名思义就是给每个元素具备了优先级,优先级决定了元素在队列中的存储位置,优先级越高的越靠前越先出队 小顶堆又是什么? 小顶堆是堆结构的一个分支,堆…

浙大MEM提面优秀成功上岸经验分享——完全准备才能“聊”的好

近期元旦放假&#xff0c;终于有时间写一写关于自己浙大MEM提面上岸的一些经验分享了。这篇可能对接下来参加2024年浙大mem考试的考生会有一些作用。因为我是参加了提前批面试&#xff0c;并在面试中取得了优秀的资格&#xff0c;所以这也为我后续的联考和录取环节减轻了不少的…

[JAVA安全]filter 内存马

原理&#xff1a; Servlet 有自己的过滤器 filter &#xff0c; 可以通过自定义的过滤器&#xff0c;来对用户的请求进行拦截等操作。 经过filter 之后才会刀Servlet &#xff0c;如果我们动态创建一个 filter 并且将其放在最前面&#xff0c;我们的filter 就会最先被执行&…

Java多线程案例——线程池及ThreadPoolExecutor类

一&#xff0c;线程池1.为什么会有线程池&#xff1f;线程池和多线程的区别&#xff1f;为了很好的解决高并发问题&#xff0c;提高计算机的运行效率&#xff0c;提出了多线程来取代多进程&#xff08;因为一个线程的创创建、销毁和调度比进程更加“轻量”&#xff0c;所以线程…

杰卡德相似度(Jaccard)详解及在UserCF中的应用

1、杰卡德相似度(Jaccard) 这个是衡量两个集合的相似度一种指标。 两个集合A和B的交集元素在A&#xff0c;B的并集中所占的比例&#xff0c;称为两个集合的杰卡德相似系数&#xff0c;用符号J(A,B)表示 另一种表示的方法&#xff1a; jaccard系数衡量维度相似性 jaccard系数很…