使用 Spring Cloud Loadbalancer 实现客户端负载均衡
创始人
2024-01-22 00:31:09

使用 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@BeanWebClient.Builder webClientBuilder() {return WebClient.builder();}@Bean@PrimaryServiceInstanceListSupplier serviceInstanceListSupplier() {return new ServiceInstanceListSupplier() {@Overridepublic String getServiceId() {return "server";}@Overridepublic 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

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
ps局部放大 放大某个部位的图... 软件类学习建议:边看边练习,可以先收藏后学习。一、使用Ctrl快捷键放大:Ctrl + +缩小:Ct...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
ps局部放大 放大某个部位的图... 软件类学习建议:边看边练习,可以先收藏后学习。一、使用Ctrl快捷键放大:Ctrl + +缩小:Ct...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...