• 使用 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

  • 相关阅读:
    性能评测|影驰RTX4090金属大师系列显卡正式发售!
    【Linux系统编程】进程程序替换、exec系列替换函数
    [moeCTF 2023] REV
    【Proteus仿真】【STM32单片机】出租车计价器
    [附源码]计算机毕业设计数字乡村基础治理系统Springboot程序
    [附源码]Python计算机毕业设计高校国防教育管理系统
    Docker轻量级可视化监控工具Portainer的使用
    普通Java工程可执行JAR两种打包方式探讨
    Unity Game FrameWork—模块使用—资源热更新
    ElasticSearch--线程池(ThreadPool)--使用/设置
  • 原文地址:https://www.cnblogs.com/greyzeng/p/16892071.html