核心:
(1)@balance,最终让template 加一层filter,作负载均衡。
(2)负载均衡用的serverlist,来自spring容器环境,一个server一个容器。
(3)定时任务更新serverlist,ping任务更新server的状态。
(4)chooseServer的rule,ping组件都支持扩展。算法
(1)@balance 实际上是个类注解,至关于标签,核心是加了@qualify,注入的时候 @balance+@autowired 配合list,能够获得全部加@balance注解的bean,就是获得List<Template>。
(2)生成LoadBalanceInterceptor组件bean,做为拦截器,核心是loadBalanceClient;生成RestTemplateCutomizer组件bean,用来装配interceptor
(3)核心SmartInitialzingSingleton组件bean,调用RestTemplateCutomizer,把interceptor放到每一个template中spring
interceptor原理:使用loadBalanceClient,利用irule规则,从servers中挑选实现负载均衡,用requestFactory建立request,向server发请求。springboot
在spring-cloud-netflix-ribbon里,找到了LoadBalanceClient类,经过RibbonAutoConfiguration 自动配置。并发
(1)RibbonAutoConfiguration,负载均衡
@AutoConfigureBefore({ LoadBalancerAutoConfiguration.class, 在这个以前,说明是template收集和加入拦截以前要自动配置,说明拦截和收集要用到它,须要先初始化loadbalanceclient。dom
@AutoConfigureAfter( name = "[org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration](http://org.springframework.cloud.netflix.eureka.eurekaclientautoconfiguration/)”)
在eureka-client注册以后配置,说明要用eureka的注册表。
在这个配置类里,完成了LoadBalancerClient的@bean初始化。ide
(2)excute过程,先拿ILoadBalance -> getLoadBalancer(serviceId);atom
本质上是从SpringClientFactory中,根据serviceId, 获得对应的AnnotationConfigApplicationContext,而后从这个环境中拿到这个service对应的ILoadBalancer。spa
问题:为何要用Spring的容器?AnnotationConfigApplicationContext? 由于区分环境后,在后面注入serverlist的时候,直接经过@bean在参数里注入便可,不须要用serviceid判断。.net
(3)ILoadBalance的本质,
RibbonClientConfiguration中完成初始化,核心是new ZoneAwareLoadBalancer<>(config, rule, ping, serverList,serverListFilter, serverListUpdater);
融合了irule组件,ping组件,serverlist,serverupdate,还执行了个restOfInit方法感知eureka。
(4)loadBlance感知eureka
a 接上面的restOfInit,参数里有个serverlist,是经过bean传递进来,颇有迷惑性,本类的那个bean不是。实际是在EurekaRibbonClientConfiguration的ribbonServerList,注入到了serverListImpl,
b 本质是restOfInit, updateListOfServers( ) -> servers = serverListImpl.getUpdatedListOfServers();调用了obtainServersViaDiscovery,从eurekaClientProvider 获得了eureka-client,从而获得了serverlist,存到iloadbalance本地。
(5)获取eureka后的更新serverlist。
仍是restOfInit(),里面启动线程定时更新(30s),enableAndInitLearnNewServersFeature 调用 serverListUpdater.start(updateAction);开启线程。
(6)ping各个server
ping组件也是能够扩展本身写的,不扩展来自于EurekaRibbonClientConfiguration的NIWSDiscoveryPing,isAlive()方法,就是传入server,检查状态是不是InstanceStatus.UP状态。
在zoneLoadBalance的父类 baseLoadBalance的实例化里,initWithConfig ->setPingInterval ,启动了ping线程,runPinger中调用server的isAlive()方法,默认30s一次。返回false的时候,就放到changelist里,返回true的收集起来做新的serverlist。
(7)excute继续,getServer(),实际上是根据irule获得具体某个server,irule好比用atomicLong,递增取模。
总体过程 ,获得IloadBalance->根据irule 算出server->执行excute
RandomRule:随机选取负载均衡策略。
RoundRobinRule:轮询负载均衡策略。
WeightedResponseTimeRule:根据平均响应时间计算全部服务的权重,时间越短权重越大。刚启动时,若是统计信息不足,则使用线性轮询策略,等信息足够时,再切换到WeightedResponseTimeRule。
RetryRule:使用线性轮询策略获取服务,若是获取失败则在指定时间内重试,从新获取可用服务。
BestAvailableRule:继承自ClientConfigEnabledRoundRobinRule。从全部没有断开的服务中,选取到目前为止请求数量最小的服务。
ClientConfigEnabledRoundRobinRule:默认经过线性轮询策略选取服务。经过继承该类,而且对choose方法进行重写,能够实现更多的策略,继承后保底使用RoundRobinRule策略。
AvailabilityFilteringRule:按可用性进行过滤,会先过滤掉因为屡次访问故障而处于断路器跳闸状态的服务,还有并发的链接数超过阈值的服务,而后对剩余的服务列表进行线性轮询。
ZoneAvoidanceRule:自己没有重写choose方法,用的仍是抽象父类PredicateBasedRule的choose。~~~~
(1)正常全局策略
@Configuration public class LoadBalanced { @Bean public IRule iRule() { return new RandomRule(); } }
irule能够换本身的
(2)指定均衡策略
能够注解配置 @RibbonClient(name = "service1", configuration = cn.wbnull.springbootconsumer.config.LoadBalanced.class)
文件配置
service1: ribbon: NFLoadBalancerRuleClassName: cn.wbnull.springbootconsumer.config.loadbalancer.GlobalRule