六、Ribbon负载均衡器源码分析

六、ribbon源码

一、准备工作

使用RestTemplate访问其他微服务的接口,可以直接访问具体的地址,但是如果服务部署多台机器,就不能写死地址和端口,当然也可以使用nginx做负载均衡。

我们微服务间最好的就是ribbon,这个组件可以做到服务名到服务具体地址的映射,也支持多种负载均衡规则。
测试代码:
controller方法:

@RestController
@RequestMapping("user")
public class UserController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private OrderFeignService orderFeignService;


    @GetMapping("queryOrderByUserId/{userId}")
    public String queryOrderByUserId(@PathVariable("userId") Long userId){
        String url = "http://order-server/order/queryOrderByUserId/" + userId;
        String order = restTemplate.getForObject(url, String.class);
        return order;
    }

}

配置类,注入RestTemplate时,加上注解@LoadBalanced

@Configuration
public class GlobalConfiguration {

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

那么是如何通过微服务名找到对应的服务的真实ip端口的?

二、源码分析

进入@LoadBalanced注解类,在同包下,找到META-INF/spring.factories下找到自动配置类LoadBalancerAutoConfiguration

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {

    //获取所有标记@LoadBalanced的RestTemplate
	@LoadBalanced
	@Autowired(required = false)
	private List<RestTemplate> restTemplates = Collections.emptyList();

	@Autowired(required = false)
	private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList();

    //注入SmartInitializingSingleton类型的bean,在所有bean初始化后调用afterSingletonsInstantiated
	@Bean
	public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
			final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
		//实现	afterSingletonsInstantiated方法,自定义下RestTemplate,也就是加入loadBalancerInterceptor拦截器
		return () -> restTemplateCustomizers.ifAvailable(customizers -> {
			for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
				for (RestTemplateCustomizer customizer : customizers) {
					customizer.customize(restTemplate);
				}
			}
		});
	}

	@Bean
	@ConditionalOnMissingBean
	public LoadBalancerRequestFactory loadBalancerRequestFactory(
			LoadBalancerClient loadBalancerClient) {
		return new LoadBalancerRequestFactory(loadBalancerClient, this.transformers);
	}

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
	static class LoadBalancerInterceptorConfig {

		@Bean
		public LoadBalancerInterceptor ribbonInterceptor(
				LoadBalancerClient loadBalancerClient,
				LoadBalancerRequestFactory requestFactory) {
			return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
		}
        //初始化RestTemplateCustomizer
		@Bean
		@ConditionalOnMissingBean
		public RestTemplateCustomizer restTemplateCustomizer(
				final LoadBalancerInterceptor loadBalancerInterceptor) {
			//给restTemplate添加LoadBalancerInterceptor拦截器
			return restTemplate -> {
				List<ClientHttpRequestInterceptor> list = new ArrayList<>(
						restTemplate.getInterceptors());
				list.add(loadBalancerInterceptor);
				restTemplate.setInterceptors(list);
			};
		}
	}
	.........
}

注入RestTemplateCustomizer,LoadBalancerInterceptor组件,RestTemplateCustomizer定义customize实现,为RestTemplate添加LoadBalancerInterceptor拦截器。
注入一个SmartInitializingSingleton类型的Bean,在所有bean初始化完成后调用SmartInitializingSingleton的afterSingletonsInstantiated。
这个时候获取所有的RestTemplate为其定制化,也就是加LoadBalancerInterceptor拦截器。

LoadBalancerInterceptor组件做了什么?
LoadBalancerInterceptor的实现类是RibbonLoadBalancerClient。
它也是自动配置类RibbonAutoConfiguration注入的。

@Configuration
@Conditional(RibbonAutoConfiguration.RibbonClassesConditions.class)
@RibbonClients
@AutoConfigureAfter(
		name = "org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration")
@AutoConfigureBefore({ LoadBalancerAutoConfiguration.class,
		AsyncLoadBalancerAutoConfiguration.class })
@EnableConfigurationProperties({ RibbonEagerLoadProperties.class,
		ServerIntrospectorProperties.class })
public class RibbonAutoConfiguration {
	@Bean
	@ConditionalOnMissingBean(LoadBalancerClient.class)
	public LoadBalancerClient loadBalancerClient() {
	    //注入RibbonLoadBalancerClient
		return new RibbonLoadBalancerClient(springClientFactory());
	}
    //注入SpringClientFactory
	@Bean
	@ConditionalOnMissingBean
	public SpringClientFactory springClientFactory() {
		SpringClientFactory factory = new SpringClientFactory();
		factory.setConfigurations(this.configurations);
		return factory;
	}
	.........

}

总结:
1、自动配置类RibbonAutoConfiguration注入loadBalancerClient,类型是RibbonLoadBalancerClient
2、自动配置类LoadBalancerAutoConfiguration,获取所有标记@LoadBalanced的RestTemplate,为其添加LoadBalancerInterceptor拦截器

分析访问接口,调用:
restTemplate.getForObject(“http://order-server/order/queryOrderByUserId/111”, String.class)

debug调试进入LoadBalancerInterceptor的方法

@Override
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
		final ClientHttpRequestExecution execution) throws IOException {
	final URI originalUri = request.getURI();
	//获取微服名称,我们的是order-server
	String serviceName = originalUri.getHost();
	Assert.state(serviceName != null,
			"Request URI does not contain a valid hostname: " + originalUri);
	//loadBalancer是 RibbonLoadBalancerClient		
	return this.loadBalancer.execute(serviceName,
			this.requestFactory.createRequest(request, body, execution));
}

RibbonLoadBalancerClient的execute方法

public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint)
		throws IOException {
    //获取负载均衡器
	ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
	//通过负载均衡器获得Server
	Server server = getServer(loadBalancer, hint);
	if (server == null) {
		throw new IllegalStateException("No instances available for " + serviceId);
	}
	//创建RibbonServer
	RibbonServer ribbonServer = new RibbonServer(serviceId, server,
			isSecure(server, serviceId),
			serverIntrospector(serviceId).getMetadata(server));
	//执行调用
	return execute(serviceId, ribbonServer, request);
}

看下SpringClientFactory在构造方法中,指定了配置类RibbonClientConfiguration

public SpringClientFactory() {
	super(RibbonClientConfiguration.class, NAMESPACE, "ribbon.client.name");
}

RibbonClientConfiguration配置类注入

@Bean
@ConditionalOnMissingBean
public ILoadBalancer ribbonLoadBalancer(IClientConfig config,
		ServerList<Server> serverList, ServerListFilter<Server> serverListFilter,
		IRule rule, IPing ping, ServerListUpdater serverListUpdater) {
	if (this.propertiesFactory.isSet(ILoadBalancer.class, name)) {
		return this.propertiesFactory.get(ILoadBalancer.class, config, name);
	}
	// 先从配置中拿,没有则ZoneAwareLoadBalancer,我们就是ZoneAwareLoadBalancer
	return new ZoneAwareLoadBalancer<>(config, rule, ping, serverList,
			serverListFilter, serverListUpdater);
}

再看下负载均衡器获得Server。

protected Server getServer(ILoadBalancer loadBalancer, Object hint) {
	if (loadBalancer == null) {
		return null;
	}
	// ZoneAwareLoadBalancer的chooseServer
	return loadBalancer.chooseServer(hint != null ? hint : "default");
}

chooseServer方法

public Server chooseServer(Object key) {
	if (counter == null) {
		counter = createCounter();
	}
	counter.increment();
	if (rule == null) {
		return null;
	} else {
		try {
			return rule.choose(key);
		} catch (Exception e) {
			logger.warn("LoadBalancer [{}]:  Error choosing server for key {}", name, key, e);
			return null;
		}
	}
}

PredicateBasedRule的choose方法

@Override
public Server choose(Object key) {
	ILoadBalancer lb = getLoadBalancer();
	//lb.getAllServers() 获得所有服务
	//chooseRoundRobinAfterFiltering轮询 所有服务
	Optional<Server> server = getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key);
	if (server.isPresent()) {
		return server.get();
	} else {
		return null;
	}       
}
@Override
public List<Server> getAllServers() {
    //allServerList 这个就是所有服务
	return Collections.unmodifiableList(allServerList);
}

下面我们看看 allServerList是如何获取到的?

回到ZoneAwareLoadBalancer 构造调用父类构造

@Deprecated
public DynamicServerListLoadBalancer(IClientConfig clientConfig, IRule rule, IPing ping, 
		ServerList<T> serverList, ServerListFilter<T> filter) {
	this(
			clientConfig,
			rule,
			ping,
			serverList,
			filter,
			new PollingServerListUpdater() //创建PollingServerListUpdater
	);
}

public DynamicServerListLoadBalancer(IClientConfig clientConfig, IRule rule, IPing ping,
									 ServerList<T> serverList, ServerListFilter<T> filter,
									 ServerListUpdater serverListUpdater) {
	super(clientConfig, rule, ping);
	this.serverListImpl = serverList;
	this.filter = filter;
	this.serverListUpdater = serverListUpdater;
	if (filter instanceof AbstractServerListFilter) {
		((AbstractServerListFilter) filter).setLoadBalancerStats(getLoadBalancerStats());
	}
	//初始化
	restOfInit(clientConfig);
}



初始化

void restOfInit(IClientConfig clientConfig) {
	boolean primeConnection = this.isEnablePrimingConnections();
	// turn this off to avoid duplicated asynchronous priming done in BaseLoadBalancer.setServerList()
	this.setEnablePrimingConnections(false);
	//开启和初始化学习新服务特性
	enableAndInitLearnNewServersFeature();
    //更新服务
	updateListOfServers();
	if (primeConnection && this.getPrimeConnections() != null) {
		this.getPrimeConnections()
				.primeConnections(getReachableServers());
	}
	this.setEnablePrimingConnections(primeConnection);
	LOGGER.info("DynamicServerListLoadBalancer for client {} initialized: {}", clientConfig.getClientName(), this.toString());
}

enableAndInitLearnNewServersFeature方法:

public void enableAndInitLearnNewServersFeature() {
	LOGGER.info("Using serverListUpdater {}", serverListUpdater.getClass().getSimpleName());
	//serverListUpdater 是PollingServerListUpdater
	serverListUpdater.start(updateAction);
}

上面的updateAction参数定义如下

protected final ServerListUpdater.UpdateAction updateAction = new ServerListUpdater.UpdateAction() {
	@Override
	public void doUpdate() {
		updateListOfServers();
	}
};

start方法,搞一个定时任务执行updateAction.doUpdate()方法,也就是执行updateListOfServers方法。

@Override
public synchronized void start(final UpdateAction updateAction) {
	if (isActive.compareAndSet(false, true)) {
		final Runnable wrapperRunnable = new Runnable() {
			@Override
			public void run() {
				if (!isActive.get()) {
					if (scheduledFuture != null) {
						scheduledFuture.cancel(true);
					}
					return;
				}
				try {
					updateAction.doUpdate();
					lastUpdated = System.currentTimeMillis();
				} catch (Exception e) {
					logger.warn("Failed one update cycle", e);
				}
			}
		};

		scheduledFuture = getRefreshExecutor().scheduleWithFixedDelay(
				wrapperRunnable,
				initialDelayMs,
				refreshIntervalMs,
				TimeUnit.MILLISECONDS
		);
	} else {
		logger.info("Already active, no-op");
	}
}

updateListOfServers方法

@VisibleForTesting
public void updateListOfServers() {
	List<T> servers = new ArrayList<T>();
	if (serverListImpl != null) {
	    //拉取服务
		servers = serverListImpl.getUpdatedListOfServers();
		LOGGER.debug("List of Servers for {} obtained from Discovery client: {}",
				getIdentifier(), servers);

		if (filter != null) {
			servers = filter.getFilteredListOfServers(servers);
			LOGGER.debug("Filtered List of Servers for {} obtained from Discovery client: {}",
					getIdentifier(), servers);
		}
	}
	//更新ServerList
	updateAllServerList(servers);
}

NacosServerList.getUpdatedListOfServers方法

@Override
public List<NacosServer> getUpdatedListOfServers() {
	return getServers();
}
	

getServers方法

private List<NacosServer> getServers() {
	try {
		String group = discoveryProperties.getGroup();
		//获取namingService,在通过NamingService查询我们需要的order-server
		List<Instance> instances = discoveryProperties.namingServiceInstance()
				.selectInstances(serviceId, group, true);
		return instancesToServerList(instances);
	}
	catch (Exception e) {
		throw new IllegalStateException(
				"Can not get service instances from nacos, serviceId=" + serviceId,
				e);
	}
}

获取NamingService

@Deprecated
public NamingService namingServiceInstance() {
	return nacosServiceManager.getNamingService(this.getNacosProperties());
}

上面也就是通过http接口的形式查询nacos的/v1/ns/instance/list获得对应的服务实例,就不展开了。

最后获取到服务,更新allServerList。

总结:
1、RibbonClientConfiguration配置类注入ZoneAwareLoadBalancer
2、ZoneAwareLoadBalancer初始化时创建定时任务,拉取nacos的/v1/ns/instance/list接口获得对应的服务实例,更新到allServerList
3、restTemplate调用时被LoadBalancerInterceptor拦截,执行intercept方法
4、获取ZoneAwareLoadBalancer,选择服务chooseServer
5、执行相应的IRule的负载均衡规则,从ZoneAwareLoadBalancer的allServerList获得对应的服务实例

源码分析流程图:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值