Spring Cloud LoadBalancer 源码解析

前言

LoadBalancer(负载均衡器):一种网络设备或软件机制,用于分发传入的网络流量负载到多个后端目标服务器上,依次来提高系统的可用性和性能,Spring Cloud 2020 版本以后,移除了对 Netflix 的依赖,也就移除了负载均衡器 Ribbon,Spring Cloud 官方推荐使用 Loadbalancer 替换 Ribbon,并成为了Spring Cloud负载均衡器的唯一实现。LoadBalancer也可以看做是一种进程级的负载均衡器。

LoadBalancer 引入

LoadBalancer 的引入十分简单,有封装好的 starter ,只需在 pom.xml 中引入依赖即可,如下:

xml 复制代码
<!--引入 LoadBalancer 支持-->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-loadbalancer</artifactId>
	<version>3.0.1</version>
</dependency>

LoadBalancerAutoConfiguration 源码分析

学习 LoadBalancer 源码我们还是从 spring-cloud-starter-loadbalancer 的 spring.factories 文件入手,spring.factories 文件内容如下:

java 复制代码
# AutoConfiguration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.loadbalancer.config.LoadBalancerAutoConfiguration,\
org.springframework.cloud.loadbalancer.config.BlockingLoadBalancerClientAutoConfiguration,\
org.springframework.cloud.loadbalancer.config.LoadBalancerCacheAutoConfiguration,\
org.springframework.cloud.loadbalancer.security.OAuth2LoadBalancerClientAutoConfiguration,\
org.springframework.cloud.loadbalancer.config.LoadBalancerStatsAutoConfiguration

spring.factories 文件中有一个 LoadBalancerAutoConfiguration 类,我们来看看这个类做了什么。

LoadBalancerInterceptorConfig 类源码分析

LoadBalancerAutoConfiguration 类中有一个内部类 LoadBalancerInterceptorConfig,LoadBalancerInterceptorConfig 类是一个负载均衡拦截器配置类,通过 LoadBalancerInterceptorConfig 类完成负载均衡拦截器的配置。

java 复制代码
@Configuration(
	proxyBeanMethods = false
)
@Conditional({LoadBalancerAutoConfiguration.RetryMissingOrDisabledCondition.class})
static class LoadBalancerInterceptorConfig {
	LoadBalancerInterceptorConfig() {
	}
	
	// 创建默认的LB拦截器
	@Bean
	public LoadBalancerInterceptor loadBalancerInterceptor(LoadBalancerClient loadBalancerClient, LoadBalancerRequestFactory requestFactory) {
		return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
	}
	
	//在 restTemplate 中添加 LoadBalancerInterceptor
	//org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration.LoadBalancerInterceptorConfig#restTemplateCustomizer
	@Bean
	@ConditionalOnMissingBean
	public RestTemplateCustomizer restTemplateCustomizer(final LoadBalancerInterceptor loadBalancerInterceptor) {
		return (restTemplate) -> {
			List<ClientHttpRequestInterceptor> list = new ArrayList(restTemplate.getInterceptors());
			list.add(loadBalancerInterceptor);
			restTemplate.setInterceptors(list);
		};
	}
}

有了拦截器,接下来我们来分析拦截器的拦截方法。

LoadBalancerInterceptor#intercept 方法源码分析

LoadBalancerInterceptor#intercept 方法将 request、body、execution 包装成 LoadBalancerRequest,LoadBalancerRequest 做为调用LoadBancerClient#execute 方法的参数。

java 复制代码
//org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor#intercept
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException {
	//获取请求 uri
	URI originalUri = request.getURI();
	//获取 ServiceName
	String serviceName = originalUri.getHost();
	Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
	//将 request  body execution 包装成 LoadBalancerRequest 交给 LoadBalancerClient 执行
	return (ClientHttpResponse)this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution));
}

BlockingLoadBalancerClient#choose 方法源码分析

BlockingLoadBalancerClient#choose 方法主要是获取负载均衡策略,然后获取服务实例,目前负载均衡策略有两种,分别是 RandomLoadBalancer、RoundRobinLoadBalancer,默认是轮训 RoundRobinLoadBalancer。

java 复制代码
//org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient#choose(java.lang.String, org.springframework.cloud.client.loadbalancer.Request<T>)
public <T> ServiceInstance choose(String serviceId, Request<T> request) {
	//根据 serviceId 获取 ReactiveLoadBalancer
	ReactiveLoadBalancer<ServiceInstance> loadBalancer = this.loadBalancerClientFactory.getInstance(serviceId);
	//loadBalancer为空判断
	if (loadBalancer == null) {
		return null;
	} else {
		//不为空 根据负载均衡策略获取服务实例 目前有两种负载均衡策略 RandomLoadBalancer RoundRobinLoadBalancer 默认是轮训  RoundRobinLoadBalancer
		Response<ServiceInstance> loadBalancerResponse = (Response)Mono.from(loadBalancer.choose(request)).block();
		return loadBalancerResponse == null ? null : (ServiceInstance)loadBalancerResponse.getServer();
	}
}

RandomLoadBalancer#choose 方法源码分析

RandomLoadBalancer#choose 方法是负载均衡策略随机算法的实现,随机算法实现很简单,就是根据根据服务实例列表的个数产生随机数,根据随机数获取指定的服务实例返回。

java 复制代码
//org.springframework.cloud.loadbalancer.core.RandomLoadBalancer#choose
public Mono<Response<ServiceInstance>> choose(Request request) {
	//获取服务实例列表
	ServiceInstanceListSupplier supplier = (ServiceInstanceListSupplier)this.serviceInstanceListSupplierProvider.getIfAvailable(NoopServiceInstanceListSupplier::new);
	//遍历使用随机的负载均衡算法得到服务实例
	return supplier.get(request).next().map((serviceInstances) -> {
		return this.processInstanceResponse(supplier, serviceInstances);
	});
}

//org.springframework.cloud.loadbalancer.core.RandomLoadBalancer#processInstanceResponse
private Response<ServiceInstance> processInstanceResponse(ServiceInstanceListSupplier supplier, List<ServiceInstance> serviceInstances) {
	//使用随机的负载算法获取服务实例
	Response<ServiceInstance> serviceInstanceResponse = this.getInstanceResponse(serviceInstances);
	if (supplier instanceof SelectedInstanceCallback && serviceInstanceResponse.hasServer()) {
		((SelectedInstanceCallback)supplier).selectedServiceInstance((ServiceInstance)serviceInstanceResponse.getServer());
	}

	return serviceInstanceResponse;
}

//org.springframework.cloud.loadbalancer.core.getInstanceResponse#choose
private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances) {
	//服务实例为空判断
	if (instances.isEmpty()) {
		if (log.isWarnEnabled()) {
			log.warn("No servers available for service: " + this.serviceId);
		}

		return new EmptyResponse();
	} else {
		//以服务实例的个数来获取随机数
		int index = ThreadLocalRandom.current().nextInt(instances.size());
		//根据随机数获取服务实例
		ServiceInstance instance = (ServiceInstance)instances.get(index);
		//返回服务实例
		return new DefaultResponse(instance);
	}
}

RoundRobinLoadBalancer#choose 方法源码分析

RoundRobinLoadBalancer#choose 方法是负载均衡策略轮训算法的实现,轮训算法的实现也很简单,维护了一个 position 的原子类,每次获取服务实例的时候就对 position 进行加一操作,然后使用 position 和服务实例个数进行取模,根据取模后的结果来获取服务实例返回。

java 复制代码
//org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer#choose
public Mono<Response<ServiceInstance>> choose(Request request) {
	//获取服务实例列表
	ServiceInstanceListSupplier supplier = (ServiceInstanceListSupplier)this.serviceInstanceListSupplierProvider.getIfAvailable(NoopServiceInstanceListSupplier::new);
	//使用轮训算法获取服务实例
	return supplier.get(request).next().map((serviceInstances) -> {
		return this.processInstanceResponse(supplier, serviceInstances);
	});
}

//org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer#processInstanceResponse
private Response<ServiceInstance> processInstanceResponse(ServiceInstanceListSupplier supplier, List<ServiceInstance> serviceInstances) {
	//使用轮训算法获取服务实例
	Response<ServiceInstance> serviceInstanceResponse = this.getInstanceResponse(serviceInstances);
	if (supplier instanceof SelectedInstanceCallback && serviceInstanceResponse.hasServer()) {
		((SelectedInstanceCallback)supplier).selectedServiceInstance((ServiceInstance)serviceInstanceResponse.getServer());
	}
	//返回服务实例
	return serviceInstanceResponse;
}

//org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer#getInstanceResponse
private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances) {
	//服务实例为空判断
	if (instances.isEmpty()) {
		if (log.isWarnEnabled()) {
			log.warn("No servers available for service: " + this.serviceId);
		}

		return new EmptyResponse();
	} else {
		//position +1 获取绝对值 
		int pos = Math.abs(this.position.incrementAndGet());
		//根据 pos 和服务实例数取模后从服务列表中获取服务实例
		ServiceInstance instance = (ServiceInstance)instances.get(pos % instances.size());
		return new DefaultResponse(instance);
	}
}

BlockingLoadBalancerClient#execute 方法源码分析

BlockingLoadBalancerClient#execute 方法是执行 HTTP 请求的方法,该方法的主要作用就是发起 HTTP 请求和对 HTTP 请求结果的处理。

java 复制代码
//org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient#execute(java.lang.String, org.springframework.cloud.client.ServiceInstance, org.springframework.cloud.client.loadbalancer.LoadBalancerRequest<T>)
public <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException {
	//创建 DefaultResponse
	DefaultResponse defaultResponse = new DefaultResponse(serviceInstance);
	//获取当前服务的负载均衡生命周期管理实例
	Set<LoadBalancerLifecycle> supportedLifecycleProcessors = LoadBalancerLifecycleValidator.getSupportedLifecycleProcessors(this.loadBalancerClientFactory.getInstances(serviceId, LoadBalancerLifecycle.class), DefaultRequestContext.class, Object.class, ServiceInstance.class);
	//request 转换
	Request lbRequest = request instanceof Request ? (Request)request : new DefaultRequest();
	//执行 onStartRequest 方法
	supportedLifecycleProcessors.forEach((lifecycle) -> {
		lifecycle.onStartRequest(lbRequest, new DefaultResponse(serviceInstance));
	});

	try {
		//发起 http 请求
		T response = request.apply(serviceInstance);
		//获取响应
		Object clientResponse = this.getClientResponse(response);
		//执行 onComplete
		supportedLifecycleProcessors.forEach((lifecycle) -> {
			lifecycle.onComplete(new CompletionContext(Status.SUCCESS, lbRequest, defaultResponse, clientResponse));
		});
		//返回
		return response;
	} catch (IOException var9) {
		supportedLifecycleProcessors.forEach((lifecycle) -> {
			lifecycle.onComplete(new CompletionContext(Status.FAILED, var9, lbRequest, defaultResponse));
		});
		throw var9;
	} catch (Exception var10) {
		supportedLifecycleProcessors.forEach((lifecycle) -> {
			lifecycle.onComplete(new CompletionContext(Status.FAILED, var10, lbRequest, defaultResponse));
		});
		ReflectionUtils.rethrowRuntimeException(var10);
		return null;
	}
}

如有不正确的地方请各位指出纠正。

相关推荐
T_Ghost35 分钟前
SpringCloud微服务服务容错机制Sentinel熔断器
spring cloud·微服务·sentinel
喂完待续3 小时前
【序列晋升】28 云原生时代的消息驱动架构 Spring Cloud Stream的未来可能性
spring cloud·微服务·云原生·重构·架构·big data·序列晋升
jzzy_hony3 小时前
云原生:微服务与Serverless指南
微服务·云原生·serverless
欧阳的棉花糖3 小时前
微前端俯瞰
微服务·前端工程化
掘金-我是哪吒4 小时前
分布式微服务系统架构第170集:Kafka消费者并发-多节点消费-可扩展性
分布式·微服务·架构·kafka·系统架构
荣光波比4 小时前
Nginx 实战系列(四)—— Nginx反向代理与负载均衡实战指南
运维·nginx·云计算·负载均衡
惜.己16 小时前
Docker启动失败 Failed to start Docker Application Container Engine.
spring cloud·docker·eureka
LQ深蹲不写BUG18 小时前
微服务的保护方式以及Sentinel详解
微服务·云原生·架构
鼠鼠我捏,要死了捏20 小时前
基于Apache Flink Stateful Functions的事件驱动微服务架构设计与实践指南
微服务·apache flink·实时处理
chenrui3101 天前
Spring Boot 和 Spring Cloud: 区别与联系
spring boot·后端·spring cloud