Ribbon是Netflix公司開源的一個負載均衡的項目,它屬於上述的第二種,是一個客戶端負載均衡器,運行在客戶端上。Spring Cloud Ribbon是在Netflix Ribbon的基礎上作了進一步的封裝,使它更加適合與微服本文主要如下倆個方便分析Ribbon的原理算法
瞭解Spring boot的自動化裝配的同窗都知道,在Spring boot啓動過程當中會加載在/META-INF/spring.factories文件下定義的配置類,而和Ribbon相關的主要配置類爲LoadBalancerAutoConfiguration,在以下文件下spring
查看LoadBalancerAutoConfiguration的源碼可知,在其內部定義了一個LoadBalancerInterceptor的攔截器,用於實現對客戶端發起請求時進行攔截,以實現客戶端負載均衡。服務器
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 { 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, this.requestFactory.createRequest(request, body, execution)); } }
從源碼中能夠看出,LoadBalancerInterceptor主要是將負載均衡的功能委託給負載均衡客戶端LoadBalancerClient。負載均衡
在看一下RibbonLoadBalancerClient的excute方法dom
public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint) throws IOException { ILoadBalancer loadBalancer = this.getLoadBalancer(serviceId); Server server = this.getServer(loadBalancer, hint); if(server == null) { throw new IllegalStateException("No instances available for " + serviceId); } else { RibbonLoadBalancerClient.RibbonServer ribbonServer = new RibbonLoadBalancerClient.RibbonServer(serviceId, server, this.isSecure(server, serviceId), this.serverIntrospector(serviceId).getMetadata(server)); return this.execute(serviceId, (ServiceInstance)ribbonServer, (LoadBalancerRequest)request); } }
從代碼中能夠看出LoadBalancerClient主要是經過負載均衡器ILoadBalancer查出對應的server而後執行。而getServer就是實現負載均衡的地方。ide
咱們再看一下getServer的實現函數
protected Server getServer(ILoadBalancer loadBalancer, Object hint) { return loadBalancer == null?null:loadBalancer.chooseServer(hint != null?hint:"default"); }
發現是經過ILoadBalancer的chooseServer方法實現的,再看一下BaseLoadBalancer的chooseServer方法性能
public Server chooseServer(Object key) { if (counter == null) { counter = createCounter(); } counter.increment(); if (rule == null) { return null; } else { try { return rule.choose(key); } catch (Exception e) { logger.warn("LoadBalancer [{}]: Error choosing server for key {}", name, key, e); return null; } } }
咱們發現是經過rule.choose方法實現的,而rule實際上是IRule(負載均衡策略接口)。this
總結Ribbon的負載均衡實現,主要是經過LoadBalancerInterceptor攔截器在請求時進行攔截實現負載均衡,而LoadBalancerInterceptor將負載均衡委託給了LoadBalancerClient,而LoadBalancerClient具體交給了ILoadBalancer來處理,ILoadBalancer是根據IRule的策略進行負載均衡。
Ribbon主要包括如下核心接口
接口 | 描述 | 默認實現 |
ILoadBalancer | 負載均衡選擇服務的核心方法接口 | ZoneAwareLoadBalancer |
IRule | 負載均衡策略接口 | ZoneAvoidanceRule |
IPing | 按期檢查服務可用性的接口 | DummyPing |
ServerList<Server> | 獲取服務列表接口 | ConfigurationBaseServerList |
ServerListUpdate | 更新服務列表接口 | PollingServerListUpdate |
ServerListFilter<Server> | 過濾服務列表接口 | ZonePerferenceServerListFilter |
IClientConfig | ribbon中管理配置接口 | DefaultClientConfigImpl |
下面咱們在介紹一下Ribbon的核心接口ILoadBalancer和IRule
ILoadBalancer的繼承關係以下
ILoadBalancer:定義了負載均衡器的主要方法
AbstractLoadBalancer:實現 ILoadBalancer 接口,提供一些默認實現
BaseLoadBalancer:類是Ribbon負載均衡器的基礎實現類,在該類中定義不少關於均衡負載器相關的基礎內容
DynamicServerListLoadBalancer:它是對基礎負載均衡器的擴展。在該負載均衡器中,實現了服務實例清單的在運行期的動態更新能力;同時,它還具有了對服務實例清單的過濾功能。
ZoneAwareLoadBalancer:負載均衡器是對DynamicServerListLoadBalancer的擴展。在DynamicServerListLoadBalancer中,咱們能夠看到它並無重寫選擇具體服務實例的chooseServer函數,因此它依然會採用在BaseLoadBalancer中實現的算法,使用RoundRobinRule規則,以線性輪詢的方式來選擇調用的服務實例,該算法實現簡單並無區域(Zone)的概念,因此它會把全部實例視爲一個Zone下的節點來看待,這樣就會週期性的產生跨區域(Zone)訪問的狀況,因爲跨區域會產生更高的延遲,這些實例主要以防止區域性故障實現高可用爲目的而不能做爲常規訪問的實例,因此在多區域部署的狀況下會有必定的性能問題,而該負載均衡器則能夠避免這樣的問題。
ILoadBalancer是根據IRule定義的負載均衡策略來進行選擇服務的,主要有如下7中負載均衡策略
Ribbon中的7中負載均衡算法:
RoundRobinRule:輪詢;
RandomRule:隨機;
AvailabilityFilteringRule:會先過濾掉因爲屢次訪問故障而處於斷路器狀態的服務,還有併發的鏈接數量超過閾值的服務,而後對剩餘的服務列表按照輪詢策略進行訪問;
WeightedResponseTimeRule:根據平均響應時間計算全部服務的權重,響應時間越快的服務權重越大被選中的機率越大。剛啓動時若是統計信息不足,則使用RoundRobinRule(輪詢)策略,等統計信息足夠,會切換到WeightedResponseTimeRule;
RetryRule:先按照RoundRobinRule(輪詢)策略獲取服務,若是獲取服務失敗則在指定時間內進行重試,獲取可用的服務;
BestAvailableRule:會先過濾掉因爲屢次訪問故障而處於斷路器跳閘狀態的服務,而後選擇一個併發量最小的服務;
ZoneAvoidanceRule:複合判斷Server所在區域的性能和Server的可用性選擇服務器;