Spring Cloud之负载均衡之LoadBalance

目录

负载均衡

问题

步骤

现象 

什么是负载均衡?

负载均衡的一些实现

服务端负载均衡

客户端负载均衡

使用Spring Cloud LoadBalance实现负载均衡

负载均衡策略

​编辑 ​编辑LoadBalancer原理

服务部署

准备环境和数据

服务构建打包

启动服务

上传Jar包到云服务器

启动服务

远程调用访问 


负载均衡

问题

上面是我们之前的代码,是根据应用名称获取了服务实例列表,并从列表中选择了一个服务实例。

那如果一个服务对应多个实例呢?流量是否可以合理的分配到多个实例呢?

我们再启动两个product-service示例。

步骤

打开View->Tool Windows->Services

选中ProductServiceApplication,然后右键,选择Copy Configuration

然后改名,并点击Modify options

然后点击Add VM options

然后添加-Dserver.port=9091,然后Apply,OK

然后再重复上述步骤,再添加一个服务实例。

现象 

启动上述所有实例后,可以在Eureka网站页面看到:

此时多次访问"http://127.0.0.1:8080/order/1",然后查看IDEA上的日志,可以看到,我们刚刚的多次访问,都访问到了同一台机器上,即第一个注册到Eureka的服务实例端口号为9092的机器。

这肯定不是我们想要的结果,我们启动多个服务实例,是希望可以分担其它机器的负荷,那么如何实现呢?

我们可以修改一下之前的order-service中的OrderService代码,把只请求服务列表第一台机器修改为轮询请求服务列表中的机器。

修改后的order-service中的OrderService代码如下:

package order.service;import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import order.mapper.OrderMapper;
import order.model.OrderInfo;
import order.model.ProductInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;@Slf4j
@Service
public class OrderService {@Autowiredprivate OrderMapper orderMapper;@Autowiredprivate RestTemplate restTemplate;@Autowiredprivate DiscoveryClient discoveryClient;//计数器private AtomicInteger count = new AtomicInteger(1);private List<ServiceInstance> instances;@PostConstructpublic void init(){//从Eureka中获取服务列表instances = discoveryClient.getInstances("product-service");}public OrderInfo selectOrderById(Integer orderId){OrderInfo orderInfo = orderMapper.selectOrderById(orderId);//计算轮流的实例idnexint index= count.getAndIncrement() % instances.size();//获取实例String uri = instances.get(index).getUri().toString();//拼接urlString url = uri+"/product/"+orderInfo.getProductId();log.info("远程调用url:{}", url);ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);orderInfo.setProductInfo(productInfo);return orderInfo;}}

重启order-service,再次多次访问"127.0.0.1:8080/order/1",可以看到每个服务实例都有被请求到:

通过⽇志可以看到, 请求被均衡的分配在了不同的实例上, 这就是负载均衡.

什么是负载均衡?

负载均衡(Load Balance,简称 LB) , 是⾼并发, ⾼可⽤系统必不可少的关键组件.
当服务流量增⼤时, 通常会采⽤增加机器的⽅式进⾏扩容, 负载均衡就是⽤来在多个机器或者其他资源中, 按照⼀定的规则合理分配负载.

负载均衡的一些实现

上⾯的例⼦中, 我们只是简单的对实例进⾏了轮询, 但真实的业务场景会更加复杂. ⽐如根据机器的配置进⾏负载分配, 配置⾼的分配的流量⾼, 配置低的分配流量低等.

服务多机部署时, 开发⼈员都需要考虑负载均衡的实现, 所以也出现了⼀些负载均衡器, 来帮助我们实现负载均衡.

负载均衡分为服务端负载均衡和客⼾端负载均衡.

服务端负载均衡

在服务端进⾏负载均衡的算法分配.
⽐较有名的服务端负载均衡器是Nginx. 请求先到达Nginx负载均衡器, 然后通过负载均衡算法, 在多个服务器之间选择⼀个进⾏访问.

客户端负载均衡

在客⼾端进⾏负载均衡的算法分配.

把负载均衡的功能以库的⽅式集成到客⼾端, ⽽不再是由⼀台指定的负载均衡设备集中提供.
⽐如Spring Cloud的Ribbon, 请求发送到客⼾端, 客⼾端从注册中⼼(⽐如Eureka)获取服务列表, 在发送请求前通过负载均衡算法选择⼀个服务器,然后进⾏访问.
Ribbon是Spring Cloud早期的默认实现, 由于不维护了, 所以最新版本的Spring Cloud负载均衡集成的是Spring Cloud LoadBalancer(Spring Cloud官⽅维护)。

客⼾端负载均衡和服务端负载均衡最⼤的区别在于服务清单所存储的位置。

Spring Cloud LoadBalance

SpringCloud 从 2020.0.1 版本开始, 移除了Ribbon 组件,使⽤Spring Cloud LoadBalancer 组件来代替 Ribbon 实现客⼾端负载均衡。

使用Spring Cloud LoadBalance实现负载均衡

1. 给 RestTemplate 这个Bean添加 @LoadBalanced 注解就可以

package order.config;import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;@Configuration
public class BeanConfig {@Bean@LoadBalancedpublic RestTemplate restTemplate(){return new RestTemplate();}
}

2.修改后的order-service中的OrderService代码如下:

修改IP为服务端名称。

package order.service;import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import order.mapper.OrderMapper;
import order.model.OrderInfo;
import order.model.ProductInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;@Slf4j
@Service
public class OrderService {@Autowiredprivate OrderMapper orderMapper;@Autowiredprivate RestTemplate restTemplate;public OrderInfo selectOrderById(Integer orderId){OrderInfo orderInfo = orderMapper.selectOrderById(orderId);String url = "http://product-service/product/"+orderInfo.getProductId();log.info("远程调用url:{}", url);ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);orderInfo.setProductInfo(productInfo);return orderInfo;}
}

此时再次多次访问"127.0.0.1:8080/order/1",可以看到每个服务实例都有被请求到,且比例差不多:

负载均衡策略

负载均衡策略是⼀种思想, ⽆论是哪种负载均衡器, 它们的负载均衡策略都是相似的. Spring Cloud
LoadBalancer 仅⽀持两种负载均衡策略: 轮询策略 和 随机策略。

1. 轮询(Round Robin): 轮询策略是指服务器轮流处理⽤⼾的请求. 这是⼀种实现最简单, 也最常⽤的策略. ⽣活中也有类似的场景, ⽐如学校轮流值⽇, 或者轮流打扫卫⽣.
2. 随机选择(Random): 随机选择策略是指随机选择⼀个后端服务器来处理新的请求.

官方介绍

翻译:

Spring Cloud提供了自己的客户端负载均衡器抽象和实现。对于负载平衡机制,添加了ReactiveLoadBalancer接口,并为其提供了基于轮转和随机的实现。为了让实例从反应式ServiceInstanceListSupplier中进行选择,使用了该接口。目前,我们支持ServiceInstanceListSupplier的基于服务发现的实现,该实现使用类路径中可用的发现客户端从服务发现中检索可用实例。通过将Spring.Cloud.LoadBalancer.enabled的值设置为false,可以禁用Spring Cloud LoadBalancer。

1. 定义随机算法对象, 通过 @Bean 将其加载到 Spring 容器中
此处使⽤Spring Cloud LoadBalancer提供的 RandomLoadBalancer

package order.config;import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.core.RandomLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;public class CustomLoadBalancerConfiguration {@BeanReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,LoadBalancerClientFactory loadBalancerClientFactory) {String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class),name);}
}

注意: 该类需要满⾜:
1. 不⽤ @Configuration 注释
2. 在组件扫描范围内 

2. 使⽤ @LoadBalancerClient 或者 @LoadBalancerClients 注解

在 RestTemplate 配置类上⽅, 使⽤ @LoadBalancerClient 或 @LoadBalancerClients 注解, 可以对不同的服务提供⽅配置不同的客⼾端负载均衡算法策略.
由于我们只有⼀个客户端服务提供者, 所以使⽤@LoadBalancerClient。

package order.config;import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;@LoadBalancerClient(name = "product-service", configuration = CustomLoadBalancerConfiguration.class)
@Configuration
public class BeanConfig {@Bean@LoadBalancedpublic RestTemplate restTemplate(){return new RestTemplate();}
}

@LoadBalancerClient 注解说明
1. name: 该负载均衡策略对哪个服务⽣效(服务提供⽅)
2. configuration : 该负载均衡策略 ⽤哪个负载均衡策略实现. 

此时再次多次访问"127.0.0.1:8080/order/1",可以看到每个服务实例都有被请求到,且比例随机:

 LoadBalancer原理

LoadBalancer 的实现, 主要是 LoadBalancerInterceptor , 这个类会对 RestTemplate 的请
求进⾏拦截, 然后从Eureka根据服务id获取服务列表,随后利⽤负载均衡算法得到真实的服务地址信息,替换服务id。

我们来看看源码实现:

可以看到这⾥的intercept⽅法, 拦截了⽤⼾的HttpRequest请求,然后做了⼏件事:

1. request.getURI() 从请求中获取uri, 也就是 http://product-service
2. service/product/1001 originalUri.getHost() 从uri中获取路径的主机名, 也就是服务id, product-service
3. loadBalancer.execute 根据服务id, 进⾏负载均衡, 并处理请求 

根据serviceId,和负载均衡策略, 选择处理的服务: 

 根据serviceId,和负载均衡策略, 选择处理的服务:

服务部署
准备环境和数据

安装好JDK17和MySQL,并在MySQL中建表且存放好数据信息。

修改配置文件中的数据库密码。

服务构建打包

采⽤Maven打包, 需要对3个服务分别打包:
eureka-server, order-service, product-service

启动服务
上传Jar包到云服务器

第一次上传需要安装 lrzsz

Centos:

yum install lrzsz

Ubantu:

apt install lrzsz 

直接拖动文件到xshell窗口,上传成功。

启动服务

#后台启动eureka-server, 并设置输出⽇志到logs/eureka.log
nohup java -jar eureka-server.jar >logs/eureka.log &


#后台启动order-service, 并设置输出⽇志到logs/order.log
nohup java -jar order-service.jar >logs/order.log &


#后台启动product-service, 并设置输出⽇志到logs/order.log
nohup java -jar product-service.jar >logs/product-9090.log &

再多启动两台product-service实例

#启动实例, 指定端⼝号为9091
nohup java -jar product-service.jar --server.port=9091 >logs/product-9091.log &


#启动实例, 指定端⼝号为9092
nohup java -jar product-service.jar --server.port=9092 >logs/product-9092.log & 

远程调用访问 

可以看到,能够正常访问并响应。

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

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

相关文章

量化研究--小果聚宽交易系统上线高速服务器,提供源代码

文章链接量化研究--小果聚宽交易系统上线高速服务器&#xff0c;提供源代码https://mp.weixin.qq.com/s/HecSeAvmaCyVCsPhvxA0xg 今天大家反应以前的服务器比较慢&#xff0c;与200多人在使用这个系统&#xff0c;反应比较慢&#xff0c;实时数据请求服务器&#xff0c;服务器还…

蓝桥杯python组备考2(b站课程笔记)超详细

语法进阶 一、列表推导式 想讲解一下示例4到示例7的代码&#xff1a; 4、循环n次生成n个零放进列表中&#xff0c;其实也就是相当于[0]*n&#xff08;列表乘法&#xff0c;将原来的列表循环n次产生一个新的列表&#xff09;&#xff0c;接着在循环n次产生n个这样的列表&#x…

【大模型LLM第十四篇】Agent学习之anthropic-quickstarts Agent

前言 对于anthropic api的快速使用&#xff0c;在github上有几个example Customer Support Agent&#xff1a;由 Claude 提供支持的客户支持代理。该项目演示了如何利用 Claude 的自然语言理解和生成功能来创建可访问知识库的 AI 辅助客户支持系统。Financial Data Analyst &…

用DrissionPage升级网易云音乐爬虫:更稳定高效地获取歌单音乐(附原码)

一、传统爬虫的痛点分析 原代码使用requests re的方案存在以下局限性&#xff1a; 动态内容缺失&#xff1a;无法获取JavaScript渲染后的页面内容 维护成本高&#xff1a;网页结构变化需频繁调整正则表达式 反爬易触发&#xff1a;简单请求头伪造容易被识别 资源消耗大&am…

2025年渗透测试面试题总结- PingCAP安全工程师(题目+回答)

网络安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 PingCAP安全工程师 一、SQL注入判断数据库类型技术分析 1. 常规判断方法 2. 盲注场景下的判断 3. 补…

【加密社】如何创建自己的币圈工具站

需要准备的工作 1.域名 2.服务器 周末的时候主要弄了快讯这方面的代码 我这里用的是星球日报的api&#xff0c;也可以订阅他们的rss&#xff0c;这部分在github上是开源的 https://github.com/ODAILY 我这里用的是WordPressonenav主题&#xff0c;然后用小工具在主页展示&am…

Oracle归档配置及检查

配置归档位置到 USE_DB_RECOVERY_FILE_DEST&#xff0c;并设置存储大小 startup mount; !mkdir /db/archivelog ALTER SYSTEM SET db_recovery_file_dest_size100G SCOPEBOTH; ALTER SYSTEM SET db_recovery_file_dest/db/archivelog SCOPEBOTH; ALTER SYSTEM SET log_archive…

Apache Hive:基于Hadoop的分布式数据仓库

Apache Hive 是一个基于 Apache Hadoop 构建的开源分布式数据仓库系统&#xff0c;支持使用 SQL 执行 PB 级大规模数据分析与查询。 主要功能 Apache Hive 提供的主要功能如下。 HiveServer2 HiveServer2 服务用于支持接收客户端连接和查询请求。 HiveServer2 支持多客户端…

FPGA_DDS_IP核

接下来对FPGA的DDS的ip核进行学习。 首先对DDS需要有些了解 DDS信号发生器采用直接数字频率合成&#xff08;Direct Digital Synthesis&#xff0c;简称DDS&#xff09;技术&#xff0c;简单来说就是 需要一个系统频率和一个输入的数字数据 &#xff0c;用这个系统频率计算出…

欢迎来到未来:探索 Dify 开源大语言模型应用开发平台

欢迎来到未来&#xff1a;探索 Dify 开源大语言模型应用开发平台 如果你对 AI 世界有所耳闻&#xff0c;那么你一定听说过大语言模型&#xff08;LLM&#xff09;。这些智能巨兽能够生成文本、回答问题、甚至编写代码&#xff01;但是&#xff0c;如何将它们变成真正的实用工具…

计算机工具基础(七)——Git

Git 本系列博客为《Missing in CS Class(2020)》课程笔记 Git是一种分布式版本控制系统&#xff0c;被其跟踪的文件可被查询精细到行的修改记录、回退版本、建立分支等 模型 一般流程&#xff1a;工作区 → \to →暂存区 → \to →仓库(本地 → \to →远端) 工作区&#xff1…

uniapp动态循环表单校验失败:初始值校验

问题现象 &#x1f4a5; 在实现动态增减的单价输入表单时&#xff08;基于uv-form组件&#xff09;&#xff0c;遇到以下诡异现象&#xff1a; <uv-input>的v-model绑定初始值为数字类型时&#xff0c;required规则失效 ❌数字类型与字符串类型校验表现不一致 &#x1…

前端框架学习路径与注意事项

学习前端框架是一个系统化的过程&#xff0c;需要结合理论、实践和工具链的综合掌握。以下是学习路径的关键方面和注意事项&#xff1a; 一、学习路径的核心方面 1. 基础概念与核心思想 组件化开发&#xff1a;理解组件的作用&#xff08;复用性、隔离性&#xff09;、组件通信…

【Python机器学习】3.5. 决策树实战:基于Iris数据集

喜欢的话别忘了点赞、收藏加关注哦&#xff08;关注即可查看全文&#xff09;&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 本文紧承 3.1. 决策树理论(基础) 和 3.2. 决策树理论(进阶)&#xff0c;没看过的建议先看理论分…

Unity2022发布Webgl2微信小游戏部分真机黑屏

复现规律&#xff1a; Unity PlayerSetting中取消勾选ShowSplashScreen 分析&#xff1a; 在Unity中&#xff0c;Splash Screen&#xff08;启动画面&#xff09; 不仅是视觉上的加载动画&#xff0c;还承担了关键的引擎初始化、资源预加载和渲染环境准备等底层逻辑。禁用后导…

docker desktop 集成WSL Ubuntu22.04

Windows docker desktop 设置WSL ubuntu 22.04启用与其他发行版的集成 Windows docker desktop 安装参考 wsl ubuntu 22.04 查看我宿主机的docker desktop 容器全部的信息 wsl -d Ubuntu-22.04 -u root

快速入手-基于Django的主子表间操作mysql(五)

1、如果该表中存在外键&#xff0c;结合实际业务情况&#xff0c;那可以这么写&#xff1a; 2、针对特殊的字典类型&#xff0c;可以这么定义 3、获取元组中的字典值和子表中的value值方法 4、对应的前端页面写法

使用cursor开发java案例——springboot整合elasticsearch

安装elasticsearch 打开cursor&#xff0c;输入如下提示词 使用springboot整合elasticsearch。其中elasticsearch服务器ip&#xff1a;192.168.236.134 管理员用户名elastic 管理员密码 PdQy_xfR2yLhpok*MK_ 监听端口9200点Accept all 使用idea打开生成的项目 &#xff0…

Deepseek结合企业数据挖掘平台能够给企业提升哪些效益?

Deepseek&#xff08;深度求索&#xff09;作为智能系统&#xff0c;在政务办公领域可通过AI技术优化流程、提升效率&#xff0c;具体应用场景分析如下&#xff1a; 1. 智能公文处理与流转 自动分类与审核 利用NLP解析公文内容&#xff0c;自动分类&#xff08;如请示、报告、通…

vite中sass警告JS API过期

在Vite创建项目中引入Sass弹出The legacy JS API is deprecated and will be removed in Dart Sass 2.0.0 vite中sass警告JS API过期 The legacy JS API is deprecated and will be removed in Dart Sass 2.0.0 警告提示表明你当前正在使用的 Dart Sass 版本中&#xff0c;旧的…