Spring Cloud LoadBalancer 负载均衡实战与原理
问题背景
在微服务架构中,远程调用是常态。假设我们之前的代码是这样写的:
List<ServiceInstance> instances = discoveryClient.getInstances("product-service");
// 服务可能有多个,获取第一个
EurekaServiceInstance instance = (EurekaServiceInstance) instances.get(0);
这段逻辑很简单:根据应用名称获取服务实例列表,然后直接取第一个。但如果一个服务对应多个实例呢?流量是否可以合理地分配到多个实例上?
现象观察
为了验证这个问题,我们在本地启动多个 product-service 实例。通过 IDEA 的 Copy Configuration 功能,修改 VM options 为 -Dserver.port=9091,再启动一个实例,共启动 3 个服务。

访问 Eureka 注册中心,可以看到 product-service 下确实有三个实例:

此时访问订单接口 http://127.0.0.1:8080/order/1,观察日志发现:请求多次访问,都是同一台机器。这显然不是我们想要的结果,启动多个实例本意是为了分担负荷。
手动轮询方案
我们可以对上述代码进行简单修改,引入轮询逻辑:
private static AtomicInteger atomicInteger = new AtomicInteger(1);
private static List<ServiceInstance> instances;
@PostConstruct
public void init() {
// 根据应用名称获取服务列表
instances = discoveryClient.getInstances();
}
OrderInfo {
orderMapper.selectOrderById(orderId);
atomicInteger.getAndIncrement() % instances.size();
instances.get(index);
log.info(instance.getInstanceId());
instance.getUri() + + orderInfo.getProductId();
restTemplate.getForObject(url, ProductInfo.class);
orderInfo.setProductInfo(productInfo);
orderInfo;
}


