1. 程式人生 > 其它 >Alibaba微服務元件 - Spring Cloud LoadBalancer

Alibaba微服務元件 - Spring Cloud LoadBalancer

1. 什麼是Spring Cloud LoadBalance

Spring Cloud LoadBalancer是Spring Cloud官方自己提供的客戶端負載均衡器, 用來替代Ribbon
Spring官方提供了兩種負載均衡的客戶端:

  • RestTemplate
    RestTemplate是Spring提供的用於訪問Rest服務的客戶端,RestTemplate提供了多種便捷訪問遠端Http服務的方法,能夠大大提高客戶端的編寫效率。預設情況下,RestTemplate預設依賴jdk的HTTP連線工具。
  • WebClient
    WebClient是從Spring WebFlux 5.0版本開始提供的一個非阻塞的基於響應式程式設計的進行Http請求的客戶端工具。它的響應式程式設計的基於Reactor的。WebClient中提供了標準Http請求方式對應的get、post、put、delete等方法,可以用來發起相應的請求。

2. RestTemplate整合LoadBalancer

2.1 引入依賴

<!-- LoadBalancer -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

<!-- 提供了RestTemplate支援 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- nacos服務註冊與發現  移除ribbon支援-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </exclusion>
    </exclusions>
</dependency>

注意:

  • nacos-discovery中引入了ribbon,需要移除ribbon的包
  • 如果不移除,也可以在yml中配置不使用ribbon
spring:
  application:
    name: order-server
  cloud:
    nacos:
      server-addr: 127.0.0.1:8848
      discovery:
        username: nacos
        password: macos
        namespace: 6325e312-7f95-48d7-8d06-810047ed3956
    # 不使用ribbon
    loadbalancer:
      ribbon:
        enabled: false

原理:預設情況下,如果同時擁有RibbonLoadBalancerClient和BlockingLoadBalancerClient,為了保持向後相容性,將使用RibbonLoadBalancerClient。要覆蓋它,可以設定spring.cloud.loadbalancer.ribbon.enabled屬性為false。

2.2 使用@LoadBalanced註解配置RestTemplate

@Configuration
public class RestConfig {
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

2.3 使用

package com.xiexie.order.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.loadbalancer.reactive.ReactorLoadBalancerExchangeFilterFunction;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

/**
 * @Description
 * @Date 2022-04-07 14:46
 * @Author xie
 */
@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private WebClient webClient;

    @Autowired
    private ReactorLoadBalancerExchangeFilterFunction lbFunction;

    @RequestMapping("/add")
    public String add() {
        System.out.println("下單成功");

        //String msg = restTemplate.getForObject("http://localhost:8011/stock/reduct", String.class);

        String msg = restTemplate.getForObject("http://stock-server/stock/reduct", String.class);

        // 基於WebClient
        Mono<String> bodyToMono = webClient.get().uri("http://stock-server/stock/reduct").retrieve().bodyToMono(String.class);

        // 基於WebClient+webFlux
        Mono<String> stringMono = WebClient.builder()
                .filter(lbFunction)
                .build()
                .get()
                .uri("http://stock-server/stock/reduct")
                .retrieve()
                .bodyToMono(String.class);


        return "Hello order add " + msg;
    }

}

3. WebClient整合LoadBalance

3.1 引入依賴

<!-- LoadBalancer -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

<!-- webflux -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

<!-- nacos服務註冊與發現 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </exclusion>
    </exclusions>
</dependency>

3.2 配置WebClient作為負載均衡器的client

@Configuration
public class WebClientConfig {

    @LoadBalanced
    @Bean
    WebClient.Builder webClientBuilder() {
        return WebClient.builder();
    }

    @Bean
    WebClient webClient() {
      return webClientBuilder().build();
    }
}

3.3 使用(WebClient、WebClient + webFlux)

package com.xiexie.order.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.loadbalancer.reactive.ReactorLoadBalancerExchangeFilterFunction;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

/**
 * @Description
 * @Date 2022-04-07 14:46
 * @Author xie
 */
@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private WebClient webClient;

    @Autowired
    private ReactorLoadBalancerExchangeFilterFunction lbFunction;

    @RequestMapping("/add")
    public String add() {
        System.out.println("下單成功");

        //String msg = restTemplate.getForObject("http://localhost:8011/stock/reduct", String.class);

        String msg = restTemplate.getForObject("http://stock-server/stock/reduct", String.class);

        // 基於WebClient
        Mono<String> bodyToMono = webClient.get().uri("http://stock-server/stock/reduct").retrieve().bodyToMono(String.class);

        // 基於WebClient+webFlux
        Mono<String> stringMono = WebClient.builder()
                .filter(lbFunction)
                .build()
                .get()
                .uri("http://stock-server/stock/reduct")
                .retrieve()
                .bodyToMono(String.class);


        return "Hello order add " + msg;
    }

}

原理: 底層會使用ReactiveLoadBalancer