目录

Spring Cloud LoadBalancer

使用 Spring Cloud LoadBalancer 进行客户端负载平衡。 Spring Cloud 2020 版本以后,默认移除了对 Netflix 的依赖,其中就包括 Ribbon,官方默认推荐使用 Spring Cloud Loadbalancer 正式替换 Ribbon,并成为了 Spring Cloud 负载均衡器的唯一实现。

1
2
3
4
5
6
7
<dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>2020.0.2</version>
        <type>pom</type>
        <scope>import</scope>
</dependency>

注意:如果是Hoxton之前的版本,默认负载均衡器为Ribbon,需要移除Ribbon引用和增加配置 spring.cloud.loadbalancer.ribbon.enabled: false

引入 loadbalancer 依赖

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
 
<!-- 负载均衡需要搭配注册中心使用,这里引入Nacos做服务注册,也可采用Eureka等 -->
<!-- SpringCloud Ailibaba Nacos -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

负载均衡需要搭配注册中心使用,这里引入Nacos做服务注册,也可采用Eureka等

RestTemplate

使用RestTemplate实现Demo

引入web依赖:

1
2
3
4
5
<dependency>
    <!-- 使用web,使用Spring MVC对外提供服务   -->
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

编写DemoController:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
@RestController
public class TestController {
    @Autowired
    private RestTemplate restTemplate;
 
    // 新增restTemplate对象注入方法,注意,此处LoadBalanced注解一定要加上,否则无法远程调用
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
 
    @GetMapping("/load")
    public String load() {
        return restTemplate.getForObject("http://demo-server/hello/", String.class);
    }
 
    @GetMapping(value = "/hello")
    public String hello() {
        return "Hello World";
    }
}

4、启动 Nacos,调用接口 http://localhost:8080/load

除此之外,Spring Cloud LoadBalancer还支持Spring Web Flux响应式编程

原理

RestTemplate#setInterceptors 用于设置拦截器,拦截器需要实现ClientHttpRequestInterceptor接口即可,在实际远程去请求服务端接口之前会先调用拦截器的intercept方法逻辑。这里的拦截器相当于Servlet技术中的Filter功能。

LoadBalancerAutoConfiguration,由于@LoadBalanced注解由spring-cloud-commons实现,查看实现逻辑我们发现spring-cloud-commons存在自动配置类LoadBalancerAutoConfiguration,当满足条件时,将自动创建LoadBalancerInterceptor并注入到RestTemplate中。

LoadBalancerInterceptor 实现了 ClientHttpRequestInterceptor 接口,实现intercept方法,用于实现负载均衡的拦截处理。

LoadBalancerClient ,负载均衡客户端,用于进行负载均衡逻辑,从服务列表中选择出一个服务地址进行调用。Spring Cloud LoadBalancer 的默认实现为 BlockingLoadBalancerClient

LoadBalancerClientFactory,BlockingLoadBalancerClient中持有LoadBalancerClientFactory通过调用其getInstance方法获取具体的负载均衡客户端。客户端实现了不同的负载均衡算法,比如轮询、随机等。LoadBalancerClientFactory继承了NamedContextFactory,NamedContextFactory继承ApplicationContextAware,实现Spring ApplicationContext容器操作。LoadBalancerAutoConfiguration实现了LoadBalancerClientFactory缺省值

ReactiveLoadBalancer,负载均衡器,实现服务选择。Spring Cloud Balancer中实现了轮询RoundRobinLoadBalancer和随机数RandomLoadBalancer两种负载均衡算法。默认缺省值为RoundRobinLoadBalancer。

LoadBalancerRequestFactory,工厂用于创建 LoadBalancerRequest,调用createRequest方法。在内部持有LoadBalancerClient属性对象,即BlockingLoadBalancerClient。

整合 Feign

Feign 本身并不支持 Spring MVC 注解,为了方便使用,Spring Cloud孵化了 OpenFeign。

在日常项目中,一般负载均衡都是结合Feign使用,下面我们讨论下结合Fegin的使用情况

1、引入依赖

1
2
3
4
5
6
7
        <!-- SpringCloud Openfeign -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

       <!-- 其他 loadbalancer依赖 -->

2、定义Feign接口

1
2
3
4
5
6
@FeignClient(name = "my-service")
public interface RemoteLogService {
 
    @PostMapping("/sys/log")
    R<Boolean> saveLog(@RequestBody SysLog sysLog);
}

3、调用Feign接口调试(正常负载均衡已经可以使用,无需做其他配置)

查看Feign的loadbalancer的自动配置:FeignLoadBalancerAutoConfiguration,存在

LoadBalancerClient和LoadBalancerClientFactory的bean时,配置生效,默认使用DefaultFeignLoadBalancerConfiguration。请注意,如果引用了OkHttp或HttpClient,将使用不同的configuration文件。

DefaultFeignLoadBalancerConfiguration,将缺省创建FeignBlockingLoadBalancerClient并注入LoadBalancerClient和LoadBalancerClientFactory

FeignBlockingLoadBalancerClient,实现excute方法,实现Feign具体请求操作,通过loadBalancerClient.choose获取实例并执行请求,具体选择逻辑和RestTemplate一致。

附录