讲解负载均衡

发布于:2025-06-13 ⋅ 阅读:(14) ⋅ 点赞:(0)

一.什么是负载均衡

负载均衡是一种将请求按一定策略分配到多个后端资源的技术其作用主要如下

  • 分摊压力:避免单个节点过载,提升整体吞吐量。
  • 高可用性:屏蔽故障节点,自动切换到健康节点。
  • 弹性扩展:支持动态扩缩容。例如增加/减少实例。

主要涉及场景:

  • 微服务架构:服务消费者调用多个服务提供者时,分配请求。
  • API网关:统一入口接受所有请求,转发到后端多个业务服务实例。
  • 分布式计算:任务队列(kafka)的分区分配到多个消费者实例。

二.负载均衡算法

负载均衡的核心是分配策略,不同算法适用于不同场景。

1.轮询(Round Robin)

  • 原理:按顺序依次将请求分配给每个后端节点。
  • 优点:简单、公平、无状态。
  • 缺点:未考虑节点性能差异

例子:

public class RoundRobinLoadBalancer {
    private List<String> servers;
    private int currentIndex = 0;

    public RoundRobinLoadBalancer(List<String> servers) {
        this.servers = servers;
    }

    public String getNextServer() {
        if (servers.isEmpty()) throw new IllegalStateException("No servers available");
        String server = servers.get(currentIndex);
        currentIndex = (currentIndex + 1) % servers.size(); // 循环取模
        return server;
    }
}

2.加权轮询(Weighted Round Robin)

  • 原理:为每个节点分配权重,性能越高的节点权重越高,也按照权重比列分配请求。
  • 优点:适应节点性能差异,合理分摊压力。
  • 缺点:需动态调整权重(如节点扩容/缩容)。
public class WeightedRoundRobinLoadBalancer {
    static class Server {
        String address;
        int weight;
        int currentWeight = 0; // 当前权重(动态调整)

        Server(String address, int weight) {
            this.address = address;
            this.weight = weight;
        }
    }

    private List<Server> servers;
    private int totalWeight;

    public WeightedRoundRobinLoadBalancer(List<Server> servers) {
        this.servers = servers;
        this.totalWeight = servers.stream().mapToInt(s -> s.weight).sum();
    }

    public String getNextServer() {
        if (servers.isEmpty()) throw new IllegalStateException("No servers available");
        // 寻找当前权重最大的节点
        Server selected = null;
        int maxWeight = -1;
        for (Server server : servers) {
            server.currentWeight += server.weight;
            if (server.currentWeight > maxWeight) {
                maxWeight = server.currentWeight;
                selected = server;
            }
        }
        selected.currentWeight -= totalWeight; // 重置当前权重
        return selected.address;
    }
}

3.最少连接(Least Connections)

  • 原理:优先将请求分配给当前活跃连接数最少的节点(适用长连接场景,如数据库连接池)
  • 优点:动态适应节点负载,避免连接堆积。
  • 缺点:需维护每个节点的连接数状态。

4.随机(Random)

  • 原理:随机选择一个节点
  • 优点:实现简单,近似均匀分配
  • 缺点:可能出现分配不均

5.哈希(Hash)

  • 原理:根据请求的关键信息(如客户端IP、用户ID)计算哈希值,映射到固定节点(保证同一请求始终路由到同一节点)
  • 优点:适合需要会话保持的场景(例如用户登录状态)
  • 缺陷:节点增减时可能导致大量哈希失效

6.一致性哈希(Consistent Hashing)

  • 原理:将节点和请求哈希到一个环形空间,请求顺时针找到最近的节点;节点增减时仅影响相邻节点
  • 优点:动态扩缩容时,仅少量请求重新分配(使用Redis集群)

三.JAVA中负载均衡实现方式

Java中的负载均衡可分为客户端负载均衡和服务端负载均衡。

  • 客户端负载均衡:客户端直接决定请求发给哪个服务提供者(Ribbon)。
  • 服务端负载均衡:请求先到负载均衡器,由其转发到后端实例(Nginx)。

1.客户端负载均衡

  1. Ribbon(弃用),现在主要是Spring Cloud LoadBalancer
  • 核心功能:
    • 服务发现:从Eureka/Nacos等注册中心获取可用实例。
    • 负载均衡策略:轮询、随机。。。。
    • 健康检查
# application.yml 配置负载均衡策略(默认轮询)
spring:
  cloud:
    loadbalancer:
      default-algorithm: round_robin # 可选 random、least_connections 等

SpringCloud LoadBalancer

 @Bean
ReactorServiceInstanceLoadBalancer customLoadBalancer(
        LoadBalancerClientFactory factory, ConfigurableApplicationContext context) {
    String serviceId = context.getEnvironment().getProperty("service.instance.id");
    return new RandomLoadBalancer(
            factory.getLazyProvider(serviceId, ServiceInstanceListSupplier.class),
            serviceId);
}

2.服务端负载均衡

1.Nginx(反向代理)

  • 原理:Nginx作为入口,通过upstream配置后端Java服务实例,按策略转发请求。
  • 常见策略
    • round_robin(轮询,默认)
    • least_conn(最少连接)
    • ip_hash(基于客户端ip哈希,会话保持)
upstream java_servers {
    server 192.168.1.101:8080 weight=3; # 权重 3
    server 192.168.1.102:8080 weight=1; # 权重 1
    least_conn; # 最少连接策略
}

server {
    listen 80;
    location / {
        proxy_pass http://java_servers;
    }
}

2.API网关(Spring Cloud Gateway)

  • 原理:网关作为统一入口,集成负载均衡逻辑,将请求路由到后端微服务。
  • Java实现:通过RouteDefinition和LoadBalancerClient动态获取实例。

Java负载均衡总结:

  • 微服务场景​:优先客户端负载均衡(如 Spring Cloud LoadBalancer),集成服务发现和健康检查。
  • 高并发网关​:使用服务端负载均衡(如 Nginx),结合一致性哈希或最少连接策略。
  • 动态扩缩容​:选择支持实时更新实例列表的框架(如 Ribbon、Spring Cloud LoadBalancer)。