• 使用 Spring Cloud Loadbalancer 实现客户端负载均衡


    使用 Spring Cloud Loadbalancer 实现客户端负载均衡

    作者:Grey

    原文地址:

    博客园:使用 Spring Cloud Loadbalancer 实现客户端负载均衡

    CSDN:使用 Spring Cloud Loadbalancer 实现客户端负载均衡

    背景#

    Spring Cloud G 版发布时提到,
    Spring Cloud Netflix 那套组件很多都进入了维护期,如下表所示

    image

    同时,针对一些组件,Spring 官方给出了一些替代方案

    image

    针对 spring-cloud-ribbon 这个负载均衡组件,Spring 官方提出的替换解决方案是 Spring Cloud Loadbalancer。本文主要通过一个示例介绍了 Spring Cloud Loadbalancer 的基础使用。

    环境#

    • JDK 1.8+

    • Maven 3.5+

    • Spring Boot 版本:2.7.5

    • Spring Cloud 版本:2021.0.5

    项目结构和说明#

    • spring-cloud-loadbalanced-usage:父项目名称
      • server : 服务端端模块
        • src/
        • pom.xml
      • client : 客户端模块
        • src/
        • pom.xml
      • pom.xml:父项目 pom 配置

    流程#

    整个过程如下示例图

    image

    注:Spring Cloud Loadbalancer 是在客户端实现负载均衡策略。

    代码说明#

    服务端主要暴露一个服务,未做特殊配置

        @GetMapping("/greeting")
        public String greet() {
            log.info("Access /greeting");
            int randomNum = rand.nextInt(greetings.size());
            return greetings.get(randomNum);
        }
    

    客户端的核心配置如下,主要是针对负载均衡配置:

    package git.snippet.client.config;
    
    import org.springframework.cloud.client.DefaultServiceInstance;
    import org.springframework.cloud.client.ServiceInstance;
    import org.springframework.cloud.client.loadbalancer.LoadBalanced;
    import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
    import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.web.reactive.function.client.WebClient;
    import reactor.core.publisher.Flux;
    
    import java.util.Arrays;
    import java.util.List;
    
    @Configuration
    @LoadBalancerClient(name = "server")
    public class WebClientConfig {
    
        @LoadBalanced
        @Bean
        WebClient.Builder webClientBuilder() {
            return WebClient.builder();
        }
    
        @Bean
        @Primary
        ServiceInstanceListSupplier serviceInstanceListSupplier() {
            return new ServiceInstanceListSupplier() {
                @Override
                public String getServiceId() {
                    return "server";
                }
    
                @Override
                public Flux> get() {
                    return Flux.just(Arrays.asList(
                            new DefaultServiceInstance(getServiceId() + "1", getServiceId(), "localhost", 8090, false),
    
                            new DefaultServiceInstance(getServiceId() + "2", getServiceId(), "localhost", 9092, false),
    
                            new DefaultServiceInstance(getServiceId() + "3", getServiceId(), "localhost", 9999, false)));
                }
            };
        }
    }
    

    其中 @LoadBalancerClient(name = "server") 指定了 服务端的名称;

    getServiceId()指定了服务端的服务 ID;

    serviceInstanceListSupplier()方法中列出了三个服务端实例的地址;

    new DefaultServiceInstance(getServiceId() + "1", getServiceId(), "localhost", 8090, false)
    new DefaultServiceInstance(getServiceId() + "2", getServiceId(), "localhost", 9092, false)
    new DefaultServiceInstance(getServiceId() + "3", getServiceId(), "localhost", 9999, false)
    

    有了这个配置,在客户端的 Controller 中,做如下注入即可

    package git.snippet.client.controller;
    
    import org.springframework.cloud.client.loadbalancer.reactive.ReactorLoadBalancerExchangeFilterFunction;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.reactive.function.client.WebClient;
    import reactor.core.publisher.Mono;
    
    @RestController
    public class HiController {
        private final WebClient.Builder loadBalancedWebClientBuilder;
        private final ReactorLoadBalancerExchangeFilterFunction lbFunction;
    
    
        public HiController(WebClient.Builder loadBalancedWebClientBuilder, ReactorLoadBalancerExchangeFilterFunction lbFunction) {
            this.loadBalancedWebClientBuilder = loadBalancedWebClientBuilder;
            this.lbFunction = lbFunction;
        }
    
        @RequestMapping("/hi")
        public Mono hi(@RequestParam(value = "name", defaultValue = "Mary") String name) {
            return loadBalancedWebClientBuilder.build().get().uri("http://server/greeting").retrieve().bodyToMono(String.class).map(greeting -> String.format("%s, %s!", greeting, name));
        }
    
        @RequestMapping("/hello")
        public Mono hello(@RequestParam(value = "name", defaultValue = "John") String name) {
            return WebClient.builder().filter(lbFunction).build().get().uri("http://server/greeting").retrieve().bodyToMono(String.class).map(greeting -> String.format("%s, %s!", greeting, name));
        }
    }
    
    

    启动并测试#

    首先启动 server,注意:

    启动 server 的时候,需要启动多实例,且每个实例要定义 VM options

    实例一定义 VM options 为 -Dserver.port=8090

    实例二定义 VM options 为 -Dserver.port=9092

    实例三定义 VM options 为 -Dserver.port=9999

    如果使用 IDEA Intellij,配置方式如下

    image

    三个 Server 启动后,接下来启动 client,运行 ClientApplication,启动完毕后,多次访问: http://localhost:8888/hi

    可以通过每个 server 实例的运行日志,查看到每个实例都轮流获取到了请求,实现了负载均衡。

    完整代码#

    见:spring-cloud-loadbalancer-usage

    参考文档#

    Spring Tips: Spring Cloud Loadbalancer

    Spring Cloud Greenwich.RELEASE is now available

    Client-Side Load-Balancing with Spring Cloud LoadBalancer

  • 相关阅读:
    丹青映画董事长唐丹青于元宇宙产业资源对接会上进行精彩演讲
    为什么UI自动化难做?—— 关于Selenium UI自动化的思考
    Linux目录结构详解
    linux shell脚本读取并解析yaml文件
    android的本地通讯录获取以及RecyclerView展示
    逻辑器件与热插拔
    keepalived的通信原理
    番外篇 | 利用华为2023最新Gold-YOLO中的Gatherand-Distribute对特征融合模块进行改进
    网络语言错误是指在编程中出现的错误或故障,导致程序无法正常运行或产生意外的结果
    四氯四碘荧光素二钾,CAS号: 632-68-8
  • 原文地址:https://www.cnblogs.com/greyzeng/p/16892071.html