Spring Cloud loadBalancer使用

使用loadbalancer

springcloud-2020.0.*版本后逐渐移除了netflix的组件(ribbon, hystrix),现在SpringCloud不是与某一个类库绑定,而是提供了一套抽象,这样就可以在保持接口不变的情况下切换实现方案,新版本负载算法使用loadbalancer实现


切换负载算法

  • 默认负载算法 RoundRobinLoadBalancer
@Configuration(proxyBeanMethods = false)
@ConditionalOnDiscoveryEnabled
public class LoadBalancerClientConfiguration {

	private static final int REACTIVE_SERVICE_INSTANCE_SUPPLIER_ORDER = 193827465;

	@Bean
	@ConditionalOnMissingBean
	public ReactorLoadBalancer reactorServiceInstanceLoadBalancer(Environment environment,
			LoadBalancerClientFactory loadBalancerClientFactory) {
		String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
		return new RoundRobinLoadBalancer(
				loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
	}
  • 模仿 RoundRobinLoadBalancer 写自定义的负载均衡类
public class MyLoadBalancer implements ReactorServiceInstanceLoadBalancer {

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

	final AtomicInteger position;

	/**轮询间隔*/
	final Integer interval = 3;

	final String serviceId;

	ObjectProvider serviceInstanceListSupplierProvider;

	public MyLoadBalancer(ObjectProvider serviceInstanceListSupplierProvider,
			String serviceId) {
		this(serviceInstanceListSupplierProvider, serviceId, new Random().nextInt(1000));
	}

	public MyLoadBalancer(ObjectProvider serviceInstanceListSupplierProvider,
			String serviceId, int seedPosition) {
		this.serviceId = serviceId;
		this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
		this.position = new AtomicInteger(seedPosition);
	}

	@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 pos = this.position.incrementAndGet() & Integer.MAX_VALUE;

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

		log.info("instance:"+instance.getInstanceId());

		return new DefaultResponse(instance);
	}
}
  • 自定义负载配置类
public class MybanlancerConfiguration {

	/**
	 * 自定义负载
	 * @author Noodles
	 * @date 2022/5/24 21:40
	 */
	@Bean
	ReactorLoadBalancer myloadBalancer(Environment environment,
			LoadBalancerClientFactory loadBalancerClientFactory) {
		String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
		return new MyLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class),
				name);
	}

}

如果要提供自定义的ServiceInstanceListSupplier 就在此类中加入自定义的bean即可,如下所示

   @Bean
    public ServiceInstanceListSupplier myDiscoveryClientServiceInstanceListSupplier(
            ConfigurableApplicationContext context) {
        return ServiceInstanceListSupplier.builder().withDiscoveryClient().build(context);
    }
  • 配置自定义负载均衡的服务,其中 "NOODLES_PROVIDER" 为注册到注册中心的serviceId
@Configuration
@LoadBalancerClients(value = {
		@LoadBalancerClient(name = "NOODLES-PROVIDER", configuration = MybanlancerConfiguration.class) })
public class LoadBalanceConfig {

	Logger logger = LoggerFactory.getLogger(LoadBalanceConfig.class);

	@LoadBalanced
	@Bean
	WebClient.Builder webClientBuilder() {
		return WebClient.builder();
	}
}


代码实现

  • spring-cloud-parent -> noodles-consumer
  • spring-cloud-parent -> spring-cloud-mygateway

参考资料

  • https://docs.spring.io/spring-cloud-commons/docs/current/reference/html/#spring-cloud-loadbalancer

扩展知识

  • Spring 接口 BeanPostProcessor
  • 代理设计模式
发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章