简介

了解过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@Beanpublic 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 {@Autowiredprivate 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 {@BeanReactorLoadBalancer<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@Beanpublic 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 {@Resourceprivate NacosDiscoveryProperties nacosDiscoveryProperties;@BeanReactorLoadBalancer<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@Beanpublic 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;}@Overridepublic 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

Spring Cloud LoadBalancer(负载均衡)相关推荐

  1. Spring Cloud的负载均衡Spring Cloud Ribbon和Spring Cloud Feign

    一.客户端负载均衡:Spring Cloud Ribbon. Spring Cloud Ribbon是基于HTTP和TCP的客户端负载工具,它是基于Netflix Ribbon实现的.通过Spring ...

  2. Spring Cloud Ribbon 负载均衡客户端调用示例

    承接 Spring Cloud 最简入门示例 这一篇, 本篇演示如何使用负载均衡客户端 Ribbon 调用在Eureka注册的服务. Ribbon 是什么? Ribbon是Netflix 的开源项目, ...

  3. 【Spring Cloud】负载均衡-Ribbon

    1. 什么是Ribbon Spring cloud 的服务有两种消费者,ribbon 是其中之一,它是一个负载均衡客户端,可以很好的控制http 和 tcp 的一些行为. Ribbon 是Netfli ...

  4. Spring Cloud Ribbon负载均衡策略详解

    通过之前的文章可以知道, Ribbon负载均衡器选择服务实例的方式是通过"选择策略"实现的, Ribbon实现了很多种选择策略,UML静态类图如上图. IRule是负载均衡的策略接 ...

  5. 客户端负载均衡Ribbon之一:Spring Cloud Netflix负载均衡组件Ribbon介绍

    Netflix:['netfliːks] ribbon:英[ˈrɪbən]美[ˈrɪbən] n. 带; 绶带; (打印机的) 色带; 带状物; v. 把-撕成条带; 用缎带装饰; 形成带状;     ...

  6. Spring Cloud Feign 负载均衡

    一.Feign负载均衡介绍 Feign本身集成了Ribbon依赖和自动配置,因此不需要额外引入依赖,也不需要再注册RestTemplate对象 Feign内置的ribbon默认设置了请求超时时长,默认 ...

  7. Spring Cloud Alibaba 负载均衡:Ribbon 如何保证微服务的高可用

    上一讲我们对 Nacos 的集群环境与实现原理进行了讲解,我们已经可以轻松将单个微服务接入到 Nacos 进行注册,但是微服务本不是孤岛,如何实现有效的服务间稳定通信是本文即将介绍的主要内容,本次我们 ...

  8. Spring Cloud Ribbon 负载均衡策略

    1.接口 IRule public interface IRule{//选择serverpublic Server choose(Object key);//设置LoadBalancerpublic ...

  9. 【Spring Cloud】OpenFeign和Spring Cloud Loadbalancer调用失败后的重试机制比较

    1 概述 搭建一个微服务系统,有两个服务,Client和Server,Server有三个实例A.B.C,我让Client调用Server,Loadbalancer负载分担默认采用轮询机制,当Serve ...

最新文章

  1. 揭秘大型网站架构进化之路
  2. c语言实现循环单链表
  3. 可伸缩视频编码svc
  4. 孩子觉得数学难?那是底子没打好!
  5. gson 入门_Google GSON入门
  6. oel6mysql_OEL6.5_X86平台部署Oracle 11gR2 RAC并配置ACFS
  7. 算法笔记_面试题_1.爬楼梯
  8. 图像语义分割(14)-FastFCN: 重新思考语义分割模型主干网络中的扩张卷积
  9. MySQL 函数:IF(expr,v1,v2) 判断
  10. 简单的VB进度条程序
  11. XPath之电影天堂数据爬取
  12. pid的matlab仿真,用MATLAB对PID控制做简单的仿真
  13. C语言标准ANSI C、C语言的特点、C语言的关键字(32个)
  14. 显示器扩展后左右如何设置?
  15. 爬取微信公众号发布的所有文章(包括阅读数,在看数,点赞数)
  16. 【算法】图解A* 搜索算法
  17. python中容易被忽视的三个点
  18. android360浏览器卸载,三款主流安卓浏览器横评!删掉APP全靠它?
  19. 华为RS3 封层模型及以太网帧结构
  20. HTK的解码过程的理解又遇到瓶颈了

热门文章

  1. 基于opencv实现人脸猫脸图像检测(python)
  2. 2.学习Vue入门知识点
  3. 巴比特 | 元宇宙每日必读:5年内元宇宙相关产业规模突破800亿元!合肥高新区发布元宇宙产业发展规划...
  4. 北大计算机QS排名,最新QS大学计算机专业排名:MIT斯坦福CMU霸榜,清华北大无缘前十...
  5. 【Aries - Unity入门】第一章 行业与引擎的了解
  6. php面试英文自我介绍范文,英语面试自我介绍范文3分钟
  7. 确认过眼神,你是HPIPS的锦鲤
  8. 军犬舆情:从“马蜂窝事件”看企业品牌舆情监测的重要性
  9. emlog mysql文件,emlog数据库操作类
  10. poj1273(网络流模板)