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
}
}