Spring Cloud之负载均衡之LoadBalance

news2025/3/28 7:46:06

目录

负载均衡

问题

步骤

现象 

什么是负载均衡?

负载均衡的一些实现

服务端负载均衡

客户端负载均衡

使用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 {
    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;

    //计数器
    private AtomicInteger count = new AtomicInteger(1);

    private List<ServiceInstance> instances;

    @PostConstruct
    public void init(){
        //从Eureka中获取服务列表
        instances = discoveryClient.getInstances("product-service");
    }

    public OrderInfo selectOrderById(Integer orderId){
        OrderInfo orderInfo = orderMapper.selectOrderById(orderId);
        //计算轮流的实例idnex
        int index= count.getAndIncrement() % instances.size();
        //获取实例
        String uri = instances.get(index).getUri().toString();
        //拼接url
        String 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
    @LoadBalanced
    public 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 {
    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private 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 {
    @Bean
    ReactorLoadBalancer<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
    @LoadBalanced
    public 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.coloradmin.cn/o/2318950.html

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

相关文章

分布式任务调度

今天我们讲讲分布式定时任务调度—ElasticJob。 一、概述 1、什么是分布式任务调度 我们可以思考⼀下下⾯业务场景的解决⽅案: 某电商平台需要每天上午10点&#xff0c;下午3点&#xff0c;晚上8点发放⼀批优惠券 某银⾏系统需要在信⽤卡到期还款⽇的前三天进⾏短信提醒 某…

架构设计的灵魂交响曲:系统设计各维度的深度解析与实战指南

引言: 系统设计的背景与重要性 在快速变化的技术环境中&#xff0c;数字化转型成为企业生存与发展的核心驱动力。系统设计能力不仅是技术团队的核心竞争力&#xff0c;也是推动业务创新和提升整体效率的关键因素。根据Gartner的研究&#xff0c;超过70%的数字化转型项目未能实…

[贪心算法]买卖股票的最佳时机 买卖股票的最佳时机Ⅱ K次取反后最大化的数组和 按身高排序 优势洗牌(田忌赛马)

1.买卖股票的最佳时机 暴力解法就是两层循环&#xff0c;找出两个差值最大的即可。 优化&#xff1a;在找最小的时候不用每次都循环一遍&#xff0c;只要在i向后走的时候&#xff0c;每次记录一下最小的值即可 class Solution { public:int maxProfit(vector<int>& p…

【 <二> 丹方改良:Spring 时代的 JavaWeb】之 Spring MVC 的核心组件:DispatcherServlet 的工作原理

<前文回顾> 点击此处查看 合集 https://blog.csdn.net/foyodesigner/category_12907601.html?fromshareblogcolumn&sharetypeblogcolumn&sharerId12907601&sharereferPC&sharesourceFoyoDesigner&sharefromfrom_link <今日更新> 一、Dispat…

第J3周:DenseNet121算法实现01(Pytorch版)

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 目标 具体实现 &#xff08;一&#xff09;环境 语言环境&#xff1a;Python 3.10 编 译 器: PyCharm 框 架: Pytorch &#xff08;二&#xff09;具体步骤…

webrtc3A算法

使用ubuntu18.04 选择webrtc_audio_processing v0.3 下载地址 https://gitlab.freedesktop.org/pulseaudio/webrtc-audio-processing/-/tree/master git clone 完 编译 # Initialise into the build/ directory, for a prefixed install into the # install/ directory meson …

让“树和二叉树”埋在记忆土壤中--性质和概念

Nice to meet your! 目录 树的介绍&#xff1a; 树的创建&#xff1a; 二叉树的概念和结构&#xff1a; 二叉树的存储结构&#xff1a; 树的介绍&#xff1a; 概念和结构&#xff1a; 不知你们是否在现实中看见过分为两个叉的枯树&#xff0c;大概长这样&#xff1a; 那…

Spring Boot整合SSE实现消息推送:跨域问题解决与前后端联调实战

摘要 本文记录了一次完整的Spring Boot整合Server-Sent Events&#xff08;SSE&#xff09;实现实时消息推送的开发过程&#xff0c;重点分析前后端联调时遇到的跨域问题及解决方案。通过CrossOrigin注解的实际应用案例&#xff0c;帮助开发者快速定位和解决类似问题。 一、项…

【工具分享】vscode+deepseek的接入与使用

目录 第一章 前言 第二章 获取Deepseek APIKEY 2.1 登录与充值 2.2 创建API key 第三章 vscode接入deepseek并使用 3.1 vscode接入deepseek 3.2 vscode使用deepseek 第一章 前言 deepseek刚出来时有一段时间余额无法充值&#xff0c;导致小编没法给大家发完整的流程&…

康谋方案 | AVM合成数据仿真验证方案

随着自动驾驶技术的快速发展&#xff0c;仿真软件在开发过程中扮演着越来越重要的角色。仿真传感器与环境不仅能够加速算法验证&#xff0c;还能在安全可控的条件下进行复杂场景的重复测试。 本文将分享如何利用自动驾驶仿真软件配置仿真传感器与搭建仿真环境&#xff0c;并对…

Linux内核IPv4路由选择子系统

一、基本知识 1.具体案例&#xff1a;直连路由 结构fib_nh表示下一跳&#xff0c;包含输出网络设备、外出接口索引等信息。 有两个以太网局域网 LAN1 和 LAN2&#xff0c;其中 LAN1 包含子网 192.168.1.0/24&#xff0c;而 LAN2 包含子网 192.168.2.0/24。在这两个 LAN 之…

NWAFU 生物统计实验二 R语言版

#1 setwd(修改为你的工作路径或桌面路径) feed_types <- c("A", "B", "C") weight_gain_means <- c(36.8, 34.9, 21.3) weight_gain_sds <- c(2.4, 2.7, 6.6) weight_gain <- rnorm(3, mean weight_gain_means, sd weight_gain_sd…

Thinkphp指纹识别

识别ThinkPHP框架(指纹) 1.ioc判断 /favicon.ico 2.报错 /1 然后使用工具梭哈

【AVRCP】蓝牙AVRCP协议中的L2CAP互操作性要求深度解析

目录 一、L2CAP互操作性要求&#xff08;针对AVRCP&#xff09; 1.1 核心概念 1.2 AVRCP对L2CAP的增强需求 1.3 关键机制解析 1.4 浏览通道优化配置 1.5 实际应用场景与解决方案 二、通道类型与配置 2.1. 通道类型限制 2.2 PSM字段规范 2.3. 实现意义 3.4. 实际应用…

剑指 Offer II 111. 计算除法

comments: true edit_url: https://github.com/doocs/leetcode/edit/main/lcof2/%E5%89%91%E6%8C%87%20Offer%20II%20111.%20%E8%AE%A1%E7%AE%97%E9%99%A4%E6%B3%95/README.md 剑指 Offer II 111. 计算除法 题目描述 给定一个变量对数组 equations 和一个实数值数组 values 作…

掌握 WRF/Chem 模式:突破大气环境研究技术瓶颈的关键

技术点目录 第一部分、WRF-Chem模式应用案例和理论基础第二部分、Linux环境配置及WRF-CHEM第三部分、WRF-Chem模式编译&#xff0c;排放源制作第四部分、WRF-Chem数据准备&#xff08;气象、排放、初边界条件等&#xff09;&#xff0c;案例实践第五部分、模拟结果提取、数据可…

linux性能监控的分布式集群 prometheus + grafana 监控体系搭建

prometheusgrafana分布式集群资源监控体系搭建 前言一、安装 prometheus二、在要监控的服务器上安装监听器三、prometheus服务器配置四、grafana配置大屏五、创建Linux监控看板五、监控windows服务器注意事项 前言 Prometheus 是一个开源的 ​分布式监控系统 和 ​时间序列数据…

数字化转型 2.0:AI、低代码与智能分析如何重塑企业竞争力?

引言&#xff1a;数字化转型进入2.0时代 在过去的十几年里&#xff0c;企业的数字化转型&#xff08;1.0&#xff09;主要围绕信息化和自动化展开&#xff0c;例如引入ERP、CRM等系统&#xff0c;提高办公效率&#xff0c;减少人为失误。然而&#xff0c;随着市场竞争加剧&…

基于SpringBoot的“校园招聘网站”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“校园招聘网站”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统整体功能图 局部E-R图 系统首页界面 系统注册…

由LAC自动建立L2TP实验

一、实验拓扑: 二、实验配置 1.LAC的配置 基础配置: [LAC]int g 0/0/0 [LAC-GigabitEthernet1/0/0]ip address 192.168.0.1 24 [LAC]int g 1/0/0 [LAC-GigabitEthernet1/0/0]ip address 10.1.1.254 24 [LAC-GigabitEthernet1/0/0]int g1/0/1 [LAC-GigabitEthernet1/0/1]ip ad…