Spring Cloud LoadBalancer(负载均衡)

news2024/12/28 6:00:55

简介

了解过Spring Cloud,就知道,之前Spring Cloud中默认的负载均衡组件为ribbon,ribbon是Netflix开源的组件,但是目前已经停止更新了。所以Spring官方推出了Spring Cloud LoadBalancer。而且Spring Cloud LoadBalancer是目前唯一的负载均衡组件。

示例

文件承接前篇的示例,需要的请移步 Spring Cloud alibaba 使用Nacos服务发现

服务端

修改一下TestController

    @RequestMapping("getCommonConf")
    public String getCommonConf(HttpServletRequest request) {
        System.out.println(conf);
        return this.conf.toString() + request.getServerPort();
    }

就在Controller里面打印了一下当前的端口。

启动

我们这次启动两个Provider的代码,端口分别为8701和8702

idea中同一个项目多次启动配置

在这里插入图片描述
在这里插入图片描述
勾上它就可以了

注意启动的时候使用不同的端口就行了。

消费端Consumer

我们使用@LoadBalanced的配置示例

package com.yyoo.cloud.conf;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class ConsumerConf {

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

}

package com.yyoo.cloud.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@RequestMapping("consumer")
public class ConsumerController {
    
    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/getMyCloudConf")
    public String getMyCloudConf(){
        return restTemplate.getForObject("http://myCloud/myCloud/conf/getCommonConf",String.class);
    }

}

消费端我们启动端口修改为8703

查看Nacos界面

两个服务端和一个客户端都启动之后,查看Nacos的服务菜单
在这里插入图片描述

客户端调用

访问:http://localhost:8703/myCloud/consumer/getMyCloudConf
在这里插入图片描述

多刷新几次,你会发现,打印出的端口在8701和8702之间转换,而且是轮流转换。

ReactiveLoadBalancer

Spring Cloud LoadBalancer中使用ReactiveLoadBalancer接口提供负载均衡的实现,目前只有两个实现:

  • RoundRobinLoadBalancer:轮询(默认)
  • RandomLoadBalancer:随机

在负载均衡策略的实现上,Spring Cloud LoadBalancer确实比ribbon少很多,不知后续官方会不会添加更多的可选策略,当然如果这些策略不够我们使用,我们也可以自己定义的,比如Nacos就自定义了一个实现NacosLoadBalancer。

RoundRobinLoadBalancer

其源码中就一句关键的代码

ServiceInstance instance = instances.get(pos % instances.size());

pos大家可以认为是当前的访问次数,instances.size()是我们的Provider实例的个数,后面的我想不用多解释了。

RandomLoadBalancer

关键代码

		int index = ThreadLocalRandom.current().nextInt(instances.size());

		ServiceInstance instance = instances.get(index);

也不用过多解释了吧

可以看到,我们的负载均衡的实现就是如此的简单。

修改默认的LoadBalancer

配置RandomLoadBalancer

package com.yyoo.cloud.conf;

import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.core.RandomLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;

public class MyLoadBalancerConfiguration {

    @Bean
    ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,
                                                            LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new RandomLoadBalancer(loadBalancerClientFactory
                .getLazyProvider(name, ServiceInstanceListSupplier.class),
                name);
    }

}

注意:我们的配置类上没有添加@Configuration等注解

在RestTemplate配置中修改代码

package com.yyoo.cloud.conf;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
@LoadBalancerClient(value = "myCloud", configuration = MyLoadBalancerConfiguration.class)
public class ConsumerConf {

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

}

其实就是增加了@LoadBalancerClient注解,value属性是我们的Provider的spring.cloud.nacos.discovery.service,spring.cloud.nacos.discovery.service的默认值是spring.application.name。configuration 就是我们的配置类。

再次尝试访问

访问:http://localhost:8703/myCloud/consumer/getMyCloudConf

多次刷新,你会发现,打印出的端口在8701和8702之间不再是轮流转换,而是随机转换了。

@LoadBalancerClients

上面我们提到了@LoadBalancerClient注解,仔细想想,就会发现,@LoadBalancerClient注解有个问题,那就是value属性需要指定,这意味着我们每个@LoadBalancerClient注解能指定某一个Provider使用我们自定义的负载均衡策略,而不能指定默认的策略。

我们再定义一个NacosLoadBalancer

package com.yyoo.cloud.conf;

import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.loadbalancer.NacosLoadBalancer;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;

import javax.annotation.Resource;

public class MyNacosLoadBalancerConfiguration {

    @Resource
    private NacosDiscoveryProperties nacosDiscoveryProperties;

    @Bean
    ReactorLoadBalancer<ServiceInstance> myNacosLoadBalancer(Environment environment,
                                                            LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new NacosLoadBalancer(loadBalancerClientFactory
                .getLazyProvider(name, ServiceInstanceListSupplier.class),
                name,nacosDiscoveryProperties);
    }

}

修改RestTemplate配置类

package com.yyoo.cloud.conf;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
@LoadBalancerClients(value = {
        @LoadBalancerClient(value = "myCloud1", configuration = MyLoadBalancerConfiguration.class)
},defaultConfiguration = MyNacosLoadBalancerConfiguration.class)
public class ConsumerConf {

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

}

我们在@LoadBalancerClients中配置了一个@LoadBalancerClient,对应Provider名称为myCloud1,目前我们的示例中没有该Provider,这没有关系,如果有,它将使用我们的随机负载均衡策略。我们还配置了一个defaultConfiguration ,使用的是NacosLoadBalancer。我们目前调用的Provider的名称为myCloud,所以在调用我们之前的接口时,将使用NacosLoadBalancer。

NacosLoadBalancer

调用上面的示例之后你会发现,好像我们的结果跟随机的负载均衡策略差不多,是不是NacosLoadBalancer也是随机的负载均衡呢?

NacosLoadBalancer源码如下

package com.alibaba.cloud.nacos.loadbalancer;

import java.util.List;
import java.util.stream.Collectors;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.balancer.NacosBalancer;
import com.alibaba.nacos.client.naming.utils.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.DefaultResponse;
import org.springframework.cloud.client.loadbalancer.EmptyResponse;
import org.springframework.cloud.client.loadbalancer.Request;
import org.springframework.cloud.client.loadbalancer.Response;
import org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;

/**
 * see original.
 * {@link org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer}
 *
 * @author XuDaojie
 * @since 2021.1
 */
public class NacosLoadBalancer implements ReactorServiceInstanceLoadBalancer {

	private static final Logger log = LoggerFactory.getLogger(NacosLoadBalancer.class);

	private final String serviceId;

	private ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;

	private final NacosDiscoveryProperties nacosDiscoveryProperties;

	public NacosLoadBalancer(
			ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider,
			String serviceId, NacosDiscoveryProperties nacosDiscoveryProperties) {
		this.serviceId = serviceId;
		this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
		this.nacosDiscoveryProperties = nacosDiscoveryProperties;
	}

	@Override
	public Mono<Response<ServiceInstance>> choose(Request request) {
		ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider
				.getIfAvailable(NoopServiceInstanceListSupplier::new);
		return supplier.get().next().map(this::getInstanceResponse);
	}

	private Response<ServiceInstance> getInstanceResponse(
			List<ServiceInstance> serviceInstances) {
		if (serviceInstances.isEmpty()) {
			log.warn("No servers available for service: " + this.serviceId);
			return new EmptyResponse();
		}

		try {
			String clusterName = this.nacosDiscoveryProperties.getClusterName();

			List<ServiceInstance> instancesToChoose = serviceInstances;
			if (StringUtils.isNotBlank(clusterName)) {
				List<ServiceInstance> sameClusterInstances = serviceInstances.stream()
						.filter(serviceInstance -> {
							String cluster = serviceInstance.getMetadata()
									.get("nacos.cluster");
							return StringUtils.equals(cluster, clusterName);
						}).collect(Collectors.toList());
				if (!CollectionUtils.isEmpty(sameClusterInstances)) {
					instancesToChoose = sameClusterInstances;
				}
			}
			else {
				log.warn(
						"A cross-cluster call occurs,name = {}, clusterName = {}, instance = {}",
						serviceId, clusterName, serviceInstances);
			}

			ServiceInstance instance = NacosBalancer
					.getHostByRandomWeight3(instancesToChoose);

			return new DefaultResponse(instance);
		}
		catch (Exception e) {
			log.warn("NacosLoadBalancer error", e);
			return null;
		}

	}

}

其最重要的方法就是getInstanceResponse

实际上NacosLoadBalancer的负载均衡策略为:取同一个集群(相同的clusterName)下Provider实例,然后根据实例的weight(权重,默认1.0)配置进行负载均衡。

Provider的权重配置为:spring.cloud.nacos.discovery.weight。

修改权重再验证

比如我们修改8701的Provider权重为10,再次测试

多试几次,8701出现的次数一定比8702的多

既然我们使用Nacos做注册发现,那么没有特殊要求的情况下,建议使用NacosLoadBalancer。

LoadBalancer的缓存设置

Spring Cloud LoadBalancer提供了两种缓存实现

  • 默认
  • caffeine支持的实现

要使用caffeine支持的实现,需要将其相关依赖添 com.github.ben-manes.caffeine:caffeine 加到项目中即可。当然相应的配置也需要使用caffeine的配置。

修改默认缓存配置

# 缓存过期时间,默认是35s
spring.cloud.loadbalancer.cache.ttl=35s
# 缓存的容量,默认是256
spring.cloud.loadbalancer.cache.capacity=256

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/140682.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

win11下通过qemu 安装win10 arm系统

安装qemu QEMU for Windows – Installers (64 bit) 我选了最新的20221230的版本&#xff0c;我将其安装在c:\qemu7\下&#xff0c;另外在环境变量中加入这个路径 然后在别的盘上建立一个路径&#xff0c;名称随意&#xff0c;不要有中文和空格即可&#xff0c;我放在了e:\qe…

电脑蓝屏提示错误代码0X000000B4怎么办?

电脑蓝屏可以说是Windows的一个常见问题了。蓝屏状况数不胜数&#xff0c;关键还得看是何终止代码。 如果电脑蓝屏&#xff0c;提示错误代码0X000000B4是什么意思&#xff1f;这是由于Windows不能启动显卡驱动&#xff0c;从而无法进入图形界面。 蓝屏错误0X000000B4可能由驱…

docker搭建redis集群(Cluster版三主三从)

docker搭建redis集群(Cluster版三主三从编写脚步建立配置redis的配置文件启动六个redis服务创建cluster集群测试集群的高可用编写脚步建立配置redis的配置文件 建立配置文件脚本 vim redis.shfor port in $(seq 1 6); \ do \ mkdir -p /volumn/redis/node-${port}/conf touch…

怎么修复老照片?这三个修复方法让你轻松学会

大家在翻看以前的照片时&#xff0c;有没有发现有一些照片的颜色泛黄&#xff0c;内容也变得有些模糊不清了&#xff0c;遇到这种情况应该怎么办呢&#xff1f;不知道的小伙伴也不要着急&#xff0c;今天我就给大家分享几个模糊老照片修复教程&#xff0c;教会大家如何修复老照…

一直没明白的 HTTPS,今天必须让你懂了~

大家第一次接触 HTTPS 协议的时候是不是和我一样&#xff0c;非常困惑。 这玩意概念又多又繁琐。尤其是里面的公钥私钥啥的。 当时就特别想知道&#xff0c;为什么用公钥加密却不能用公钥解密&#xff1f; 看完这篇文章你会弄明白&#xff0c;同时还会解锁很多HTTPS里的细节…

1.所有被new出来的实例都是存放在堆里的吗?Android面经

问题&#xff1a; 所有被new出来的实例都是存放在堆里的吗&#xff1f; 相关知识点&#xff1a; 堆和栈、标量替换、栈上分配、逃逸分析 思考&#xff1a; 首先&#xff0c;这样问了&#xff0c;答案肯定是不是所有new出来的实例都存放在堆里&#xff0c;不然下面没法继续问了…

MODBUS转PROFINET网关在冷水机项目中应用

在电镀行业中&#xff0c;需要频繁用到冷水机&#xff0c;电镀产品在焊接过程中会产生大量的热量&#xff0c;这些热量若不及时散除&#xff0c;则有可能会导致待加工的电镀产品发生大变形&#xff0c;本案例的目的是通过微硬创新MODBUSRTU转PROFINET网关连接冷水机和PLC&#…

安卓玩机搞机技巧综合资源-----修复基带 改串码 基带qcn 改相关参数 终结贴

有需要了解这方面常识的友友梦可以先参阅我这几个帖子 请点击跳转 基带qcn的备份与写入相关 格机 nv报错 高通联机修改IMEI等参数的相关解析 关于高通QPST平台功能和选项的一些简单说明 基带qcn的备份与写入相关 格机 nv报错 以上几个帖子可以初步了解基带 串码等参数方面…

面试官:如何用Excel进行预测分析?这操作绝了!

【面试题】一个社交APP, 它的新增用户次日留存、7日留存、30日留存分别是52%、25%、14%。请模拟出来&#xff0c;每天如果日新增6万用户&#xff0c;那么第30天&#xff0c;它的日活数会达到多少&#xff1f;请使用Excel进行分析。【分析思路】第1日(次日)留存用户数第1日新增用…

筛选用户权限子集记录

【问题】Is there a way to use the $map operator in a regular Mongo document query (or aggregate \$match which I believe is the same thing).What I’m trying to do is thus: Given an set of sets, return the document if any of the sets is a subset of a paramet…

SpringBoot+VUE前后端分离项目学习笔记 - 【12 Vue使用路由】

整体代码结构 Manage.vue HomeView.vue改名为Manage.vue,用以管理其他view页面【通过import 】 <template><el-container style"min-height: 100vh"><el-aside :width"sideWidth px" style"box-shadow: 2px 0 6px rgb(0 21 41 / 3…

年终盘点:元宇宙产业委多项成果荣登元宇宙行业影响力榜单

在经过了2021年元宇宙概念落地和普及后&#xff0c;2022年成为元宇宙相关产业井喷式发展的一年。元宇宙产业委在2022年多项成果荣登行业影响力榜单。 2021-2022元宇宙科技传播图书影响力榜发布&#xff0c;元宇宙产业委好书上榜 2022年9月&#xff0c;两办印发《关于新时代进一…

Internet Download Manager2023最新永久版下载及功能介绍

提到下载工具&#xff0c;大多数国人映入脑海的或许是迅雷。没错&#xff0c;当今随着互联网的迅猛发展&#xff0c;不少早期积累大量用户的国内外下载工具尽显疲态&#xff0c;止步不前&#xff0c;纷纷掉队&#xff0c;如网络快车、FDM、脱兔等等。一款名叫Internet Download…

Anaconda(python)安装教程以及创建新环境

文章目录一. Anaconda简介二. Anacoda安装1. Anacondad下载2. 安装方式三.通过conda创建新的环境四.conda常用命令一. Anaconda简介 Anaconda介绍&#xff1a;开源的Python发行版本。Anaconda指的是一个开源的Python发行版本&#xff0c;其包含了conda、Python等180多个科学包…

make_shared与new

假设有这么个类&#xff1a; class A {private:int b;public:A(int c):b(c) { cout << "call constructor..." << endl;}~A() { cout << "call destructor..." << endl;}int getValue() { return b;} }; 当创建指向 A 对象的智能…

【测绘程序设计】——附合导线近似平差

附合导线(Connecting Traverse,CT)近似平差是测绘专业九大核心专业基础课——《数字地形测量学》中的重点内容,其程序设计也是测绘学子必修的课程设计之一。本文分享了测绘程序设计——附合导线近似平差(C++/MFC版),相关源代码(完整工程,包含测试数据)及使用示例(结果…

CLion开发环境的完全解析(QT开发?STM32?顺便速通cmake

文章目录下载与安装主题推荐编辑器与clang-format设置鼠标滚轮改变字体大小clang-format的使用我的 .clang-format 配置编译工具链设置编译工具链的添加与解释cmake配置项的添加与解释cmake的使用与实战常用的cmake变量&#xff08;入门&#xff09;常用的cmake命令&#xff08…

融合通信系统建设建议(华脉智联内参一)

各行业融合通信系统建设建议 让通信融合信息无阻 题记&#xff1a;目前各个行业都已建设了视频监控系统、内部电话系统、无线对讲机系统、公共广播系统、会场音频系统、视频会议系统等。这些通信系统各自解决不同的用户需求&#xff0c;随着技术的发展&#xff0c;以及融合通信…

腾讯安全连续三年列为Gartner在线反欺诈市场指南全球代表厂商

近日&#xff0c;全球研究机构Gartner发布了2022《在线反欺诈市场指南》&#xff08;Market Guide for Online Fraud Detection&#xff09;。腾讯安全凭借天御&#xff08;TenDI&#xff09;金融风控被列为全球代表性厂商&#xff0c;这也是腾讯安全连续第三次被列入该报告。随…

洛谷千题详解 | P1031 [NOIP2002 提高组] 均分纸牌【C/C++、pascal、Java语言】

博主主页&#xff1a;Yu仙笙 专栏地址&#xff1a;洛谷千题详解 目录 题目描述 输入格式 输出格式 输入输出样例 解析&#xff1a; C源码&#xff1a; pascal源码&#xff1a; pascal源码2&#xff1a; Java源码&#xff1a; ------------------------------------------------…