[SpringCloud][7]负载均衡介绍,以及一些实现

文章目录

负载均衡介绍

简单实现

问题描述

观察上篇文章的远程调用代码

java 复制代码
List<ServiceInstance> instances = discoveryClient.getInstances("product-service");  
// 服务可能有多个,获取第一个  
EurekaServiceInstance instance = (EurekaServiceInstance) instances.get(0);
  1. 根据应用名称获取了服务实例列表
  2. 从列表中选择了一个服务实例

思考 :如果一个服务对应多个实例呢?流量是否可以合理的分配到多个实例?
现象观察

  • 我们再启动 2 个 product-service 实例
  • 选中要启动的服务,右键选择 Copy Configuration...

在弹出的框中,选择 Modify options -> Add VM options

添加 VM options-Dserver.port=9091

  • 9091 为服务启动的端口号,根据自己的情况可修改

现在 IDEAService 窗口就会多出一个启动配置,右键启动服务就可以了

同样的操作,再启动一个实例,共启动三个服务器

观察 Eureka,可以看到 product-service 下有三个实例:


访问结果

访问: http://127.0.0.1:8080/order/1

  • 通过日志可以发现,请求多次访问,都是同一台机器

问题解决

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

我们可以针对上述代码简单修改:

java 复制代码
package org.example.order.service;  
  
import jakarta.annotation.PostConstruct;  
import jakarta.annotation.Resource;  
import lombok.extern.slf4j.Slf4j;  
import org.example.order.mapper.OrderMapper;  
import org.example.order.model.OrderInfo;  
import org.example.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.cloud.netflix.eureka.EurekaServiceInstance;  
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;  
  
    @Resource  
    private DiscoveryClient discoveryClient;  
    @Autowired  
    private RestTemplate restTemplate;  
  
    private static AtomicInteger atomicInteger = new AtomicInteger(1);  
    private static List<ServiceInstance> instances;  
  
    @PostConstruct  
    public void init() {  
        // 根据应用名称获取服务器列表  
        instances = discoveryClient.getInstances("product-service");  
    }  
  
    public OrderInfo selectOrderById(Integer orderId) {  
        OrderInfo orderInfo = orderMapper.selectOrderById(orderId);  
        //String url = "http://127.0.0.1:9090/product/" + orderInfo.getProductId();  
        // 服务可能有多个,轮询获取实例  
        int index = atomicInteger.getAndIncrement() % instances.size();  
        ServiceInstance instance = instances.get(index);  
        log.info(instance.getInstanceId());  
        // 拼接 URL        
        String url = instance.getUri() + "/product/" + orderInfo.getProductId();  
        ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);  
        orderInfo.setProductInfo(productInfo);  
        return orderInfo;  
    }  
}
  • @PostConstruct :在 Spring 容器完成 依赖注入(DI) 后,自动调用标注了 @PostConstruct 的方法,用于执行初始化逻辑。

    • 就是当这个 Bean 创建完成并注入完需要的依赖后,Spring 会自动调用我标注的方法一次,用来做一些初始化的操作。
  • discoveryClient.getInstances() 可以返回当前所有可用的 product-service 实例。

    • instances 列表包含了所有可用的 product-service 实例,每个实例包含了服务的 URI 和其他元数据
  • int index = atomicInteger.getAndIncrement() % instances.size():该逻辑基于递增的计数器来决定访问哪个实例。每次访问时,计数器会递增,并且通过 index % instances.size() 确保能够在实例列表中轮询(即循环访问所有实例)。

    • 例如,如果有 3 个实例,当 atomicInteger 的值为 1、2、3、4 时,它会依次访问

观察日志:

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

通过使用 DiscoveryClient 获取 product-service 的所有实例,并结合 AtomicInteger 实现轮询负载均衡,将请求均匀地分发到 product-service 的各个实例上,从而有效地进行负载均衡。

什么是负载均衡

负载均衡(Load Balance,简称 LB),是高并发,高可用系统必不可少的关键组件

当服务流量增大时,通常会采用增加机器的方式进行扩容,负载均衡就是用来在多个机器或者其他资源中,按照一定规则合理分配负载

  • 一个团队最开始只有一个人,后来随着工作量的增加,公司又招聘了几个人,负载均衡就是:如何把工作量均衡的分配到这几个人身上,以提高整个团队的效率

负载均衡的一些实现

上面的例子中,我们只是简单的对实例进行了轮询,但真是的业务场景会更加复杂。比如根据机器的配置进行负载分配,配置高的分配的流量高,配置低的分配流量低等

  • 类似企业员工:能力强的员工可以多承担一些工作

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

  • 负载均衡分为服务端负载均衡客户端负载均衡

服务端负载均衡

在服务端进行负载均衡的算法分配


比较有名的服务端负载均衡器是 Nginx。请求先到达 Nginx 负载均衡器,然后通过负载均衡算法,在多个服务器之间选择一个进行访问

客户端负载均衡

在客户端进行负载均衡的算法分配


把负载均衡的功能以库的方式集成到客户端,而不再是由一台指定的负载均衡设备集中提供

比如 Spring CloudRibbon,请求发送到客户端,客户端从注册中心(比如 Eureka)获取到服务列表,在发送请求前通过负载均衡算法选择一个服务器,然后再进行访问

RibbonSpring Cloud 早期的默认实现,由于不维护了,所以最新版本的 Spring Cloud 负载均衡集成的是 Spring CloudBalancerSpring Cloud 官方维护)

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

相关推荐
paishishaba1 天前
JAVA面试复习笔记(待完善)
java·笔记·后端·面试
四谎真好看1 天前
Java 黑马程序员学习笔记(进阶篇19)
java·笔记·学习·学习笔记
從南走到北1 天前
JAVA代泊车接机送机服务代客泊车系统源码支持小程序+APP+H5
java·开发语言·微信小程序·小程序
apocelipes1 天前
golang unique包和字符串内部化
java·python·性能优化·golang
Full Stack Developme1 天前
java.text 包详解
java·开发语言·python
刘梦凡呀1 天前
C#获取钉钉平台考勤记录
java·c#·钉钉
best_virtuoso1 天前
PostgreSQL 常见数组操作函数语法、功能
java·数据结构·postgresql
yudiandian20141 天前
02 Oracle JDK 下载及配置(解压缩版)
java·开发语言
楚韵天工1 天前
宠物服务平台(程序+文档)
java·网络·数据库·spring cloud·编辑器·intellij-idea·宠物