LoadBalanced restTemplate
首先在spring.cloud.common包的spring.factories中定义了org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration。LoadBalancerAutoConfiguration中获取了@LoadBalanced的RestTemplate。
@LoadBalanced@Autowired(required=false)private List<RestTemplate> restTemplates= Collections.emptyList();
然后对被@LoadBalanced标注的restTemplates注入拦截器LoadBalancerInterceptor。
@Beanpublic LoadBalancerInterceptorribbonInterceptor(
LoadBalancerClient loadBalancerClient,
LoadBalancerRequestFactory requestFactory){returnnewLoadBalancerInterceptor(loadBalancerClient, requestFactory);}
restTemplate的http请求的方法,最终都会调用到doExecute()方法,在doExecute()方法中会创建InterceptingClientHttpRequest,这个request包含了刚才被注入的拦截器,在真正的http调用之前,会先执行负载均衡拦截器的intercept方法,在该方法中又会调用RibbonLoadBalancerClient的execute方法。
主要逻辑
execute方法中,先获取ILoadBalancer实例,在调用ILoadBalancer实例的chooseServer方法获取到具体Server实例
ILoadBalancer loadBalancer=getLoadBalancer(serviceId);
Server server=getServer(loadBalancer, hint);
ILoadBalancer如何获取
会根据serviceId创建一个子容器,让这个子容器去加载@RibbonClient或@RibbonClients引入的配置类(默认是RibbonClientConfiguration,如果自定义了配置类会覆盖默认配置,conditinalOnMissingBean),引入的配置类中含有ILoadBalancer,再从子容器获取ILoadBalancer bean(默认是ZoneAwareLoadBalancer)。
RibbonLoadBalancerClient.getLoadBalancer(String serviceId)
SpringClientFactory.getLoadBalancer(String name)getInstance(name, ILoadBalancer.class)super.getInstance(name, type)getContext(String name)createContext(String name)
context.getBean(type)
NamedContextFactory#createContext(String name):
//自定义配置类if(this.configurations.containsKey(name)){//configurations就是RibbonClient通过xxRegistrar引入引入的配置类for(Class<?> configuration:this.configurations.get(name).getConfiguration()){
context.register(configuration);}}//默认配置类for(Map.Entry<String, C> entry:this.configurations.entrySet()){if(entry.getKey().startsWith("default.")){for(Class<?> configuration: entry.getValue().getConfiguration()){
context.register(configuration);}}}//子容器名称就是serviceIdprotected StringgenerateDisplayName(String name){returnthis.getClass().getSimpleName()+"-"+ name;}
例子
在入口类中加入@RibbonClient
@EnableDiscoveryClient@SpringBootApplication@RibbonClient(name="nacos-payment-provider",configuration= MyConfig.class)publicclassOrderNacosMain83
自定义配置类,其实被spingboot入口类扫到也无大碍,只不过父容器也会定义一份ribbon相关的bean,而这些用不到,只会用子容器的
@ConfigurationpublicclassMyConfig{@Beanpublic IRulerule(){returnnewRoundRobinRule();}}
如何获取serverList
ZoneAwareLoadBalancer构造方法执行时,会调用NacosNamingService#selectInstances(String serviceName, String groupName, List clusters, boolean healthy, boolean subscribe).
核心接口
IRule
RetryRule
底层还是调用子RUle(默认RoudRobinRule),如果返回的Server不可用,如果会在一个时间范围内重试(默认500ms)。
public Serverchoose(ILoadBalancer lb, Object key){
answer= subRule.choose(key);if(((answer== null)||(!answer.isAlive()))&&(System.currentTimeMillis()< deadline)){//开启一个延时任务,中断当前线程
InterruptTask task=newInterruptTask(deadline- System.currentTimeMillis());while(!Thread.interrupted()){
answer= subRule.choose(key);if(((answer== null)||(!answer.isAlive()))&&(System.currentTimeMillis()< deadline)){/* pause and retry hoping it's transient */
Thread.yield();}else{break;}}
task.cancel();}if((answer== null)||(!answer.isAlive())){return null;}else{return answer;}}
BestAvailableRule
字面意思上理解是并发连接数最少的Server
WeightedResponseTimeRule
根据平均响应时间来选择,权值=总的响应时间-单个响应时间+前一个权值,平均响应时间小的权重大,会维护一个权重集合,定时更新这个集合,这个集合的每个元素的权值是前面元素的权值和,权值大的说明区间范围大,被选中的概率更大,并不是一定会选择权值最大的。权值还没更新时,使用RoundRobin作为备选
比如A,B,C,D4个节点,平均响应时间分别为10,5,12,20,总响应时间47,
计算出来的权值为:37,79,114,141
相当于得到4个区间:[0,37] [37,79] [79,114] [114,141]
再从0~141随机取值,第一个大于随机值的权值即为选中Server
if(maxTotalWeight<0.001d|| serverCount!= currentWeights.size()){
server=super.choose(getLoadBalancer(), key);if(server== null){return server;}}else{// generate a random weight between 0 (inclusive) to maxTotalWeight (exclusive)//0~总权值内随机获取double randomWeight= random.nextDouble()* maxTotalWeight;// pick the server index based on the randomIndexint n=0;for(Double d: currentWeights){if(d>= randomWeight){
serverIndex= n;break;}else{
n++;}}
server= allList.get(serverIndex);}
AvailabilityFilteringRule
也是对RoundRobin的封装,会对Server可用性进行过滤,熔断了的或活动的请求数超出限制的,在剩下的Server中轮询