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;
	}
}

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

相关推荐
天天扭码37 分钟前
五天SpringCloud计划——DAY2之单体架构和微服务架构的选择和转换原则
java·spring cloud·微服务·架构
凡人的AI工具箱1 小时前
15分钟学 Go 第 60 天 :综合项目展示 - 构建微服务电商平台(完整示例25000字)
开发语言·后端·微服务·架构·golang
跳跳的向阳花1 小时前
03-03、SpringCloud第三章,负载均衡Ribbon和Feign
spring cloud·ribbon·负载均衡
运维&陈同学2 小时前
【zookeeper01】消息队列与微服务之zookeeper工作原理
运维·分布式·微服务·zookeeper·云原生·架构·消息队列
码上有前16 小时前
解析后端框架学习:从单体应用到微服务架构的进阶之路
学习·微服务·架构
天天扭码17 小时前
五天SpringCloud计划——DAY1之mybatis-plus的使用
java·spring cloud·mybatis
gjh120818 小时前
什么是微服务?
微服务
luckywuxn1 天前
Spring Cloud Alibaba、Spring Cloud 与 Spring Boot各版本的对应关系
spring boot·spring·spring cloud
问窗1 天前
微服务中Spring boot的包扫描范围
java·spring boot·微服务
聂 可 以1 天前
IDEA一键启动多个微服务
java·微服务·intellij-idea