Ribbon核心工作原理
1.Ribbon的核心接口
接口 | 描述 | 默認實現 |
---|---|---|
IClientConfig | 定義 Ribbon 中管理配置的接口 | DefaultClientConfiglmpl |
IRule | 定義 Ribbon 中負載均衡策略的接口 | ZoneAvoidanceRule |
IPing | 定義定期 ping 服務檢查可用性的接口 | DummyPing |
ServerList | 定義獲取服務列表方法的接口 | ConfigurationBasedServerList |
ServerListFilter | 定義特定期望獲取服務列表方法的接口 | ZonePreferenceServerListFilter |
ILoadBalancer | 定義負載均衡選擇服務的核心方法的接口 | ZoneAwareLoadBalancer |
ServerListUpdater | 爲 DynamicServerListLoadBalancer 定義動態 更新 服務列表的接口 |
PollingServerListUpdater |
2.LoadBalancerClient-負載均衡的基石
/**
* Represents a client side load balancer
* @author Spencer Gibb
*/
public interface LoadBalancerClient extends ServiceInstanceChooser {
// 使用來自LoadBalancer的ServiceInstance對指定對象執行請求
<T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException;
// 使用來自LoadBalancer的ServiceInstance對指定對象執行請求
<T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException;
// 使用真實的主機和端口創建適當的URI
URI reconstructURI(ServiceInstance instance, URI original);
}
public interface ServiceInstanceChooser {
/**從LoadBalancer中爲指定服務選擇一個ServiceInstance
* Choose a ServiceInstance from the LoadBalancer for the specified service
*/
ServiceInstance choose(String serviceId);
}
這兩個類奠定了從負載均衡器中選取服務實例,用服務實例構建真實服務地址,以及發送請求的底層架構基礎。
3.LoadBalancerAutoConfiguration-負載均衡配置的自動裝配
@Configuration
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {
/***
*從類的註解就可以看出,它配置加載的時機一是當前工程環境必須有 RestTemplate 的實 例,
二是在工程環境中必須初始化了 LoadBalancerClient 的實現類
**/
@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
@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);
}
}
});
}
@Autowired(required = false)
private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList();
/**
*LoadBalancerRequestFactory 用於創建 LoadBalancerRequest和LoadBalancerlnterceptor 使用,它在低版本中是沒有的.LoadBalancerInterceptorConfig 中 則 維 護 了 Load- Balancerinterceptor 與RestTemplateCustomizer 的實例 , 它們的作用如下:
□ LoadBalancerlnterceptor : 攔截每一次 HTTP 請求,將請求綁定進 Ribbon 負載均衡的 生命週期。
□ RestTemplateCustomizer: 爲每個 RestTemplate 綁定 LoadBalancerlnterceptor 攔截器。
**/
@Bean
@ConditionalOnMissingBean
public LoadBalancerRequestFactory loadBalancerRequestFactory(
LoadBalancerClient loadBalancerClient) {
return new LoadBalancerRequestFactory(loadBalancerClient, transformers);
}
@Configuration
@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
static class LoadBalancerInterceptorConfig {
@Bean
public LoadBalancerInterceptor ribbonInterceptor(
LoadBalancerClient loadBalancerClient,
LoadBalancerRequestFactory requestFactory) {
return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
}
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(
final LoadBalancerInterceptor loadBalancerInterceptor) {
return restTemplate -> {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(
restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
};
}
}
......
}
在這裏就很明確了,通過
loadBalancerClient
生成LoadBalancerInterceptor
併爲每個RestTemplate
綁定LoadBalancerlnterceptor
攔截器。
4.LoadBalancerInterceptor-負載均衡攔截器
public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {
private LoadBalancerClient loadBalancer;
private LoadBalancerRequestFactory requestFactory;
.....
// 執行攔截器
@Override
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
final ClientHttpRequestExecution execution) throws IOException {
final URI originalUri = request.getURI();
String serviceName = originalUri.getHost();
Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
return this.loadBalancer.execute(serviceName, requestFactory.createRequest(request, body, execution));
}
}
利用
ClientHttpRequestlnterceptor
來對每次 HTTP 請求進行攔截的,此類是 Spring 中維護的請求攔截器,實現它的 intercept 方法就可以使請求進入方法體,從而做一些處 理。可以看出這裏把請求攔截下來之後使用了LoadBalancerClient
的execute
方法來處理請求,由於我 們在 RestTemplate 中使用的 URI 是形如 http://myservice/path/to/service 的,所以這裏的 getHost() 方法實 際 取 到 的 就 是 服 務 名 myservice。LoadBalancerClient
接 口 只 有 一 個 實 現 類 , 即RibbonLoadBalancerClient
。
4.RibbonLoadBalancerClient-Ribbon的負載均衡實現
public class RibbonLoadBalancerClient implements LoadBalancerClient {
.....
@Override
public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
// 獲取具體的服務實例 就是根基服務的實例名字獲取服務的相關元數據信息
ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
// Server 就是具體服務實例的封裝
// 就是發生負載均衡過程的地方
Server server = getServer(loadBalancer);
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);
}
protected Server getServer(ILoadBalancer loadBalancer) {
if (loadBalancer == null) {
return null;
}
return loadBalancer.chooseServer("default"); // default 就是默認的負載均衡算法的key
}
/********************************非本類的實現********************************/
public Server chooseServer(Object key) {
if (counter == null) {
counter = createCounter();
}
counter.increment();
if (rule == null) {
return null;
} else {
try {
// 我們發現, rule.choose(key) 中的 rule 其實就是 IRule, 至此,攔截的HTTP 請求與負載均 衡策略得以關聯起來
return rule.choose(key);
} catch (Exception e) {
logger.warn("LoadBalancer [{}]: Error choosing server for key {}", name, key, e);
return null;
}
}
}
}