Appearance
Hello Eureka
1. 项目依赖管理
XML
<properties>
<spring-boot.version>2.7.6</spring-boot.version>
<spring-cloud.version>2021.0.8</spring-cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- Spring Boot Dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Spring Cloud Dependencies -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>2. Eureka Server 搭建
创建项目并引入依赖:
XML<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>编写启动类,并添加
@EnableEurekaServer注解;Java@EnableEurekaServer @SpringBootApplication public class EurekaApplication { public static void main(String[] args) { SpringApplication.run(EurekaApplication.class, args); } }1
2
3
4
5
6
7编写
application.yml:YAMLserver: port: 8761 # Eureka 服务端口号 spring: application: name: Eureka eureka: client: service-url: defaultZone: http://localhost:8761/eureka1
2
3
4
5
6
7
8
9这里 3 ~ 9 行的配置实际上是关于服务注册的配置(将 Eureka 自己也注册为服务提供者)。
eureka.client.service-url配置项用于定义 Eureka 客户端连接到的 Eureka Server 的地址(将来 Eureka 集群也是通过这里配置的)。它是一个Map<String, String>类型,配置项中的 Key 用于表示某个 Eureka Server 的分组或区域。当没有特殊区域划分需求时,通常使用defaultZone作为 Key。需要注意的是defaultZone是区分大小写的,并且要求使用驼峰命名法。
3. Client 服务注册
在客户端项目中引入依赖:
XML<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>Note:注意这里是
spring-cloud-starter-netflix-eureka-client不是spring-cloud-starter-netflix-eureka-server。编写
application.yml:YAMLserver: port: 8081 # Client 服务端口号 spring: application: name: CustomService eureka: client: service-url: defaultZone: http://localhost:8761/eureka # Eureka Server 地址测试同一服务注册多个实例
在 Idea 中将目标服务的 Run/Debug 配置文件复制一份出来后,添加 Java VM 选项
-Dserver.port=8091(需与原服务端口号不同),再 Run/Debug 该配置文件,待服务启动完成后,在 Eureka Server 页面将看到该服务存在多个接口地址:
图 3.1 - 同一服务注册多个实例
4. Client 服务发现
为
RestTemplate添加@LoadBalance注解:Java@Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); }1
2
3
4
5将请求的 URL 主机名和端口号改为服务名称:
修改前 JavarestTemplate.getForObject("http://localhost:8081/user/" + random.nextInt(), UserVO.class)修改后 JavarestTemplate.getForObject("http://UserService/user/" + random.nextInt(), UserVO.class)
5. 配置负载均衡规则
在 Spring Cloud 中,负载均衡策略是由 Ribbon 提供的,而 Ribbon 的负载均衡策略可以通过配置文件或代码来设置。
Tip:从 Spring Cloud 2020.0 开始,官方推荐使用 Spring Cloud LoadBalancer 替代 Ribbon(Ribbon 进入维护模式)。
5.1. 常见的负载均衡策略
Ribbon 支持以下几种负载均衡策略:
| 策略 | 名称 | 描述 |
|---|---|---|
RoundRobinRule | 轮询策略(默认策略) | 按顺序轮流选择服务器,均匀分配请求。 |
RandomRule | 随机策略 | 随机选择一台服务器处理请求。 |
WeightedResponseTimeRule | 加权响应时间策略 | 根据服务器的平均响应时间分配权重,响应快的服务器获得更多请求。 |
BestAvailableRule | 最佳可用策略 | 选择当前连接数最少的服务器(跳过已被标记为不可用的服务器)。 |
RetryRule | 重试策略 | 在选定策略(如轮询)的基础上,如果请求失败,会在一定时间内重试其他服务器。 |
ZoneAwareRoundRobinRule | 区域感知轮询策略 | 优先选择同一区域内的服务器,然后在区域内进行轮询。 |
AvailabilityFilteringRule | 可用性过滤策略 | 过滤掉不可用或连接数过高的服务器,然后从剩余服务器中选择。 |
5.2. 通过配置文件配置
Ribbon 的配置可以通过服务名称指定负载均衡策略。例如,假设你的服务名称是 user-service,可以在配置文件中这样设置:
YAML
user-service:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule5.3. 通过 Java 代码配置
如果需要更灵活的配置,可以通过定义一个 @Bean 来覆盖默认的负载均衡策略。例如:
Java
@Configuration
public class RibbonConfig {
@Bean
public IRule ribbonRule() {
return new RandomRule(); // 设置为随机策略
}
}然后在主类上使用 @RibbonClient 注解,指定服务和配置类(未指定则表示策略):
Java
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@RibbonClient(name = "user-service", configuration = RibbonConfig.class)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}6. 负载均衡实现原理
拦截器
@LoadBalanced注解会触发RestTemplate的自定义配置,自动配置类是LoadBalancerAutoConfiguration,它会为@LoadBalanced注解标记的RestTemplate自动注入一个拦截器LoadBalancerInterceptor(ClientHttpRequestInterceptor接口的实现类)。服务发现
拦截器会调用
LoadBalancerClient(如 Ribbon 的实现或 Spring Cloud LoadBalancer)的choose方法,从服务注册中心获取服务名称对应的服务实例列表。负载均衡器根据配置的策略(如轮询、随机、权重等)选择一个服务实例,并返回其实际地址(IP 和端口)。
URL 重写
拦截器将原始请求的 URL 中的服务名称替换为选中的服务实例的实际地址。例如,将
http://UserService/api重写为http://192.168.1.100:8080/api。发送请求
重写后的 URL 被传递给
RestTemplate的底层 HTTP 客户端(如HttpURLConnection或OkHttp),完成实际的 HTTP 请求。
7. 饥饿加载
Ribbon 默认是采用懒加载,即第一次访问时才会去创建 LoadBalanceClient,请求时间会很长。而饥饿加载则会在项目启动时创建,降低第一次访问的耗时,通过下面配置开启饥饿加载:
YAML
ribbon:
eager-load:
enabled: true # 开启饥饿加载
clients: # 指定饥饿加载的服务名称
- user-service