依然 是 依賴(lài)于 Spring-Ioc 和自動(dòng)配置的方式,實(shí)現(xiàn) 客戶端負(fù)載均衡器的初始化配置. 由于 代碼量多,層次關(guān)聯(lián)復(fù)雜.因此選擇從核心類(lèi)開(kāi)始閱讀
N : Netflix 的設(shè)計(jì)的類(lèi)結(jié)構(gòu)
SN : Spring 集成 Netflix 設(shè)計(jì)的類(lèi)結(jié)構(gòu)
S: Spring 設(shè)計(jì)的類(lèi)結(jié)構(gòu)
S- LoadBalancerClient :負(fù)載均衡器
public interface LoadBalancerClient {
// 根據(jù) serviceId 獲取 ServiceInstance
ServiceInstance choose(String serviceId);
// 執(zhí)行LoadBalancerRequest
<T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException;
// 根據(jù)ServiceInstance,原始 URI,拼接出 目標(biāo)URI
URI reconstructURI(ServiceInstance instance, URI original);
}
SN- RibbonLoadBalancerClient : 基于 Ribbon實(shí)現(xiàn)的LoadBalancerClient
@Override
public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
// 根據(jù) serviceId 獲取 ILoadBalancer
ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
// 獲取 Server
Server server = getServer(loadBalancer);
if (server == null) {
throw new IllegalStateException("No instances available for " + serviceId);
}
// 重新包裝為RibbonServer
RibbonServer ribbonServer = new RibbonServer(serviceId, server, isSecure(server,
serviceId), serverIntrospector(serviceId).getMetadata(server));
// 獲取RibbonLoadBalancerContext
RibbonLoadBalancerContext context = this.clientFactory
.getLoadBalancerContext(serviceId);
//狀態(tài)記錄
RibbonStatsRecorder statsRecorder = new RibbonStatsRecorder(context, server);
try {
// 執(zhí)行請(qǐng)求
T returnVal = request.apply(ribbonServer);
// 狀態(tài)更新
statsRecorder.recordStats(returnVal);
return returnVal;
}
// catch IOException and rethrow so RestTemplate behaves correctly
catch (IOException ex) {
// 狀態(tài)更新
statsRecorder.recordStats(ex);
throw ex;
}
catch (Exception ex) {
// 狀態(tài)更新
statsRecorder.recordStats(ex);
ReflectionUtils.rethrowRuntimeException(ex);
}
return null;
}
? 可以觀察到, 核心的負(fù)載均衡是由 ILoadBalancer實(shí)現(xiàn)的.通過(guò)SpringClientFactory 獲取/創(chuàng)建 ILoadBalancer實(shí)現(xiàn)實(shí)例.
protected ILoadBalancer getLoadBalancer(String serviceId) {
return this.clientFactory.getLoadBalancer(serviceId);
}
SN-SpringClientFactory:
用以 創(chuàng)建 Ribbon 的 負(fù)載均衡相關(guān)實(shí)例. 并 為每個(gè)"客戶端名稱(chēng)" 創(chuàng)建一個(gè) Spring ApplicationContext per,并從中提取需要的注入對(duì)象.(但它們公用一個(gè)父容器,可以拿到父容器中的 Bean 實(shí)例的引用).而 Spring 通過(guò)RibbonClientConfiguration創(chuàng)建 并使用了 ILoadBalancer的一個(gè)實(shí)現(xiàn),名為ZoneAwareLoadBalancer.
到這里.差不多可以看出整體雛形了:
Spring Cloud 創(chuàng)建并注冊(cè) RibbonLoadBalancerClient. 在execute方法中, 委托給 Ribbon 的 ILoadBalancer獲取 Server, 以實(shí)現(xiàn)負(fù)載均衡. 默認(rèn)大家了解 Spring RestTemplate(封裝了 HTTP 相關(guān)方法的模板類(lèi)), 在ClientHttpRequestExecution調(diào)用的過(guò)程中, 將被ClientHttpRequestInterceptor 實(shí)現(xiàn)攔截功能.在LoadBalancerAutoConfiguration部分,可以看到 配置注冊(cè)了一個(gè)名為L(zhǎng)oadBalancerInterceptor的ClientHttpRequestInterceptor.
S-LoadBalancerInterceptor: 實(shí)現(xiàn)了客戶端負(fù)載均衡的攔截器
@Override
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
final ClientHttpRequestExecution execution) throws IOException {
final URI originalUri = request.getURI();
String serviceName = originalUri.getHost();
return this.loadBalancer.execute(serviceName, requestFactory.createRequest(request, body, execution));
}
也就是所有的@LoadBalanced
注解的RestTemplate
都會(huì)被攔截進(jìn)入loadBalancer(RibbonLoadBalancerClient)并進(jìn)行相應(yīng)的執(zhí)行.然后我們可以進(jìn)行下一步了.
S-LoadBalancerRequest
public interface LoadBalancerRequest<T> {
public T apply(ServiceInstance instance) throws Exception;
}
最新版LoadBalancerRequest而它是由LoadBalancerRequestFactory生成.
public LoadBalancerRequest<ClientHttpResponse> createRequest(final HttpRequest request,
final byte[] body, final ClientHttpRequestExecution execution) {
return new LoadBalancerRequest<ClientHttpResponse>() {
@Override
public ClientHttpResponse apply(final ServiceInstance instance)
throws Exception {
// HttpRequest包轉(zhuǎn)
HttpRequest serviceRequest = new ServiceRequestWrapper(request, instance, loadBalancer);
if (transformers != null) {
for (LoadBalancerRequestTransformer transformer : transformers) {
//
serviceRequest = transformer.transformRequest(serviceRequest, instance);
}
}
return execution.execute(serviceRequest, body);
}
};
}
就是如此 將 RestTemplate 變?yōu)橹С重?fù)載均衡的RestTemplate.
Spring集成 Ribbon 的部分已經(jīng)介紹好了.下面繼續(xù)深入了解下 N- ILoadBalancer 負(fù)載均衡器.(好累啊!!!.)
public interface ILoadBalancer {
// 添加服務(wù)
public void addServers(List<Server> newServers);
// 選擇服務(wù)
public Server chooseServer(Object key);
// 標(biāo)記為關(guān)閉的服務(wù)
public void markServerDown(Server server);
// 獲取所有服務(wù)
@Deprecated
public List<Server> getServerList(boolean availableOnly);
// 獲取所有可用服務(wù)
public List<Server> getReachableServers();
// 獲取所有服務(wù)
public List<Server> getAllServers();
}
主要介紹下幾個(gè)子類(lèi)
AbstractLoadBalancer 作為ILoadBalancer的抽象.定義了 服務(wù)分類(lèi).
public abstract class AbstractLoadBalancer implements ILoadBalancer {
public enum ServerGroup{
ALL,
STATUS_UP,
STATUS_NOT_UP
}
public Server chooseServer() {
return chooseServer(null);
}
public abstract List<Server> getServerList(ServerGroup serverGroup);
public abstract LoadBalancerStats getLoadBalancerStats();
}
BaseLoadBalancer 作為基礎(chǔ)類(lèi).主要功能有.
-
定義了 IRule 變量.實(shí)現(xiàn) 服務(wù)選擇算法.
- RandomRule 實(shí)現(xiàn)了隨機(jī)選擇算法
- RoundRobinRule:實(shí)現(xiàn)了線性輪詢(xún)算法
- RetryRule:實(shí)現(xiàn)了重試選擇的算法
- WeightedResponseTimeRule:實(shí)現(xiàn)了更具服務(wù)狀態(tài),進(jìn)行權(quán)重分析選擇的算法.
- …..還有很多
定義了 IPingStrategy變量. 實(shí)現(xiàn) Ping的策略.SerialPingStrategy為默認(rèn)實(shí)現(xiàn),線性順序 Ping 操作.
-
定義了 IPing 變量.實(shí)現(xiàn) 服務(wù)是否活躍的判斷.主要有:
維護(hù)了 服務(wù)列表
DynamicServerListLoadBalancer.主要提供 服務(wù)狀態(tài)動(dòng)態(tài)更新的功能.
-
ServerList 獲取服務(wù):
DiscoveryEnabledNIWSServerList 就實(shí)現(xiàn)了通過(guò) EurekaClient 對(duì)服務(wù)列表的獲取. 源碼不寫(xiě)了.有興趣大家可以自己讀
public interface ServerList<T extends Server> {
public List<T> getInitialListOfServers();
public List<T> getUpdatedListOfServers();
}
-
ServerListUpdater 控制當(dāng)前服務(wù)列表的更新策略.
- PollingServerListUpdater 輪詢(xún)方式 更新.
- DynamicServerListLoadBalancer: 客戶端維護(hù)服務(wù)狀態(tài),并通過(guò) 控制狀態(tài)改變事件的發(fā)布,實(shí)現(xiàn) 服務(wù)列表更新.
ZoneAwareLoadBalancer: 作為 DynamicServerListLoadBalancer的擴(kuò)展,實(shí)現(xiàn)了關(guān)于 Zone 的概念,提高可用性.
參考資料
http://blog.didispace.com/springcloud-sourcecode-ribbon/ (感謝 DD)