这里的负载均衡使用,基于RestTemplate。Fegin的负载均衡策略最终也是对其的包装

Ribbon负载均衡-已不在默认集成

服务发现远程调用时地址是服务名, 这个地址是不能真正访问的. 而这解析的过程就是ribbon在起作用

ribbon.jpgRestTemplate使用

通过给RestTemplate bean添加注解@LoadBalanced实现

这个注解是让类LoadBalancerInterceptor生效,实现拦截处理

特别说明

新版本的spring cloud 移除了对ribbon的支持,众所周知,netflix以及停止维护了,所有新版本的spring cloud移除了eureka的其他组件。

目前默认使用的是LoadBalancer

LoadBalancer

从springcloud2020版本开始默认移除了对Ribbon的依赖,官方默认推荐使用Spring Cloud Loadbalancer正式替换Ribbon,并成为了Spring Cloud负载均衡器的唯一实现。

启动方式和核心和ribbon一样。通过注解启动,和类LoadBalancerInterceptor生效。

不过对于LoadBalancerClient在Spring Cloud LoadBalancer中实现类则是BlockingLoadBalancerClient

对于负载均衡的核心类为ReactorServiceInstanceLoadBalancer

1、默认负载均衡策略

     默认实现了如下两种负载均衡策略:

  • RandomLoadBalancer - 随机分配策略

  • (默认) RoundRobinLoadBalancer - 轮询分配策略

2、自定义负载均衡策略

通过ReactorServiceInstanceLoadBalancer的execute方法可知通过choose方法获取到真正调用的实例

1692535555331.pngchoose通过loadBalancerClientFactory获取到serviceId对应到负载均衡策略。再通过具体的负载均衡策略获取到服务实例。默认的loadBalancerClientFactory是LoadBalancerClientFactory

1692535888360.pngloadBalancerClientFactory是springFactory的形式获取bean。每次通过serviceId获取对应的一个context。通过这个context获取符合要求的负载均衡策略。这里是ReactorServiceInstanceLoadBalancer接口类型的bean。

另外在图一中的getSupportedLifecycleProcessors中也会从这个context获取LoadBalancerLifecycle接口的bean,从而实现在负载平衡之前和之后执行的操作。

第一次通过serviceId获取时,对应的context都是不存在的。在创建时会获取serviceId对应配置的configuration,并向这个spring上下文中注册该配置,从而生效预先注册的bean。

image-eeyy.png每个serviceId对应的configuration是一个NamedContextFactory.Specification的接口,其有两个方法如下图, 默认实现是LoadBalancerClientSpecification

	public interface Specification {

       // 对应serviceID
		String getName();
        
        // 注册给spring的bean
		Class<?>[] getConfiguration();

	}

方式一

所以如果要自定义一个负载均衡策略,先要注册一个serviceId对应的NamedContextFactory.Specification。在这个configuration中添加ReactorServiceInstanceLoadBalancer接口的自定义负载均衡策略

/**
 * @author cyp
 * @date 2023-08-20
 */
@Configuration
public class MyRemoteServiceLoadBalancerConfiguration {

    @Bean("remoteService-userService")
    public LoadBalancerClientSpecification myLoadBalancer(){
        LoadBalancerClientSpecification myLoadBalancer = new LoadBalancerClientSpecification();
        myLoadBalancer.setName("user-service");
        myLoadBalancer.setConfiguration(new Class[]{CustomRandomLoadBalancerClient.class});
        return myLoadBalancer;
    }
}

方式二

不直接给自定义的负载均衡策略,而是加载Configuration。例如加载nacos的配置

    @Bean("remoteService-userService")
    public LoadBalancerClientSpecification myLoadBalancer(){
        return new LoadBalancerClientSpecification("user-service", new Class[]{NacosLoadBalancerClientConfiguration.class});
    }

方式三

在启动类,使用@LoadBalancerClient或者@LoadBalancerClients注解,加载自己的配置类,由此切换loadBalancer默认的负载均衡策略.

而通过@LoadBalancerClients的defaultConfiguration 可以全局修改

@LoadBalancerClients(defaultConfiguration = NacosLoadBalancerClientConfiguration.class)