SpringCloud之 LoadBalancer负载均衡

news/2024/5/8 8:49:51/文章来源:https://blog.csdn.net/qq15035899256/article/details/129350492

文章目录

  • LoadBalancer 负载均衡
    • 一、@LoadBalanced 负载均衡
    • 二、自定义负载均衡
    • 三、OpenFeign 实现负载均衡
      • ①添加依赖
      • ②启动类添加 @EnableFeignClients
      • ③创建客户端接口 UserClient
      • ④service业务中调用客户端接口


提示:以下是本篇文章正文内容,SpringCloud 系列学习将会持续更新

在这里插入图片描述

LoadBalancer 负载均衡

前面我们讲解了如何对服务进行拆分、如何通过 Eureka 服务器进行服务注册与发现,那么现在我们来看看,它的负载均衡到底是如何实现的,实际上之前演示的负载均衡是依靠 LoadBalancer 实现的。

在2020年前的 SpringCloud 版本是采用 Ribbon 作为负载均衡实现,但是2020年的版本之后SpringCloud 把 Ribbon 移除了,进而用自己编写的 LoadBalancer 替代。

那么,负载均衡是如何进行的呢?

一、@LoadBalanced 负载均衡

我们之前注册 RestTemplate 时,就用 @LoadBalanced 注解进行了修饰:

@Configuration
public class BeanConfiguration {@Bean@LoadBalanced // 负载均衡public RestTemplate getRestTemplate() {return new RestTemplate();}
}
// User user = this.template.getForObject("http://userservice/user/"+uid, User.class);

剖析源码:
实际上,在添加 @LoadBalanced 注解之后,会启用LoadBalancerInterceptor拦截器对我们发起的服务调用请求进行拦截(只针对我们发起的请求)。

它实现ClientHttpRequestInterceptor接口:

@FunctionalInterface
public interface ClientHttpRequestInterceptor {ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException;
}

LoadBalancerInterceptor类对 intercept()方法 的实现:

public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException {URI originalUri = request.getURI();String serviceName = originalUri.getHost();Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);return (ClientHttpResponse)this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution));
}

我们可以打个断点看看实际是怎么在执行的,可以看到:
在这里插入图片描述
服务端会在发起请求时执行这些拦截器。它们会去找 Eureka 获取真正需要访问的主机名称

我们来看看BlockingLoadBalancerClient类对 loadBalancer.execute()方法 的具体实现:

//从上面给进来了服务的名称和具体的请求实体
public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {String hint = this.getHint(serviceId);LoadBalancerRequestAdapter<T, DefaultRequestContext> lbRequest = new LoadBalancerRequestAdapter(request, new DefaultRequestContext(request, hint));Set<LoadBalancerLifecycle> supportedLifecycleProcessors = this.getSupportedLifecycleProcessors(serviceId);supportedLifecycleProcessors.forEach((lifecycle) -> {lifecycle.onStart(lbRequest);});//可以看到在这里会调用choose方法自动获取对应的服务实例信息ServiceInstance serviceInstance = this.choose(serviceId, lbRequest);if (serviceInstance == null) {supportedLifecycleProcessors.forEach((lifecycle) -> {lifecycle.onComplete(new CompletionContext(Status.DISCARD, lbRequest, new EmptyResponse()));});//没有发现任何此服务的实例就抛异常(之前的测试中可能已经遇到了)throw new IllegalStateException("No instances available for " + serviceId);} else {//成功获取到对应服务的实例,这时就可以发起HTTP请求获取信息了return this.execute(serviceId, serviceInstance, lbRequest);}
}

所以,实际上在进行负载均衡的时候,会向 Eureka 发起请求,选择一个可用的对应服务,然后会返回此服务的主机地址等信息:
在这里插入图片描述

回到目录…

二、自定义负载均衡

LoadBalancer 默认提供了两种负载均衡策略:

  • RandomLoadBalancer - 随机分配策略
  • RoundRobinLoadBalancer - (默认)轮询分配策略

现在我们希望修改默认的负载均衡策略,可以进行指定,比如我们现在希望用户服务采用随机分配策略

①我们需要先创建随机分配策略的配置类(不用加@Configuration):

public class LoadBalancerConfig {//将官方提供的 RandomLoadBalancer 注册为Bean@Beanpublic ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory){String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);}
}

②接着我们需要为对应的服务指定负载均衡策略,直接使用注解即可:

@Configuration
// 指定只要是 userservice 服务,都会使用我们指定的策略 LoadBalancerConfig
@LoadBalancerClient(value = "userservice", configuration = LoadBalancerConfig.class)
public class BeanConfiguration {@Bean@LoadBalanced // 负载均衡public RestTemplate getRestTemplate() {return new RestTemplate();}
}

接着我们在BlockingLoadBalancerClient中添加断点,观察是否采用我们指定的策略进行请求:
在这里插入图片描述
在这里插入图片描述
发现访问 userservice 服务的策略已经更改为我们指定的策略了。

回到目录…

三、OpenFeign 实现负载均衡

官方文档:https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/

Feign 和 RestTemplate 一样,也是 HTTP 客户端请求工具,但是它的使用方式更加便捷。
OpenFeign 默认的负载均衡策略是轮询调用

①添加依赖

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

②启动类添加 @EnableFeignClients

@SpringBootApplication
@EnableFeignClients
public class BorrowApplication {public static void main(String[] args) {SpringApplication.run(BorrowApplication.class, args);}
}

那么现在我们需要调用其他微服务提供的接口,该怎么做呢?

③创建客户端接口 UserClient

我们的客户端接口需要用 @FeignClient 注解来指定向哪个微服务发送 HTTP 请求。

@FeignClient("userservice")   //声明为 userservice 服务的 HTTP 请求客户端
public interface UserClient {
}

我们之前的远程调用:

RestTemplate template = new RestTemplate();
User user = template.getForObject("http://userservice/user/"+uid, User.class);

现在直接在客户端接口中写入控制层的方法:

@FeignClient("userservice")
public interface UserClient {//路径保证和其他微服务提供的一致即可@RequestMapping("/user/{uid}")User getUserById(@PathVariable("uid") int uid);  //参数和返回值也保持一致
}

④service业务中调用客户端接口

我们直接注入使用(有 Mybatis 那味了):

@Service
public class BorrowServiceImpl implements BorrowService {@Resourceprivate BorrowMapper borrowMapper;@Resourceprivate UserClient userClient;@Resourceprivate BookClient bookClient;@Overridepublic UserBorrowView getBorrowViewByUid(int uid) {// 现在拿到借阅关联信息了,怎么调用其他服务获取信息呢?List<Borrow> borrowList = borrowMapper.getBorrowsByUid(uid);// 直接调用客户端接口的方法User user = userClient.findUserById(uid);List<Book> bookList = borrowList.stream().map(b -> bookClient.findBookById(b.getBid())).collect(Collectors.toList());return new UserBorrowView(user, bookList);}
}

继续访问进行测试:
在这里插入图片描述
OK,正常。

当然,Feign 也有很多的其他配置选项,这里就不多做介绍了,详细请查阅官方文档。

回到目录…


总结:
提示:这里对文章进行总结:
本文是对SpringCloud的学习, 了解了LoadBalancer 负载均衡策略的内部流程,学习了如何自定义负载均衡策略,并且学习了使用OpenFeign实现负载均衡。之后的学习内容将持续更新!!!

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

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

某游戏app sig参数分析

今天要分析的app 叫 dGFwdGFwIDIuMjA= (base64 解码),来一起学习下。 找个视频接口,上来先抓个包,没错今天就是要分析下这个sig参数。 这个app 在高版本上有加固壳,并且还有frida检测(ps:遇到困难不会放弃,以后慢慢研究),这里只是研究sig参数,所以采用低版本了。 把…

pycharm的License Certificate使用方法

1 在邮箱获得License Certificate的激活码之后&#xff0c;打开pycharm&#xff0c;选择HELP 在HELP菜单里选择Register 2 输入username or email和密码进行登录 3 登录之后&#xff0c;根据提示&#xff08;如果有的话&#xff09;&#xff0c;进入官网如下页面&#xff0c…

2023年软考中级电子商务设计师考什么?

首先&#xff0c;电子商务设计师属于软考中级&#xff0c;因此难度也不是特别大。但并不是说就完全没有难度&#xff0c;难度还是有的&#xff0c;像上午题一般把基本知识点掌握了&#xff0c;是没什么问题的&#xff0c;重点就在于下午题会比较难。 接下来我们来剖析一下考试…

黑马程序员SSM框架教程之学习笔记1

P44-SpringMVC入门案例 1.在pom.xml中导入坐标springMVC与servlet 2.创建一个SpringMVC控制器类 3.创建springMVC配置文件springMvcCponfig 4.定义一个servlet容器启动配置类&#xff0c;在里面加载spring的配置 5.在pom.xml文件中配置tomcat插件 运行结果显示 P45-springMVC入…

【自然语言处理】【大模型】大语言模型BLOOM推理工具测试

相关博客 【自然语言处理】【大模型】大语言模型BLOOM推理工具测试 【自然语言处理】【大模型】GLM-130B&#xff1a;一个开源双语预训练语言模型 【自然语言处理】【大模型】用于大型Transformer的8-bit矩阵乘法介绍 【自然语言处理】【大模型】BLOOM&#xff1a;一个176B参数…

2023-03-05:ffmpeg推送本地视频至lal流媒体服务器(以RTMP为例),请用go语言编写。

2023-03-05&#xff1a;ffmpeg推送本地视频至lal流媒体服务器&#xff08;以RTMP为例&#xff09;&#xff0c;请用go语言编写。 答案2023-03-05&#xff1a; 使用 github.com/moonfdd/ffmpeg-go 库。 先启动lal流媒体服务器软件&#xff0c;然后再执行命令&#xff1a; go…

QT配置安卓环境(保姆级教程)

目录 下载环境资源 JDK1.8 NDK SDK ​安装QT 配置环境 下载环境资源 JDK1.8 介绍JDK是Java开发的核心工具&#xff0c;为Java开发者提供了一套完整的开发环境&#xff0c;包括开发工具、类库和API等&#xff0c;使得开发者可以高效地编写、测试和运行Java应用程序。 下载…

Java分布式解决方案(三)

文章目录&#x1f525;MySQL事务-MySQL中锁的分类&#x1f525;MySQL事务-MySQL中的死锁问题&#x1f525;MySQL事务-MySQL中锁的分类 MySQL中锁的分类 从本质上讲&#xff0c;锁是一种协调多个进程或多个线程对某一资源的访问的机制&#xff0c;MySQL使用锁和MVCC机制实现了…

【博学谷学习记录】超强总结,用心分享|狂野大数据课程【Spark SQL函数定义】的总结分析

5.1 如何使用窗口函数 回顾: 窗口函数格式:分析函数 over(partition by xxx order by xxx [asc|desc] [rows between xxx and xxx])学习的相关分析函数有那些? 第一类: row_number() rank() dense_rank() ntile()第二类: 和聚合函数组合使用 sum() avg() max() min() count…

sklearn使用入门

文章目录1.机器学习1.1 机器学习简介1.2 有监督学习(supervised learning)1.3 无监督学习(unsupervised learning)1.4 半监督学习2. 机器学习工具SKlearn2.1 sklearn2.2 sklearn常用模块2.2.1 分类2.2.2 回归2.2.3 聚类2.2.4 降维2.2.5 模型选择2.2.6 数据预处理2.3 sklearn使用…

ChatGPT vs Bard 背后的技术对比分析和未来发展趋势

ChatGPT vs Bard 背后的技术对比分析和未来发展趋势 目录 ChatGPT vs Bard 背后的技术对比分析和未来发展趋势

SQLI-Labs(3)8-14关【布尔盲注和时间盲注】

目录 第八关 第九关&#xff1a; 第十关 第十一关 第十二关 第十三关 第十四关 第八关 我们用测试语句来测试是否为注入点 从上图中得知存在注入点&#xff0c;那么接下来就是爆列 一共有三列&#xff0c;接下来用union select 和报错注入都试一下发现没有回显点&…

嵌入式安防监控项目——前期知识复习

目录 一、概述 二、C语言 三、数据结构 四、IO进程 五、网络 六、ARM体系结构和接口技术 七、系统移植 八、内核驱动 一、概述 我再报班之前学过51和32&#xff0c;不过都是自学的。报班开始先从应用层入手的&#xff0c;C语言和数据结构。只要是个IT专业的大学这都是必…

cadence专题【1】--多引脚IC如何创建orcad原理图库

cadense下载说明新建工程一、采用传统方式创建1、新建库文件2、放置pin array3、修改管脚信息二、采用电子表格方式创建1、新建库文件2、Ctrlc、Ctrlvcadense下载说明 cadence是目前最流行的EDA&#xff0c;下载装机全交给阿狸狗即可。 浏览器搜索cadence吴川斌或点击链接: ht…

既然有MySQL了,为什么还要有Redis?

目录专栏导读一、同样是缓存&#xff0c;用map不行吗&#xff1f;二、Redis为什么是单线程的&#xff1f;三、Redis真的是单线程的吗&#xff1f;四、Redis优缺点1、优点2、缺点五、Redis常见业务场景六、Redis常见数据类型1、String2、List3、Hash4、Set5、Zset6、BitMap7、Bi…

GDScript 导出变量 (Godot4.0)

概述 导出变量的功能在3.x版本中也是有的&#xff0c;但是4.0版本对其进行了语法上的改进。 导出变量在日常的游戏制作中提供节点的自定义参数化调节功能时非常有用&#xff0c;除此之外还用于自定义资源。 本文是&#xff08;Bilibili巽星石&#xff09;在4.0官方文档《GDScr…

Java学习笔记 --- jQuery

一、jQuery介绍 jQuery&#xff0c;顾名思义&#xff0c;也就是JavaScript和查询&#xff08;Query&#xff09;&#xff0c;它就是辅助JavaScript开发的js类库。它的核心思想是write less&#xff0c;do more&#xff08;写得更少&#xff0c;做得更多&#xff09;&#xff0c…

C语言实现扫雷【详细讲解+全部源码】

扫雷的实现1. 配置运行环境2. 扫雷游戏的初步实现2.1 建立扫雷分布模块2.2 创建名为board的二维数组并进行棋盘初始化2.3 打印棋盘3. 接下来该讨论的事情3.1 布置雷3.2 排查雷3.3 统计坐标周围有几个雷4. 完整扫雷游戏的实现4.1 game.h4.2 game.c4.3 扫雷.c1. 配置运行环境 本游…

信息安全与数学基础-笔记-③一次同余方程

知识目录一次同余方程的解中国剩余定理中国剩余定理的应用一次同余方程的解 本文只研究一次同余方程的解。 f(x) 三 0 (mod m)&#xff0c; 若有一个s能够满足该式子&#xff0c;那么该数字就是该式子的解&#xff0c; 在同余方程式中的解一般写成&#xff1a;x三s (mod m) 同…

04_Apache Pulsar的可视化监控管理、Apache Pulsar的可视化监控部署

1.4.Apache Pulsar的可视化监控管理 1.4.1.Apache Pulsar的可视化监控部署 1.4.Apache Pulsar的可视化监控管理 1.4.1.Apache Pulsar的可视化监控部署 第一步&#xff1a;下载Pulsar-Manager https://archive.apache.org/dist/pulsar/pulsar-manager/pulsar-manager-0.2.0/…