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

作者:Grey

原文地址:

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

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

背景

Spring Cloud G 版发布时提到,

Spring Cloud Netflix 那套组件很多都进入了维护期,如下表所示

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

针对 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 配置

流程

整个过程如下示例图

注: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<List<ServiceInstance>> 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<String> 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<String> 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,配置方式如下

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

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

完整代码

见:spring-cloud-loadbalancer-usage

参考文档

Spring Cloud Greenwich.RELEASE is now available

Client-Side Load-Balancing with Spring Cloud LoadBalancer

使用 Spring Cloud LoadBalancer 实现客户端负载均衡的更多相关文章

  1. 服务注册发现Eureka之三:Spring Cloud Ribbon实现客户端负载均衡(客户端负载均衡Ribbon之三:使用Ribbon实现客户端的均衡负载)

    在使用RestTemplate来消费spring boot的Restful服务示例中,我们提到,调用spring boot服务的时候,需要将服务的URL写死或者是写在配置文件中,但这两种方式,无论哪一 ...

  2. Spring Cloud Ribbon实现客户端负载均衡

    1.构建microservice-consumer-movie-ribbon项目,在pom.xml中引入ribbon依赖 在引入Eureka依赖的时候,默认里面含有ribbon依赖 2.添加@Load ...

  3. Spring Cloud 客服端负载均衡 Ribbon

    一.简介   Spring Cloud Ribbon 是一个基于Http和TCP的客服端负载均衡工具,它是基于Netflix Ribbon实现的.它不像服务注册中心.配置中心.API网关那样独立部署, ...

  4. Spring Cloud - 切换Ribbon的负载均衡模式

    Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现.通过Spring Cloud的封装,可以让我们轻松地将面向服务的REST模 ...

  5. 2.【Spring Cloud Alibaba】实现负载均衡-Ribbon

    负载均衡的两种方式 如何实现负载均衡 目前已经实现让A总能找到B,如何实现负载均衡 负载均衡的两种方式 服务器端负载均衡 客户端负载均衡 使用Ribbo实现负载均衡 Ribbon是什么 ==Netfl ...

  6. Spring Cloud微服务Ribbon负载均衡/Zuul网关使用

    客户端负载均衡,当服务节点出现问题时进行调节或是在正常情况下进行 服务调度.所谓的负载均衡,就是当服务提供的数量和调用方对服务进行 取舍的调节问题,在spring cloud中是通过Ribbon来解决 ...

  7. 4.Spring Cloud初相识--------Feign负载均衡

    前言: 在上一节里,我们学习了ribbon的使用. 我们了解到ribbon是一个客户端负载均衡机制. 而我们今天要讲的Feign呢,也是一款客户端负载均衡机制. 或者这样说,Feign封装了ribbo ...

  8. 撸一撸Spring Cloud Ribbon的原理-负载均衡策略

    在前两篇<撸一撸Spring Cloud Ribbon的原理>,<撸一撸Spring Cloud Ribbon的原理-负载均衡器>中,整理了Ribbon如何通过负载均衡拦截器植 ...

  9. Spring Cloud Gateway Ribbon 自定义负载均衡

    在微服务开发中,使用Spring Cloud Gateway做为服务的网关,网关后面启动N个业务服务.但是有这样一个需求,同一个用户的操作,有时候需要保证顺序性,如果使用默认负载均衡策略,同一个用户的 ...

  10. 【Spring Cloud学习之三】负载均衡

    环境 eclipse 4.7 jdk 1.8 Spring Boot 1.5.2 Spring Cloud 1.2 主流的负载均衡技术有nginx.LVS.HAproxy.F5,Spring Clou ...

随机推荐

  1. Linux系统启动报错No bootable device解决步骤

    CSDN文章地址点击此处 磁盘的 MBR 表损坏 实验环境准备工作 查看分区类型及磁盘位置信息点击此篇 首先备份虚拟机A上的 MBR 表 dd if=/dev/vda of=MBR bs=512 co ...

  2. [DOM]获取元素:根据ID、标签名、HTML5新增的方法、特殊元素获取

    目录 [DOM]获取元素:根据ID.标签名.HTML5新增的方法.特殊元素获取 1.根据 ID 获取[.getElementById( )] 2.根据标签名获取[.getElementsByTagNa ...

  3. C++程序的内存分布

    4.文字常量区: p与p1的指针地址一致,且字符串常量是不能被改变的. 5.程序代码区:存放一系列代码. 动态内存 1.按需分配,根据需要分配内存,不浪费. 内存拷贝函数 void *memcpy(v ...

  4. win10系统应用商店打开后无法联网 代码: 0x80131500 的解决办法

    官方提供的建议网址: https://answers.microsoft.com/zh-hans/windows/forum/all/代码/cbbe7aaf-8f66-4779-89c8-3c74f5 ...

  5. rpm,docker,k8s三种方式安装部署GitLab服务

    rpm方式 源地址:https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/ wget https://mirrors.tuna.tsinghua ...

  6. 2_CSS

    1. 什么是CSS 1.1 什么是CSS Cascading Style Sheet 层叠样式表 是一种用来表现HTML(标准通用标记语言的一个应用)或XML(标准通用标记语言的一个子集)等文件样式的 ...

  7. 改善C#程序的方法-1 操作字符串

    正确操作字符串 引言: 字符串是使用很频繁的一种数据类型. 如果使用不慎,则会为一次字符串操作所带来的额外性能开销而付出代价. 下面从这几个方面来探讨如何正确操作字符串: 1.确保尽量少的装箱,尽可能 ...

  8. PHP全栈开发(八):CSS Ⅵ 列表 style

    列表分为有序列表和无序列表 我们知道有序列表的标签是<ol>意思是order list 无序列表的标签是<ul> 列表里面每项的标签用<li>来进行包裹. 使用CS ...

  9. 220722 T3 石子染色 (背包)

    序列s中的数就是要选的堆的编号,假设要选的有i个石子,这i个染为红色,剩下j个染为蓝色,i+j=x,i=x-j,那么对答案的贡献是|x-2j|.那么只要我们选的有i个石子,贡献就是这么多,所以我们可以 ...

  10. 使用FreeMarker配置动态模板

    FreeMarker动态模板 目录 FreeMarker动态模板 前言 准备工作 FreeMarker 代码构建 项目结构 创建 Configuration 实例 调用 模板文件 调用结果 Tips ...