Ribbon核⼼源码解析-@LoadBalanced

Ribbon核⼼源码解析

在这里插入图片描述

在这里插入图片描述
Ribbon给restTemplate添加了⼀个拦截器

在这里插入图片描述
负载均衡管理器LoadBalancer(总的协调者,相当于⼤脑,为了做事情,协调四肢) ,围
绕它周围的多有IRule、 IPing等

  • IRule:是在选择实例的时候的负载均衡策略对象
  • IPing:是⽤来向服务发起⼼跳检测的,通过⼼跳检测来判断该服务是否可⽤
  • ServerListFilter:根据⼀些规则过滤传⼊的服务实例列表
  • ServerListUpdater:定义了⼀系列的对服务列表的更新操作

@LoadBalanced源码剖析

在RestTemplate实例上添加了⼀个@LoadBalanced注解,就可以实现负载均衡,很神奇

/**
 * Annotation to mark a RestTemplate bean to be configured to use a LoadBalancerClient.
 * 使用@LoadBalanced 注解标记RestTemplate 后,使用LoadBalancerClient去处理
 * @author Spencer Gibb
 */
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {
}

注解什么也没有,就是个普通注解,可以用在属性,参数,方法上注释才是重点

LoadBalancerClient

public interface LoadBalancerClient extends ServiceInstanceChooser {

	//根据服务执⾏请求内容
	<T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException;

//根据服务执⾏请求内容
	<T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException;

	//拼接请求⽅式 传统中是ip:port 现在是服务名称:port 形式
	URI reconstructURI(ServiceInstance instance, URI original);
}

实现类 org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient

SpringCloud充分利⽤了SpringBoot的⾃动装配特点,找spring.factories配置⽂件
在这里插入图片描述

RibbonAutoConfiguration 类头信息
@Configuration
//1.
@Conditional(RibbonAutoConfiguration.RibbonClassesConditions.class)
@RibbonClients
@AutoConfigureAfter(name = "org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration")
//2. LoadBalancerAutoConfiguration
@AutoConfigureBefore({LoadBalancerAutoConfiguration.class, AsyncLoadBalancerAutoConfiguration.class})
@EnableConfigurationProperties({RibbonEagerLoadProperties.class, ServerIntrospectorProperties.class})
//3.RibbonAutoConfiguration 
public class RibbonAutoConfiguration {

1.RibbonClassesConditions

static class RibbonClassesConditions extends AllNestedConditions {

		RibbonClassesConditions() {
			super(ConfigurationPhase.PARSE_CONFIGURATION);
		}

		@ConditionalOnClass(IClient.class)
		static class IClientPresent {

		}
		/**
		当classpath中有RestTemplate这个类时就创建
		*/
		@ConditionalOnClass(RestTemplate.class)
		static class RestTemplatePresent {

		}

		@ConditionalOnClass(AsyncRestTemplate.class)
		static class AsyncRestTemplatePresent {

		}
	/**
		当classpath中有Ribbon这个类时就创建
		*/
		@ConditionalOnClass(Ribbon.class)
		static class RibbonPresent {

		}

	}

2.LoadBalancerAutoConfiguration

@Configuration
//1.当有RestTemplate这个类时才装配 
@ConditionalOnClass(RestTemplate.class)
//2.当 有LoadBalancerClient这个对象时才装配
@ConditionalOnBean(LoadBalancerClient.class)
//3.启动配置属性 @ConfigurationProperties("spring.cloud.loadbalancer.retry")
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {

2.1 LoadBalancerAutoConfiguration类中 restTemplates
声明一个 List对象用于保存一些加了@LoadBalanced 注解的RestTemplate

@LoadBalanced
	@Autowired(required = false)
	private List<RestTemplate> restTemplates = Collections.emptyList();

2.2 restTemplateCustomizer 方法

@Bean
		@ConditionalOnMissingBean
		public RestTemplateCustomizer restTemplateCustomizer(
				final LoadBalancerInterceptor loadBalancerInterceptor) {
			return restTemplate -> {
                List<ClientHttpRequestInterceptor> list = new ArrayList<>(
                        restTemplate.getInterceptors());
                list.add(loadBalancerInterceptor);
                //向容器中注入RestTemplateCustomizer 定制器 拦截器 给Restemplate添加一个拦截器loadBalancerInterceptor
                restTemplate.setInterceptors(list);
            };
		}

2.3 loadBalancedRestTemplateInitializerDeprecated
.使⽤定制器给集合中的每⼀个resttemplate对象添加⼀个拦截器

	@Bean
	public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
			final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
		return () -> restTemplateCustomizers.ifAvailable(customizers -> {
            for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
                for (RestTemplateCustomizer customizer : customizers) {
                //定制
                    customizer.customize(restTemplate);
                }
            }
        });
	}

添加了注解@LoadBalanced的RestTemplate对象会被添加⼀个拦截器LoadBalancerInterceptor

2.4 LoadBalancerInterceptor

public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {

	private LoadBalancerClient loadBalancer;
	private LoadBalancerRequestFactory requestFactory;

	public LoadBalancerInterceptor(LoadBalancerClient loadBalancer, LoadBalancerRequestFactory requestFactory) {
		this.loadBalancer = loadBalancer;
		this.requestFactory = requestFactory;
	}

	public LoadBalancerInterceptor(LoadBalancerClient loadBalancer) {
		// for backwards compatibility
		this(loadBalancer, new LoadBalancerRequestFactory(loadBalancer));
	}
	
	//核心拦截方法
	@Override
	public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
			final ClientHttpRequestExecution execution) throws IOException {
			//获取请求的URL http://edu-service-resume/resume/openstate/"+userId
		final URI originalUri = request.getURI();
		//远程主机服务名称 edu-service-resume
		String serviceName = originalUri.getHost();
		//判断服务名称是否为null
		Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
		//执行负载均衡 交给LoadBalancerClient 
		return this.loadBalancer.execute(serviceName, requestFactory.createRequest(request, body, execution));
	}
}

下面回到RibbonAutoConfiguration

3.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 {

	@Autowired(required = false)
	private List<RibbonClientSpecification> configurations = new ArrayList<>();

	@Autowired
	private RibbonEagerLoadProperties ribbonEagerLoadProperties;

	@Bean
	public HasFeatures ribbonFeature() {
		return HasFeatures.namedFeature("Ribbon", Ribbon.class);
	}

	@Bean
	public SpringClientFactory springClientFactory() {
		SpringClientFactory factory = new SpringClientFactory();
		factory.setConfigurations(this.configurations);
		return factory;
	}
	//1. 当没有LoadBalancerClient对象时,创建LoadBalancerClient对象RibbonLoadBalancerClient
	//负载均衡的事情执⾏原来交给了最初看到的RibbonLoadBalancerClient对象⾮常核⼼的⼀个⽅法: RibbonLoadBalancerClient.execute()
	@Bean
	@ConditionalOnMissingBean(LoadBalancerClient.class)
	public LoadBalancerClient loadBalancerClient() {
		return new RibbonLoadBalancerClient(springClientFactory());
	}

	@Bean
	@ConditionalOnClass(name = "org.springframework.retry.support.RetryTemplate")
	@ConditionalOnMissingBean
	public LoadBalancedRetryFactory loadBalancedRetryPolicyFactory(final SpringClientFactory clientFactory) {
		return new RibbonLoadBalancedRetryFactory(clientFactory);
	}

	@Bean
	@ConditionalOnMissingBean
	public PropertiesFactory propertiesFactory() {
		return new PropertiesFactory();
	}

	@Bean
	@ConditionalOnProperty(value = "ribbon.eager-load.enabled")
	public RibbonApplicationContextInitializer ribbonApplicationContextInitializer() {
		return new RibbonApplicationContextInitializer(springClientFactory(),
				ribbonEagerLoadProperties.getClients());
	}

	@Configuration
	@ConditionalOnClass(HttpRequest.class)
	@ConditionalOnRibbonRestClient
	protected static class RibbonClientHttpRequestFactoryConfiguration {

		@Autowired
		private SpringClientFactory springClientFactory;

		@Bean
		public RestTemplateCustomizer restTemplateCustomizer(
				final RibbonClientHttpRequestFactory ribbonClientHttpRequestFactory) {
			return restTemplate -> restTemplate.setRequestFactory(ribbonClientHttpRequestFactory);
		}

		@Bean
		public RibbonClientHttpRequestFactory ribbonClientHttpRequestFactory() {
			return new RibbonClientHttpRequestFactory(this.springClientFactory);
		}
	}

	//TODO: support for autoconfiguring restemplate to use apache http client or okhttp

	@Target({ ElementType.TYPE, ElementType.METHOD })
	@Retention(RetentionPolicy.RUNTIME)
	@Documented
	@Conditional(OnRibbonRestClientCondition.class)
	@interface ConditionalOnRibbonRestClient { }

	private static class OnRibbonRestClientCondition extends AnyNestedCondition {
		public OnRibbonRestClientCondition() {
			super(ConfigurationPhase.REGISTER_BEAN);
		}

		@Deprecated //remove in Edgware"
		@ConditionalOnProperty("ribbon.http.client.enabled")
		static class ZuulProperty {}

		@ConditionalOnProperty("ribbon.restclient.enabled")
		static class RibbonProperty {}
	}

	/**
	 * {@link AllNestedConditions} that checks that either multiple classes are present
	 */
	static class RibbonClassesConditions extends AllNestedConditions {

		RibbonClassesConditions() {
			super(ConfigurationPhase.PARSE_CONFIGURATION);
		}

		@ConditionalOnClass(IClient.class)
		static class IClientPresent {

		}

		@ConditionalOnClass(RestTemplate.class)
		static class RestTemplatePresent {

		}

		@ConditionalOnClass(AsyncRestTemplate.class)
		static class AsyncRestTemplatePresent {

		}

		@ConditionalOnClass(Ribbon.class)
		static class RibbonPresent {

		}

	}
}

RibbonLoadBalancerClient.execute()
@Override
	public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
	    return execute(serviceId, request, null);
	}


	public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint) throws IOException {
	//1.获取一个ILoadBalancer 对象,负载均衡器
		ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
		//2.通过负载均衡器获取一个Server
		Server server = getServer(loadBalancer, hint);
		if (server == null) {
			throw new IllegalStateException("No instances available for " + serviceId);
		}
		//3. 把server封装为RibbonServer 
		RibbonServer ribbonServer = new RibbonServer(serviceId, server, isSecure(server,
				serviceId), serverIntrospector(serviceId).getMetadata(server));
		//调用下面的执行方法
		return execute(serviceId, ribbonServer, request);
	}

	@Override
	public <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException {
		Server server = null;
		//判断是不是serviceInstance  instanceof RibbonServer
		if(serviceInstance instanceof RibbonServer) {
		//转换
			server = ((RibbonServer)serviceInstance).getServer();
		}
		//空就抛出异常
		if (server == null) {
			throw new IllegalStateException("No instances available for " + serviceId);
		}

//根据Serviceid获取上 下文
		RibbonLoadBalancerContext context = this.clientFactory
				.getLoadBalancerContext(serviceId);
		RibbonStatsRecorder statsRecorder = new RibbonStatsRecorder(context, server);

		try {
			T returnVal = request.apply(serviceInstance);
			statsRecorder.recordStats(returnVal);
			return returnVal;
		}
		// catch IOException and rethrow so RestTemplate behaves correctly
		catch (IOException ex) {
			statsRecorder.recordStats(ex);
			throw ex;
		}
		catch (Exception ex) {
			statsRecorder.recordStats(ex);
			ReflectionUtils.rethrowRuntimeException(ex);
		}
		return null;
	}

1. 获取负载均衡器 getLoadBalancer

protected ILoadBalancer getLoadBalancer(String serviceId) {
//从容器中获取,什么时候注入在 RibbonAutoConfiguration类中
		return this.clientFactory.getLoadBalancer(serviceId);
	}

RibbonAutoConfiguration中注入ILoadBalancer

	@Bean
	public SpringClientFactory springClientFactory() {
		SpringClientFactory factory = new SpringClientFactory();
		factory.setConfigurations(this.configurations);
		return factory;
	}

springClientFactory


public class SpringClientFactory extends NamedContextFactory<RibbonClientSpecification> {

	static final String NAMESPACE = "ribbon";
	//装配
	public SpringClientFactory() {
		super(RibbonClientConfiguration.class, NAMESPACE, "ribbon.client.name");
	}
RibbonClientConfiguration
//策略
	@Bean
	@ConditionalOnMissingBean
	public IRule ribbonRule(IClientConfig config) {
		if (this.propertiesFactory.isSet(IRule.class, name)) {
			return this.propertiesFactory.get(IRule.class, config, name);
		}
		//返回ZoneAvoidanceRule 策略
		ZoneAvoidanceRule rule = new ZoneAvoidanceRule();
		rule.initWithNiwsConfig(config);
		return rule;
	}

//心跳
@Bean
	@ConditionalOnMissingBean
	public IPing ribbonPing(IClientConfig config) {
		if (this.propertiesFactory.isSet(IPing.class, name)) {
			return this.propertiesFactory.get(IPing.class, config, name);
		}
		return new DummyPing();
	}


@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负载均衡器 默认
		return new ZoneAwareLoadBalancer<>(config, rule, ping, serverList,
				serverListFilter, serverListUpdater);
	}

回到org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient


public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint) throws IOException {
		ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
		//1获取Server
		Server server = getServer(loadBalancer, hint);
		if (server == null) {
			throw new IllegalStateException("No instances available for " + serviceId);
		}
		RibbonServer ribbonServer = new RibbonServer(serviceId, server, isSecure(server,
				serviceId), serverIntrospector(serviceId).getMetadata(server));

		return execute(serviceId, ribbonServer, request);
	}
  • getServer
protected Server getServer(ILoadBalancer loadBalancer, Object hint) {
		if (loadBalancer == null) {
			return null;
		}
		// Use 'default' on a null hint, or just pass it on?
		return loadBalancer.chooseServer(hint != null ? hint : "default");
	}
  • chooseServer
    ZoneAwareLoadBalancer#chooseServer
    在这里插入图片描述
    public Server chooseServer(Object key) {
      ....
        if (server != null) {
            return server;
        } else {
            logger.debug("Zone avoidance logic is not invoked.");
            //调用父类的
            return super.chooseServer(key);
        }
    }
  • com.netflix.loadbalancer.BaseLoadBalancer#chooseServer

 public Server chooseServer(Object key) {
        if (counter == null) {
            counter = createCounter();
        }
        counter.increment();
        if (rule == null) {
            return null;
        } else {
            try {
            //使用负载均衡策略选择一个Server默认 ZoneAvoidanceRule区域隔离
                return rule.choose(key);
            } catch (Exception e) {
                logger.warn("LoadBalancer [{}]:  Error choosing server for key {}", name, key, e);
                return null;
            }
        }
    }
  • 区域隔离策略的⽗类choose⽅法中com.netflix.loadbalancer.PredicateBasedRule#choose
    在这里插入图片描述
 @Override
    public Server choose(Object key) {
        ILoadBalancer lb = getLoadBalancer();
        //使用过滤条件过滤扣,使用轮询策略选择一个Server
        Optional<Server> server = getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key);
        if (server.isPresent()) {
            return server.get();
        } else {
            return null;
        }       
    }



 public Optional<Server> chooseRoundRobinAfterFiltering(List<Server> servers, Object loadBalancerKey) {
 //获取忽略
        List<Server> eligible = getEligibleServers(servers, loadBalancerKey);
        if (eligible.size() == 0) {
            return Optional.absent();
        }
        //索引计算
        return Optional.of(eligible.get(incrementAndGetModulo(eligible.size())));
    }

 private int incrementAndGetModulo(int modulo) {
        for (;;) {
        //获取当前服务的索引
            int current = nextIndex.get();
            //+1取模 记录下一个索引
            int next = (current + 1) % modulo;
            //通过cas设置下一个索引的值
            if (nextIndex.compareAndSet(current, next) && current < modulo)
                return current;
        }
    }

在这里插入图片描述

RoundRobinRule轮询策略


public class RoundRobinRule extends AbstractLoadBalancerRule {

    private AtomicInteger nextServerCyclicCounter;
    private static final boolean AVAILABLE_ONLY_SERVERS = true;
    private static final boolean ALL_SERVERS = false;

    private static Logger log = LoggerFactory.getLogger(RoundRobinRule.class);

    public RoundRobinRule() {
        nextServerCyclicCounter = new AtomicInteger(0);
    }

    public RoundRobinRule(ILoadBalancer lb) {
        this();
        setLoadBalancer(lb);
    }

//核心方法
    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            log.warn("no load balancer");
            return null;
        }

        Server server = null;
        int count = 0;
        while (server == null && count++ < 10) {
        //使用负载均衡获取可用服务列表
            List<Server> reachableServers = lb.getReachableServers();
            //获取所有的服务列表 
            List<Server> allServers = lb.getAllServers();
            //判断在线的服务数量
            int upCount = reachableServers.size();
            //所有服务数量
            int serverCount = allServers.size();
			//如果都为0 返回null
            if ((upCount == 0) || (serverCount == 0)) {
                log.warn("No up servers available from load balancer: " + lb);
                return null;
            }

			//根据serverCount获取下一个服务的索引
            int nextServerIndex = incrementAndGetModulo(serverCount);
            //获取下一个索引的server
            server = allServers.get(nextServerIndex);
			//如果为空 等待
            if (server == null) {
                /* Transient. */
                Thread.yield();
                continue;
            }

            if (server.isAlive() && (server.isReadyToServe())) {
            //判断服务可用后返回
                return (server);
            }

            // Next.
            server = null;
        }

        if (count >= 10) {
            log.warn("No available alive servers after 10 tries from load balancer: "
                    + lb);
        }
        return server;
    }

   
    private int incrementAndGetModulo(int modulo) {
        for (;;) {
        // 获取当前服务的索引
            int current = nextServerCyclicCounter.get();
            //+1取模获取下一索引
            int next = (current + 1) % modulo;
            //通过CAS设置下一个索引
            if (nextServerCyclicCounter.compareAndSet(current, next))
                return next;
        }
    }

    @Override
    public Server choose(Object key) {
        return choose(getLoadBalancer(), key);
    }

    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
    }
}

RandomRule随机策略


public class RandomRule extends AbstractLoadBalancerRule {

    /**
     * Randomly choose from all living servers
     */
    @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE")
    public Server choose(ILoadBalancer lb, Object key) {
    //判断负载均衡器为空就返加null
        if (lb == null) {
            return null;
        }
        Server server = null;
		//循环判断
        while (server == null) {
        //如果线程中断了就返回null
            if (Thread.interrupted()) {
                return null;
            }
            //获取可用服务列表
            List<Server> upList = lb.getReachableServers();
            //获取所有服务列表
            List<Server> allList = lb.getAllServers();

			//获取所有的服务数量
            int serverCount = allList.size();
            //如果为0就返加null
            if (serverCount == 0) {
                /*
                 * No servers. End regardless of pass, because subsequent passes
                 * only get more restrictive.
                 */
                return null;
            }
			//随机选择一个索引
            int index = chooseRandomInt(serverCount);
            //获取索引的服务
            server = upList.get(index);

            if (server == null) {
                /*
                 * The only time this should happen is if the server list were
                 * somehow trimmed. This is a transient condition. Retry after
                 * yielding.
                 */
                Thread.yield();
                continue;
            }

//判断服务可用就返回
            if (server.isAlive()) {
                return (server);
            }

            // Shouldn't actually happen.. but must be transient or a bug.
            server = null;
            Thread.yield();
        }

        return server;

    }

    protected int chooseRandomInt(int serverCount) {
    	//随机数当前线程
        return ThreadLocalRandom.current().nextInt(serverCount);
    }

	@Override
	public Server choose(Object key) {
		return choose(getLoadBalancer(), key);
	}

	@Override
	public void initWithNiwsConfig(IClientConfig clientConfig) {
		// TODO Auto-generated method stub
		
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值