六、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获得对应的服务实例
源码分析流程图: