负载均衡 —— SpringCloud Netflix Ribbon

news2024/11/20 14:26:05

Ribbon 简介

Ribbon 是 Netfix 客户端的负载均衡器,可对 HTTP 和 TCP 客户端的行为进行控制。为 Ribbon 配置服务提供者地址后,Ribbon 就可以基于某种负载均衡算法自动帮助服务消费者去请求。Ribbon 默认提供了很多负载均衡算法,例如轮询、随机等,也可以为 Ribbon 实现自定义的负载均衡算法

Ribbon 有以下几个重要概念:

  • Rule:该组件主要决定从候选服务器中返回哪个服务器地址进行远程调用的操作
  • Ping:在后台运行的组件,用来确认哪些服务器是存活可用的
  • ServerList:当前可以用作 LB 的服务器列表,该列表可以是静态的,也可以是动态的。如果是动态列表(例如从 Eurka 服务器获取),就会有一个后台线程按照时间间隔刷新列表

Ribbon 提供了以下几种 Rule:

  • RoundRobinRule:最简单的规则,会在 ServerList 中依次轮询调用
  • RandomRule:随机
  • AvailabilityFileringRule:在这种规则下 Ribbon 集成了 Hystrix 的功能,默认情况下调用某个远程方法失败三次后断路器的开关会被打开,而之后的请求中 Ribbon 会跳过这个服务器地址,直到三十秒之后断路器关闭后才会重新加入调用列表
  • WeightedResponseTimeRule:将响应时间作为权重的负载规则,某个服务器的响应时越长,它的权重就越低,具体选择服务器时,结合权重进行随机选择
  • RetryRule:按照 RoundRobinRule(轮询)策略获取服务,如果获取服务失败,就在指定时间内重试,获取可用的服务
  • BestAvailableRule:先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
  • ZoneAvoidanceRule:复合判断 Server 所在区域的性能和 Server 的可用性选择服务器

负载均衡算法

服务消费者从服务配置中心获取服务的地址列表后需要选取其中一台发起 RPC/HTTP 调用,这时需要用到具体的负载均衡算法

1. 轮询法

轮询法是指将请求按顺序轮流分配到后端服务器上,均衡地对待后端的每一台服务器,不关心服务器实际的连接数和当前系统负载

2. 加权轮询法

简单的轮询法并不考虑后端机器的性能和负载差异,加权轮询法可以很好地处理这一问题,它将按照顺序且按照权重分派给后端服务器,给性能高、负载低的机器配置较高的权重,让其处理较多的请求,给性能低、负载高的机器配置较低的权重,让其处理较少的请求

假设有 9 个客户端请求、3 台后端服务器,后端服务器 1 被赋予权值 1,后端服务器2被赋予值 2,后端服务器 3 赋值 3,这样一来,客户端请求 1、2、3 都被分派到服务器 3 处理,客户端请求 4、5 被分派到服务器 2 处,客户端请求 6 被分派到服务器 1 处理,客户端请求 7、8、9 被分派到服务器 3 处理,以此类推

3. 随机法

随机法也很简单,就是随机选择一台后端服务器进行请求处理,由于每次服务器被挑中的概率都一样,因此客户端的请求可以被均匀地分派到所有的后端服务器上

4. 加权随机法

加权随机法跟加权轮询法类似,根据后台服务器不同的配置和负载情况配置不同的权重,不同的是,它是按照权重来随机选取服务器的,而非顺序

比如希望抽到 A 的概率是 50%、抽到 B 和 C 的概率是 20%、抽到 D 的概率是 10%,一般来说,我们可以给各项附加一个权重,抽取的概率正比于这个权重,上述集合就成了 {A:5,B:2,C:2,D:1),扩展这个集合,使每一项出现的次数与其权重正相关,即 {A,A,A,A,A,B,BC,C,D},然后就可以用均匀随机算法从中选取了

5. 源地址哈希法

源地址哈希是根据获取客户端的 IP 地址,通过哈希函数计算得到一个数值,用该数值对服务器列表的大小进行取模运算,得到的结果便是客户端要访问服务器的序号。采用源地址哈希法进行负载均衡,当后端服务器列表不变时,同一个 IP 地址的客户端,每次都会映射到同一台后端服务器进行访问,但当后端服务器增加或者减少时,由于次数用于取模的服务器总数发生了变化,就导致同一哈希值的请求无法命中同一台服务器,节点数越高,命中率越低

6. 一致性哈希法

一致性哈希法解决了分布式环境下机器增加或者减少时简单的取模运算无法获取较高命中率的问题,通过一个一致性哈希环的数据结构实现映射,具体算法过程为:先构造一个长度为 2 的 32 次方的整数环(一致性哈希环),根据节点计算得出的哈希值将缓存服务器节点放置在这个哈希环上,然后在哈希环上顺时针查找距离这个哈希值最近的服务器节点,完成请求到服务器的映射

在这里插入图片描述

假设现在增加一台服务器 4,那么影响的就只有一个的请求,也就是说原本到服务器 1 的请求会被映射到服务器 4 上,虽然也会影响到整个集群,但是影响的只是加粗的那一段而已,这种影响要小得多。更重要的是,集群中缓存服务器节点越多,增加节点带来的影响越小

在这里插入图片描述


第一个 Ribbon 程序

创建名为 ribbon-provider 的项目,添加配置文件 application-01.properties 和 application-02.properties

# application-01.properties 配置文件内容
server.port=8080

# application-02.properties 配置文件内容
server.port=8081

开发 UserController 类

@RestController
@RequestMapping("user")
public class UserCon {

    @Resource
    private Environment environment;

    public String getPort() {
        return environment.getProperty("local.server.port");
    }

    @RequestMapping("getName")
    public String getUserName (){
        return "hello,ay" + "-" + getPort();
    }
}

通过使用不同的配置文件,可以启动多个 SpringBoot 应用,分别启动 ribbon-provider-8080 和 ribbon-provider-8081

创建名为 ribbon-consumer 的项目,pom.xml 添加依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

添加配置文件 application.yml

my-client:  #负载均衡配置
  ribbon:
    listOfServers: localhost:8080,localhost:8081  # 配置服务列表
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule  # 配置负载均衡算法 RoundRobinRule(轮询)

Ribbon 的配置格式是 <clientName>:ribbon:需要配置的属性<clientName> 是 Ribbon 的客户端名称,如果省略就配置所有客户端,配置的属性有以下几种:

  • NFLoadBalancerClassName:配置 ILoadBalancer 的实现类
  • NFLoadBalancerRuleClassName:配置 IRule 的实现类
  • NFLoadBalancerPingClassName:配置 IPing 的实现类
  • NIWSServerListClassName:配置 ServerList 的实现类
  • NIWSServerListFilterClassName:配置 ServerListFilter 的实现类

在 main 方法中添加如下代码:

@SpringBootApplication
public class RibbonConsumerApplication {

    public static void main(String[] args) throws Exception {
        SpringApplication.run(RibbonConsumerApplication.class, args);
        //获取客户端
        RestClient client = (RestClient) ClientFactory.getNamedClient("my-client");
        //调用UserController类的getUserName 方法
        HttpRequest request = HttpRequest.newBuilder().uri("/user/getName").build();
        //循环调用
        for(int i = 0; i<10; i++) {
            HttpResponse response = client.executeWithLoadBalancer(request);
            String result = response.getEntity(String.class);
            System.out.println(result);
        }
    }
}

启动 ribbon-consumer 项目,从打印信息中可以看出,服务通过轮询的方式调用


Ribbon 整合 Nacos & 自定义负载均衡策略

创建 ribbon-custom-consumer 的项目,添加配置类

@Configuration
public class RibbonConfig {

    @Bean
    public IRule ribbonRule() {
        // ribbon默认使用的是zoneAvoidanceRule规则,这里修改为自定义方式
        return new MyRule();
    }
}

创建 MyRule 类,用来自定义负载均衡规则

/**
 * 负载规则:始终返回第一个服务
 */
public class MyRule extends AbstractLoadBalancerRule {

    @Override
    public void initWithNiwsConfig(IClientConfig iClientConfig) {

    }

    @Override
    public Server choose(Object o) {
        ILoadBalancer loadBalancer = getLoadBalancer();
        // 获取所有的服务
        List<Server> servers = loadBalancer.getAllServers();
        // 始终返回第一个服务
        return servers.get(0);
    }
}

自定义指定 Ribbon 客户端的配置

/**
 * 使用 RibbonClient 为特定 name 的 Ribbon Client 自定义配置
 * 使用 @RibbonClient 的 configuration 属性指定 Ribbon 的配置类
 */
@Configuration
@RibbonClient(name = "service-provider", configuration = RibbonConfig.class)
public class TestConfig {

}

在 application.properties 配置文件中添加如下配置

server.port=7089
spring.application.name=service-custom
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848

在启动类中添加 @EnableDiscoveryClient 注解

@EnableDiscoveryClient
@SpringBootApplication
public class RibbonCustomApplication {

    public static void main(String[] args) {
        SpringApplication.run(RibbonCustomApplication.class, args);
    }
}

创建 TesController类,具体代码如下

@RestController
@RequestMapping("test")
public class TestController {

    @Resource
    private LoadBalancerClient loadBalancerClient;

    @RequestMapping("getUserName")
    public String getUserName() {
        for (int i = 0; i < 20; i++) {
            //获取service-provider服务
            ServiceInstance serviceInstance = loadBalancerClient.choose("service-provider");
            //打印当前选择的是哪个节点
            System.out.println(serviceInstance.getServiceId() + serviceInstance.getHost() + "; " + serviceInstance.getPort());
        }
        return "hello,ay";
    }
}

在上述步骤中,我们创建了 ribbon-custom-consumer 项目,并定义了负载均衡规则 MyRule,服务启动后注册到 Nacos 中,这样一来,在调用 getUserName 方法时,会从 Nacos 中获取已注册的服务提供者列表,并按照我们自定义的负载规则进行调用


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

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

相关文章

useCallBack

React.memo 保证了只有props发生变化时&#xff0c;该组件才会重新渲染 &#xff08;当然组件内部的state 和 context 变化也会导致组件重新渲染&#xff09;&#xff0c;但咱们只要将咱们的子组件包裹&#xff0c;便可以保证Child组件在props不变的情况下&#xff0c;不会重新…

一篇聊聊Mybatis插件开发

Mybatis的插件&#xff0c;主要用于在执行sql前后&#xff0c;对sql进行封装加工&#xff0c;或者在sql执行后&#xff0c;对数据进行加工处理。常用于一些公共数据操作处理&#xff0c;例如&#xff1a; 分页插件&#xff0c;在执行sql查询前增加分页参数多租户系统中&#x…

[winerror 5] 拒绝访问。: ‘..\\data‘解决方案

使用Jupyter Notebook学习深度学习时出现错误如下&#xff1a;[winerror 5] 拒绝访问。: ‘…\data’ 解决方法&#xff1a; 打开anaconda3找到对应环境的python.exe 点开属性&#xff0c;点安全&#xff0c;选择如下&#xff1a; 点编辑&#xff0c;选择User&#xff0c;勾…

k8s集群-3 pod 管理

pod是可以创建和管理k 8 s 计算的最小可部署单元&#xff0c;一个pod 代表着集群中运行的一个进程&#xff0c;每个pod 都有一个唯一的ip 一个pod 类似一个豌豆荚&#xff0c;包含一个或者多个容器&#xff0c;多个容器间共享IPC Network和UTC namespace pod 包裹了容器 下载…

Unity之NetCode多人网络游戏联机对战教程(2)--简单实现联机

文章目录 1.添加基本组件2.创建NetworkManager组件3.创建Player4.创建地面5.创建GameManager6.编译运行7. 测试联机后话 1.添加基本组件 NetworkManagerPlayerScene 2.创建NetworkManager组件 创建一个空物体&#xff0c;命名为NetworkManager 选择刚刚创建的NetworkManager…

Android Jetpack组件架构:Lifecycle的使用 和 原理

Android Jetpack组件架构&#xff1a;Lifecycle的使用和原理 导言 作为Jetpack中关于生命周期管理的核心组件&#xff0c;Lifecycle组件是其他比如LiveDate和ViewModel等组件的基础&#xff0c;本篇文章主要就将介绍关于Lifecycle的使用和它的运作原理。 Lifecycle的使用 我…

【05】FISCOBCOS中的节点配置

官方文档https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/manual/configuration.html 配置黑名单列表 基于防作恶考虑&#xff0c;FISCO BCOS允许节点将不受信任的节点加入到黑名单列表&#xff0c;并拒绝与这些黑名单节点建立连接&#xff0c;通过[certif…

MySQL数据库的索引和事务

目录 一、索引 1.1Mysql索引 1.2索引的作用 1.3 创建索引的依据 1.4 普通索引 修改表方式创建索引 删除索引 1.5 唯一索引 修改表方式创建 删除索引 1.6 主键索引 修改表方式创建 1.7 组合索引 1.8 全文索引 1.9查看索引 二、事务 2.1事务概念 2.2事务的ACID特…

Java 核心技术卷 I —— 第2章 Java 编程环境

文章目录 2.1 安装 Java 开发工具包&#xff08;*&#xff09;2.2 使用命令行工具2.3 使用集成开发环境&#xff08;*&#xff09;2.4 JShell 2.1 安装 Java 开发工具包&#xff08;*&#xff09; 2.2 使用命令行工具 ​ 打开终端窗口&#xff0c;进入 Java 的 bin 目录&…

Linux Mint大动作:全新设计Software Manager,大幅提升用户体验

Clem Lefebvre在Linux Mint博客上宣布&#xff0c;团队已经着手开发新版本。新版本中将版本全新设计的Software Manager&#xff0c;带来更卓越更现代化的界面大幅提升用户体验。 全新的Software Manager会迎来大量变动&#xff0c;包括的内容包括&#xff1a; 用户界面看起来…

别再乱写git commit了

B站|公众号&#xff1a;啥都会一点的研究生 写在前面 在很长的一段时间中&#xff0c;使用git commit都是随心所欲&#xff0c;log肥肠简洁&#xff0c;随着代码的迭代&#xff0c;当时有多偷懒&#xff0c;返过头查看git日志就有多懊悔&#xff0c;就和写代码不写doc string…

Super Marker插件——标记资源,提高效率

插件介绍&#xff1a; 这是一款可以给资源添加颜色或图标标记&#x1f4cc;的插件&#xff0c;当资源文件比较多的时候&#xff0c;颜色标记可以让你一眼定位到要使用的资源&#xff0c;提高开发效率。 插件地址&#xff1a; Cocos商店&#xff1a;https://store.cocos.com/a…

工业蒸汽量预测(速通一)

工业蒸汽量预测&#xff08;一&#xff09; 赛题理解1、评估指标2、赛题模型3、解题思路 理论知识1、变量识别2、变量分析3、缺失值处理4、异常值处理5、变量转换6、新变量生成 数据探索1、导包2、读取数据3、查看数据4、可视化数据分布4.1箱型图4.2获取异常数据并画图4.3直方图…

【RabbitMQ实战】04 RabbitMQ的基本概念:Exchange,Queue,Channel等

一、简介 Message Queue的需求由来已久&#xff0c;80年代最早在金融交易中&#xff0c;高盛等公司采用Teknekron公司的产品&#xff0c;当时的Message queuing软件叫做&#xff1a;the information bus&#xff08;TIB&#xff09;。 TIB被电信和通讯公司采用&#xff0c;路透…

某度sign参数逆向

文章目录 前文分析完整代码结尾 前文 本文章中所有内容仅供学习交流&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff0c;若有侵权&#xff0c;请联系我立即删除&#xff01; 分析 经过我们几次抓包&#xff0c;测试&#xf…

单片机IAP固件升级分几步?(Qt上位机)

更新 0924&#xff0c;一些潜在的bug解决方案 前言 这周一直想做一个IAP固件升级的上位机&#xff0c;然后把升级流程全都搞懂。 我用的单片机型号是STM32F103VET6&#xff0c;FLASH容量是512K&#xff0c;FLASH单页是2K。 有纰漏请指出&#xff0c;转载请说明。 学习交流…

Rabbit消息的可靠性

Confirm模式简介 消息的confirm确认机制&#xff0c;是指生产者投递消息后&#xff0c;到达了消息服务器Broker里面的exchange交换机&#xff0c;则会给生产者一个应答&#xff0c;生产者接收到应答&#xff0c;用来确定这条消息是否正常的发送到Broker的exchange中&#xff…

黑马JVM总结(二十二)

&#xff08;1&#xff09;类的结构-field 成员变量信息 类字节码里的一些简单表示&#xff1a; &#xff08;2&#xff09;类文件结构-method-init &#xff08;3&#xff09;类文件结构-method-main &#xff08;4&#xff09;类文件结构-附加属性

Java基础(六)

前言&#xff1a;本篇博客学习Junit单元测试框架的使用以及常见的注解。 目录 单元测试 Junit单元测试框架 常见注解 单元测试 什么是单元测试&#xff1f; 针对最小的功能单元&#xff08;方法&#xff09;&#xff0c;编写测试代码对其进行正确性测试。 Junit单元测试框…

十六、MySql的MVCC机制CONNECT(收官!)

文章目录 一、数据库并发的场景有三种&#xff1a;二、读-写&#xff08;一&#xff09;3个记录隐藏列字段&#xff08;二&#xff09;undo 日志&#xff08;三&#xff09;模拟 MVCC&#xff08;四&#xff09;一些思考&#xff08;五&#xff09;Read View 一、数据库并发的场…