微服务多机部署与负载均衡实战:从手写轮询到 Spring Cloud LoadBalancer 落地

微服务多机部署与负载均衡实战:从手写轮询到 Spring Cloud LoadBalancer 落地

在微服务架构里,单实例服务扛不住高并发 ,多实例部署是常态。但多实例跑起来后,请求怎么均匀分给不同机器?这就是负载均衡要解决的核心问题。

本文基于 Spring Cloud 环境,从手写轮询踩坑,到 Spring Cloud LoadBalancer 开箱即用,再到 Linux 多实例部署,带你彻底吃透客户端负载均衡。


一、为什么要做负载均衡?先看痛点

先回顾一下原生服务调用代码:

java 复制代码
// 1. 根据服务名获取实例列表
List<ServiceInstance> instances = discoveryClient.getInstances("product-service");
// 2. 直接拿第一个实例
EurekaServiceInstance instance = (EurekaServiceInstance) instances.get(0);

问题很明显:

  • 服务多实例部署,请求永远打在第一台机器

  • 其他实例完全闲置,单节点压力巨大,容易雪崩

  • 完全达不到高可用、水平扩容的目的

我们启动 3 个 product-service 实例(9090/9091/9092),连续请求订单服务,日志会发现:

Plain 复制代码
LUCF: product-service:9090
LUCF: product-service:9090
LUCF: product-service:9090

所有流量都堆在一台机器,这绝对不是我们想要的。


二、手写负载均衡:最简单的轮询实现

既然默认只取第一个,那我们自己按顺序轮询不就行了?

核心思路:

  • 用 AtomicInteger 保证线程安全计数

  • 每次请求对实例数量取模,循环选择实例

代码改造如下:

java 复制代码
@Configuration
public class BeanConfig {
    // 原子计数器,保证线程安全
    private static final 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);
        // 轮询计算索引
        int index = atomicInteger.getAndIncrement() % instances.size();
        ServiceInstance instance = instances.get(index);
        // 拼接真实地址
        String url = instance.getUri() + "/product/" + orderInfo.getProductId();
        ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);
        orderInfo.setProductInfo(productInfo);
        return orderInfo;
    }
}

再看日志,请求均匀分配:

Plain 复制代码
LUCF: product-service:9091
LUCF: product-service:9090
LUCF: product-service:9092
LUCF: product-service:9091

✅ 负载均衡生效!

但手写有明显缺点:

  • 代码侵入业务,冗余且难维护

  • 只支持简单轮询,不支持权重、随机等策略

  • 生产环境不推荐


三、负载均衡核心:服务端 vs 客户端

1. 服务端负载均衡

  • 请求先到独立负载均衡器(Nginx、F5)

  • 由均衡器统一分发到后端服务

  • 代表组件:Nginx

2. 客户端负载均衡

  • 均衡逻辑集成在调用方(客户端)

  • 客户端从注册中心拉取服务列表

  • 发送请求前自己选实例

  • 代表组件:Spring Cloud LoadBalancer(替代 Ribbon)

两者最大区别:服务实例清单存在哪里

  • 服务端:均衡器维护

  • 客户端:调用方本地维护


四、Spring Cloud LoadBalancer 开箱即用

Spring Cloud 2020.0.1 后移除 Ribbon,官方主推 Spring Cloud LoadBalancer

1. 三步快速集成

① 给 RestTemplate 加注解
java 复制代码
@Configuration
public class BeanConfig {
    @Bean
    @LoadBalanced // 开启负载均衡
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
② 调用地址改用服务名
java 复制代码
public OrderInfo selectOrderById(Integer orderId) {
    OrderInfo orderInfo = orderMapper.selectOrderById(orderId);
    // 不再写死 IP:端口,直接用服务名
    String url = "http://product-service/product/" + orderInfo.getProductId();
    ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);
    orderInfo.setProductInfo(productInfo);
    return orderInfo;
}
③ 启动多实例测试

IDEA 复制启动配置,添加 VM 参数:

Plain 复制代码
-Dserver.port=9091
-Dserver.port=9092

连续请求,日志自动轮询分发。


五、负载均衡策略:轮询 &amp; 随机 &amp; 自定义

Spring Cloud LoadBalancer 自带两种策略:

1. 轮询(默认)

请求按顺序轮流分配,适合实例配置相近场景。

2. 随机

随机选一个实例,实现简单,流量分布较均匀。

3. 自定义策略(以随机为例)

① 定义策略配置类
java 复制代码
public class LoadBalancerConfig {
    @Bean
    public ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(
            Environment environment,
            LoadBalancerClientFactory factory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new RandomLoadBalancer(
                factory.getLazyProvider(name, ServiceInstanceListSupplier.class),
                name
        );
    }
}

注意:不要加 @Configuration,避免被全局扫描。

② 绑定到服务
java 复制代码
@Configuration
// 对 product-service 启用随机策略
@LoadBalancerClient(name = "product-service", configuration = LoadBalancerConfig.class)
public class BeanConfig {
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

六、LoadBalancer 核心原理

核心是 LoadBalancerInterceptor 拦截器:

  1. 拦截 RestTemplate 请求,提取服务名(如 product-service)

  2. 从 Eureka 获取该服务的所有实例

  3. 按负载均衡策略选中一个实例

  4. 把服务名替换成真实 IP: 端口,发起调用

源码简化流程:

java 复制代码
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) {
    // 1. 获取服务名
    String serviceName = request.getURI().getHost();
    // 2. 负载均衡选择实例
    ServiceInstance instance = loadBalancer.choose(serviceName);
    // 3. 替换地址并转发
    return execution.execute(request, body);
}

七、Linux 环境多实例部署实战

本地测试完,上线到 Linux 服务器:

1. 服务打包

Maven 执行 package,得到 3 个 jar:

  • eureka-server.jar

  • order-service.jar

  • product-service.jar

2. 后台启动多实例

bash 复制代码
# 启动注册中心
nohup java -jar eureka-server.jar > logs/eureka.log &

# 启动订单服务
nohup java -jar order-service.jar > logs/order.log &

# 启动 3 个商品服务实例
nohup java -jar product-service.jar --server.port=9090 > logs/product-9090.log &
nohup java -jar product-service.jar --server.port=9091 > logs/product-9091.log &
nohup java -jar product-service.jar --server.port=9092 > logs/product-9092.log &

3. 防火墙开放端口

以腾讯云为例:

  • 进入防火墙 → 添加规则

  • 协议 TCP,端口 8761,8080,9090,9091,9092

  • 策略允许

4. 验证

  • 访问 Eureka:http:// 服务器 IP:8761

  • 查看 product-service 有 3 个实例 UP

  • 请求订单接口,负载均衡正常分发


八、总结

  1. 负载均衡是微服务高并发、高可用的必备组件

  2. 客户端负载均衡:调用方本地选实例,无单点、性能好

  3. Spring Cloud LoadBalancer:@LoadBalanced 一行开启,默认轮询,支持随机 / 自定义

  4. 生产建议:

    • 禁用手写轮询,统一用官方 LoadBalancer

    • 按实例性能配置权重策略(扩展)

    • 配合健康检查,自动剔除异常实例

相关推荐
fajianchen16 小时前
RBAC 模型与角色爆炸
微服务·权限管理
咖啡星人k16 小时前
MonkeyCode 后端架构全解析:Go微服务如何支撑万级并发AI任务
微服务·架构·golang·monkeycode
无聊的老谢16 小时前
电信系统中的单元测试策略:构建高可靠性的微服务防线
数据库·微服务·单元测试
我登哥MVP17 小时前
SpringCloud 核心组件解析:服务链路追踪
java·spring boot·后端·spring·spring cloud·java-ee·maven
惜缘破军18 小时前
基于 Spring Boot 3 和 Spring Cloud 2023 的微服务基础框架 hdfk7-boot
spring boot·后端·微服务
LT101579744418 小时前
2026年接口自动化测试平台选型指南:微服务高效测试工具
测试工具·微服务·架构
budingxiaomoli19 小时前
优雅的实现远程调用--OpenFeign
spring cloud
我登哥MVP20 小时前
SpringCloud 核心组件解析:服务调用和负载均衡
java·spring boot·后端·spring·spring cloud·java-ee·负载均衡
心之伊始20 小时前
Dubbo 3 Consumer 调用链路源码分析:从 Proxy 到 Cluster、Directory、Router、LoadBalance
java·微服务·dubbo·源码分析·服务治理
sbjdhjd20 小时前
企业级 Tomcat (上):WEB 技术栈 + 架构演进 + 生产级安装部署
linux·运维·云原生·开源·tomcat·云计算·负载均衡