往期回顾
前面我们已经介绍了
Nacos
的安装与配置,以及
Spring Cloud
集成
Nacos
作为服务的注册中心。
Nacos的安装与配置
Spring Cloud集成Nacos作为注册中心
接下来,我们接着上一讲,我们使用
Spring Cloud
自带的
LoadBalacer
来实现负载均衡
负载均衡
负载均衡(Load Balance) ,简单点说就是将用户的请求平摊分配到多个服务器上运行,以达到扩展服务器带宽、增强数据处理能力、增加吞吐量、提高网络的可用性和灵活性的目的。
负载均衡一般分为硬件负载均衡和软件负载均衡,硬件负载均衡因为知识受限,这里不做说明
软件负载均衡又分为:
- 服务端负载均衡服务端的负载均衡就是传统的
Nginx
方式,它的一个特点是调用的客户端不知道具体是哪一个Server提供的服务,只需要将请求发送给Nginx
,再由Nginx
转发给Tomcat
,客户端只需要记住Nginx
的地址即可
- 客户端负载均衡客户端负载均衡是将负载均衡逻辑以代码的形式封装到客户端上,即负载均衡器位于客户端。客户端通过服务注册中心(例如
Eureka``````Nacos
)获取到一份服务端提供的可用服务清单。有了服务清单后,负载均衡器会在客户端发送请求前通过负载均衡算法选择一个服务端实例再进行访问,以达到负载均衡的目的
Ribbon
就是一个很典型的客户端负载均衡器,
Ribbon
是
Netflix
公司发布的开源项目(组件、框架、jar包),主要功能是提供客户端的软件负载均衡算法,它会从注册中心中获取一个可用的服务端清单,通过心跳检测来剔除故障的服务端节点以保证清单中都是可以正常访问的服务端节点
但是,
Ribbon
已经在最新的
Spring Cloud
版本中被废弃,
Spring Cloud Loadbalancer
是官方正式推出的一款新负载均衡利器,在未来,
LoadBalancer
很有可能取代Ribbon的地位成为新一代的负载均衡器
而今天,我们的主角就是
LoadBalancer
,我们将使用它与
Nacos
集成,实现客户端的负载均衡,下面让我们开始愉快的编码吧
构建项目
创建新工程
首先,我们需要在原来的项目基础上再创建一个服务消费者,用于消费,如图所示:
导入依赖
这里需要重点注意一下,**将
Ribbon
的依赖从
Nacos
的依赖中排除**
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId><exclusions><!-- 将ribbon排除 --><exclusion><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-ribbon</artifactId></exclusion></exclusions></dependency><!--添加loadbalancer依赖
由于 Netflix Ribbon 进入停更维护阶段,因此 SpringCloud 2020.0.1 版本之后 删除了eureka中的ribbon,
替代ribbon的是spring cloud自带的LoadBalancer,默认使用的是轮询的方式
新版本的 Nacos discovery 都已经移除了 Ribbon ,此时我们需要引入 loadbalancer 代替,才能调用服务提供者提供的服务
--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency>
配置
application.yml
server:port:7001spring:cloud:nacos:discovery:server-addr: 192.168.199.128
application:name: UserConsumer
profiles:active: dev
management:endpoints:web:exposure:include:"*"
配置LoadBalancer
使用
RestTemplate
与注解的方式配置对应的负载均衡策略
- 创建LoadBalancer配置类
packagecuit.epoch.pymjl.config;importorg.springframework.cloud.client.ServiceInstance;importorg.springframework.cloud.loadbalancer.core.RandomLoadBalancer;importorg.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;importorg.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;importorg.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;importorg.springframework.context.annotation.Bean;importorg.springframework.core.env.Environment;/**
* 注意不要加@Configuration
*
* @author Pymjl
* @version 1.0
* @date 2022/8/26 13:05
**/publicclassMyLoadBalancerConfig{@BeanReactorLoadBalancer<ServiceInstance>randomLoadBalancer(Environment environment,LoadBalancerClientFactory loadBalancerClientFactory){String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);// 随机轮询returnnewRandomLoadBalancer(loadBalancerClientFactory
.getLazyProvider(name,ServiceInstanceListSupplier.class),
name);}}
注意,MyLoadBalancerConfig这里有一个细节大家需要注意一下
- 如果你在
MyLoadBalancerConfig
上面加了@Configuration
注解,使用到的服务必须显式的在启动类上配置好
//假设项目中使用了2个服务,stock-service和product-service//都配置好不会报错@LoadBalancerClients(value ={@LoadBalancerClient(name ="stock-services",configuration =MyLoadBalancerConfig.class),@LoadBalancerClient(name ="product-service",configuration =MyLoadBalancerConfig.class)})//调用stock-service不会报错,调用product-service会报错@LoadBalancerClients(value ={@LoadBalancerClient(name ="stock-services",configuration =MyLoadBalancerConfig.class)
- 如果没有加
@Configuration
注解那么配了的服务会使用配置的负载均衡策略,没有配的服务会使用默认的策略 - 或者将对应的配置类放在
Spring
的扫描包外,效果同第二点一样
- 配置
RestTemplates
packagecuit.epoch.pymjl.config;importorg.springframework.cloud.client.loadbalancer.LoadBalanced;importorg.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.web.client.RestTemplate;/**
* 在这里配置我们自定义的LoadBalancer策略 如果想自己扩展算法 需要实现ReactorServiceInstanceLoadBalancer接口
* /@LoadBalancerClients(defaultConfiguration = {name = "CLOUD-PAYMENT-SERVICE", configuration = MyLoadBalancerConfig.class})
* 注意这里的name属性 需要和Nacos页面中的服务提供者名字一致
*
* @author Pymjl
* @version 1.0
* @date 2022/8/26 12:20
**/@Configuration@LoadBalancerClient(name ="UserService", configuration =MyLoadBalancerConfig.class)publicclassRestTemplateConfig{@Bean@LoadBalancedpublicRestTemplaterestTemplate(){returnnewRestTemplate();}}
编写Controller
packagecuit.epoch.pymjl.controller;importcuit.epoch.pymjl.result.CommonResult;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;importorg.springframework.web.client.RestTemplate;importjavax.annotation.Resource;/**
* @author Pymjl
* @version 1.0
* @date 2022/8/26 12:17
**/@RestController@RequestMapping("/consumer")publicclassTestController{privatestaticfinalString SERVICE_URL ="http://UserService";@ResourceRestTemplate restTemplate;@GetMapping("/test")publicCommonResultconsumerTest(){return restTemplate.getForObject(SERVICE_URL +"/user/test",CommonResult.class);}}
你也可以采用直接使用
LoadBalanceClient
不使用注解的方式(这是我Copy的Nacos官方的样例,使用方法是一样的,就不再演示)
@SpringBootApplication@EnableDiscoveryClientpublicclassNacosConsumerApp{@RestControllerpublicclassNacosController{@AutowiredprivateLoadBalancerClient loadBalancerClient;@AutowiredprivateRestTemplate restTemplate;@Value("${spring.application.name}")privateString appName;@GetMapping("/echo/app-name")publicStringechoAppName(){//使用 LoadBalanceClient 和 RestTemolate 结合的方式来访问ServiceInstance serviceInstance = loadBalancerClient.choose("nacos-provider");String url =String.format("http://%s:%s/echo/%s",serviceInstance.getHost(),serviceInstance.getPort(),appName);System.out.println("request url:"+url);return restTemplate.getForObject(url,String.class);}}//实例化 RestTemplate 实例@BeanpublicRestTemplaterestTemplate(){returnnewRestTemplate();}publicstaticvoidmain(String[] args){SpringApplication.run(NacosConsumerApp.class,args);}}
开始测试
- 我们先启动
UserService
,因为涉及到负载均衡,所以我们需要使用idea配置启动类,启动多个UserService,点击如图所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aNMyQJJi-1662117457388)(https://pymjl.oss-cn-shanghai.aliyuncs.com/picgo/%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE%202022-08-26%20163659.png)]
然后点击启动服务提供者和消费者,如图所示:
调用接口
经过多次刷新后你会发现消费者会随机的去调用服务提供者的服务,两者的概率大概是相同的
项目源码:gitee github
62117457390)]
[外链图片转存中…(img-Z73V2blX-1662117457391)]
经过多次刷新后你会发现消费者会随机的去调用服务提供者的服务,两者的概率大概是相同的
[外链图片转存中…(img-fojNGyVX-1662117457392)]
[外链图片转存中…(img-O63oaM6O-1662117457393)]
项目源码:gitee github
版权归原作者 Pymj 所有, 如有侵权,请联系我们删除。