1. 概述
本文将深入探讨 Zuul 与 Eureka 协同实现负载均衡的机制。我们将通过 Zuul 代理,将请求路由到由 Spring Cloud Eureka 发现的 REST 服务。
2. 初始准备
需要预先搭建好 Eureka 服务端/客户端,具体步骤可参考 Spring Cloud Netflix-Eureka 一文(此处不展开基础配置)。
3. 配置 Zuul
Zuul 的核心功能之一是从 Eureka 获取服务位置并执行服务端负载均衡。
3.1. Maven 依赖配置
首先在 pom.xml
中添加 Zuul Server 和 Eureka 依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
3.2. 与 Eureka 通信
在 Zuul 的 application.properties
中添加关键配置:
server.port=8762
spring.application.name=zuul-server
eureka.instance.preferIpAddress=true
eureka.client.registerWithEureka=true
eureka.client.fetchRegistry=true
eureka.client.serviceUrl.defaultZone=${EUREKA_URI:http://localhost:8761/eureka}
✅ 此配置让 Zuul 在 Eureka 中注册为服务,并运行在 8762 端口。
接下来实现主类,使用 @EnableZuulProxy
和 @EnableDiscoveryClient
注解:
@SpringBootApplication
@EnableZuulProxy
@EnableDiscoveryClient
public class ZuulConfig {
public static void main(String[] args) {
SpringApplication.run(ZuulConfig.class, args);
}
}
访问 http://localhost:8762/routes 可查看所有由 Eureka 发现的 Zuul 路由:
{"/spring-cloud-eureka-client/**":"spring-cloud-eureka-client"}
现在通过 Zuul 代理路由访问 Eureka 客户端:http://localhost:8762/spring-cloud-eureka-client/greeting,将得到类似响应:
Hello from 'SPRING-CLOUD-EUREKA-CLIENT with Port Number 8081'!
4. Zuul 负载均衡实现
当 Zuul 收到请求时,会从可用服务实例中选择一个并转发请求。服务实例位置缓存和请求转发过程完全开箱即用,无需额外配置。
下图展示了 Zuul 如何封装同一服务的三个不同实例:
内部实现上,Zuul 使用 Netflix Ribbon 从服务发现中心(Eureka Server)查询所有服务实例。
4.1. 注册多实例
启动两个服务实例(端口 8081 和 8082)。观察日志可见实例位置已注册到 DynamicServerListLoadBalancer
,路由映射到负责转发的 Zuul Controller
:
Mapped URL path [/spring-cloud-eureka-client/**] onto handler of type [class org.springframework.cloud.netflix.zuul.web.ZuulController]
Client:spring-cloud-eureka-client instantiated a LoadBalancer:
DynamicServerListLoadBalancer:{NFLoadBalancer:name=spring-cloud-eureka-client,
current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null
Using serverListUpdater PollingServerListUpdater
DynamicServerListLoadBalancer for client spring-cloud-eureka-client initialized:
DynamicServerListLoadBalancer:{NFLoadBalancer:name=spring-cloud-eureka-client,
current list of Servers=[0.0.0.0:8081, 0.0.0.0:8082],
Load balancer stats=Zone stats: {defaultzone=[Zone:defaultzone; Instance count:2;
Active connections count: 0; Circuit breaker tripped count: 0;
Active connections per server: 0.0;]},
Server stats:
[[Server:0.0.0.0:8080; Zone:defaultZone;......],
[Server:0.0.0.0:8081; Zone:defaultZone; ......],
⚠️ 日志已格式化以便阅读
4.2. 负载均衡演示
多次访问 http://localhost:8762/spring-cloud-eureka-client/greeting,将看到轮询分配的结果:
Hello from 'SPRING-CLOUD-EUREKA-CLIENT with Port Number 8081'!
Hello from 'SPRING-CLOUD-EUREKA-CLIENT with Port Number 8082'!
Hello from 'SPRING-CLOUD-EUREKA-CLIENT with Port Number 8081'!
Zuul 收到的每个请求都会以轮询方式转发到不同实例。
启动新实例(如端口 8083)并注册到 Eureka 后,Zuul 自动将其加入负载均衡池:
Hello from 'SPRING-CLOUD-EUREKA-CLIENT with Port Number 8083'!
⚠️ 可通过 Ribbon 配置更改负载均衡策略(详见 Ribbon 文章)。
5. 总结
实践表明,Zuul 为 REST 服务的所有实例提供统一入口,并通过轮询方式实现负载均衡。核心优势包括:
- ✅ 服务自动发现与注册
- ✅ 零配置负载均衡
- ✅ 动态实例感知
完整代码示例请查阅 GitHub 仓库。