文章目录

一、简介二、使用LoadBnlancer三、切换策略四、自定义策略

一、简介

在Spring Cloud Nacos 2021以后就没有在默认使用Ribbon作为负载均衡器了,而且在Cloud官网中也推荐使用LoadBnancer作为负载均衡器,他实现了轮询和随机两种方式(RandomLoadBalancer、RoundRobinLoadBalancer),如果引入了NacosDiscovery的话里面还可以使用NacosLoadBnancer的方式。所以接下来我们就来实现一下如何使用LoadBnlancer吧。

二、使用LoadBnlancer

因为本系列是SpringCloudAlibaba系列的一次学习记录,所以使用版本如下,也可以去官网看看最近的版本说明

Spring Cloud Alibaba VersionSentinel VersionNacos VersionRocketMQ VersionDubbo VersionSeata Version2021.0.1.0*1.8.31.4.24.9.22.7.151.4.2

Spring Cloud Alibaba VersionSpring Cloud VersionSpring Boot Version2021.0.1.0Spring Cloud 2021.0.12.6.3

在使用了这些版本后,就不需要像网上说的还需要去排除ribbon的包和在nacos上禁用ribbon。因为该版本本来就没有使用ribbon的依赖。

我们只需要在pom中引入如下依赖

org.springframework.cloud

spring-cloud-starter-loadbalancer

然后在注入的RestTemplateBean上添加@LoadBalanced注解

@Bean

@LoadBalanced

public RestTemplate restTemplate(RestTemplateBuilder builder) {

return builder.build();

}

这时候使用restTemplate进行请求同一个服务的时候就会默认使用LoadBnlancer中的轮询策略(RoundRobinLoadBalancer)了

@GetMapping("/add")

public String add() {

log.info("添加商品!");

String reduce = restTemplate.getForObject("http://stock-service/stock/reduce", String.class);

return "添加商品成功." + reduce;

}

三、切换策略

LoadBnlancer除了默认的轮询策略外还提供了随机策略RandomLoadBalancer,如果你使用了nacos的注册发现功能的话,还可以使用spring-cloud-starter-alibaba-nacos-discovery包里的NacosLoadBalancer策略。

首先我们需要创建一个类用来构建RandomLoadBalancer,但是需要注意的是,这个类不能被加载到spring的上下文中,也就是说这个类要么不添加@Configuration之类的注解,要么不在springscan的扫描包之内。

public class LoadBalancerConfig {

@Bean

ReactorLoadBalancer randomLoadBalancer(Environment environment,

LoadBalancerClientFactory loadBalancerClientFactory) {

String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);

return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);

}

}

然后我们需要在启动类上添加注解进行配置

第一种直接使用 @LoadBalancerClients(defaultConfiguration = LoadBalancerConfig.class),意思就是所以的服务都使用我们创建的LoadBalancerConfig中策略,具体见下面的代码

第二种是使用@LoadBalancerClients对不同的服务配置不同的策略,具体见下面的代码

第三种是我们只有一个服务的时候直接使用@LoadBalancerClient配置一个就行。

@SpringBootApplication

// 第一种

// @LoadBalancerClients(defaultConfiguration = LoadBalancerConfig.class)

// 第二种

/** @LoadBalancerClients(value = {

@LoadBalancerClient(name = "stock-service", configuration = LoadBalancerConfig.class),

@LoadBalancerClient(name = "stock-service1", configuration = LoadBalancerConfig1.class)

})*/

// 第三种

@LoadBalancerClient(name = "stock-service", configuration = LoadBalancerConfig.class)

public class OrderApplication {

public static void main(String[] args) {

SpringApplication.run(OrderApplication.class, args);

}

@Bean

@LoadBalanced

public RestTemplate restTemplate(RestTemplateBuilder builder) {

return builder.build();

}

}

当然我们也可以配置NacosLoadBalancer策略。只是需要注入NacosDiscoveryProperties属性,然后对应的换一下对象就行。

public class LoadBalancerConfig {

// 注入当前服务的nacos的配置信息

@Resource

private NacosDiscoveryProperties nacosDiscoveryProperties;

@Bean

ReactorLoadBalancer nacosLoadBalancer(Environment environment,

LoadBalancerClientFactory loadBalancerClientFactory) {

String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);

return new NacosLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name, nacosDiscoveryProperties);

}

}

其实对于NacosLoadBalancer还有一个更加简单配置,如下只有设置为true就会使用NacosLoadBalancer策略,当然这种方式没有上面设置的优先级高。

spring:

application:

name: order-service

cloud:

loadbalancer:

nacos:

enabled: true

四、自定义策略

这个我们就可以模仿RandomLoadBalancer进行修改,直接负责出来完整的代码,修改getInstanceResponse这个方法就行了,然后安装之前将的,将他注入进去就行了。

package com.alibaba.order.config;

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

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.*;

import reactor.core.publisher.Mono;

import java.util.List;

import java.util.concurrent.ThreadLocalRandom;

/**

* @projectName springcloudalibaba-demo

* @title CustomBalancer

* @description

* @date 27/04/2022 10:37

*/

public class CustomBalancer implements ReactorServiceInstanceLoadBalancer {

private static final Log log = LogFactory.getLog(RandomLoadBalancer.class);

private final String serviceId;

private ObjectProvider serviceInstanceListSupplierProvider;

public CustomBalancer(ObjectProvider serviceInstanceListSupplierProvider,

String serviceId) {

this.serviceId = serviceId;

this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;

}

@SuppressWarnings("rawtypes")

@Override

public Mono> choose(Request request) {

ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider.getIfAvailable(NoopServiceInstanceListSupplier::new);

return supplier.get(request).next().map(serviceInstances -> processInstanceResponse(supplier, serviceInstances));

}

private Response processInstanceResponse(ServiceInstanceListSupplier supplier,

List serviceInstances) {

Response serviceInstanceResponse = getInstanceResponse(serviceInstances);

if (supplier instanceof SelectedInstanceCallback && serviceInstanceResponse.hasServer()) {

((SelectedInstanceCallback) supplier).selectedServiceInstance(serviceInstanceResponse.getServer());

}

return serviceInstanceResponse;

}

private Response getInstanceResponse(List instances) {

if (instances.isEmpty()) {

if (log.isWarnEnabled()) {

log.warn("No servers available for service: " + serviceId);

}

return new EmptyResponse();

}

// 这段代码就随机获取的核心 我们可以按照自己的规则来定制

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

ServiceInstance instance = instances.get(index);

return new DefaultResponse(instance);

}

}

--------------最后感谢大家的阅读,愿大家技术越来越流弊!--------------

--------------也希望大家给我点支持,谢谢各位大佬了!!!--------------

相关阅读

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: