這篇文章給大家介紹Ribbon中怎么使用 LoadBalancer 實(shí)現(xiàn)負(fù)載均衡,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對(duì)大家能有所幫助。
成都創(chuàng)新互聯(lián)公司10余年專(zhuān)注成都高端網(wǎng)站建設(shè)按需網(wǎng)站制作服務(wù),為客戶(hù)提供專(zhuān)業(yè)的成都網(wǎng)站制作,成都網(wǎng)頁(yè)設(shè)計(jì),成都網(wǎng)站設(shè)計(jì)服務(wù);成都創(chuàng)新互聯(lián)公司服務(wù)內(nèi)容包含成都網(wǎng)站建設(shè),重慶小程序開(kāi)發(fā)公司,軟件開(kāi)發(fā),網(wǎng)絡(luò)營(yíng)銷(xiāo)推廣,網(wǎng)絡(luò)運(yùn)營(yíng)服務(wù)及企業(yè)形象設(shè)計(jì);成都創(chuàng)新互聯(lián)公司擁有眾多專(zhuān)業(yè)的高端網(wǎng)站制作開(kāi)發(fā)團(tuán)隊(duì),資深的高端網(wǎng)頁(yè)設(shè)計(jì)團(tuán)隊(duì)及經(jīng)驗(yàn)豐富的架構(gòu)師高端網(wǎng)站策劃團(tuán)隊(duì);我們始終堅(jiān)持從客戶(hù)的角度出發(fā),為客戶(hù)量身訂造網(wǎng)絡(luò)營(yíng)銷(xiāo)方案,解決網(wǎng)絡(luò)營(yíng)銷(xiāo)疑問(wèn)。
Ribbon 的負(fù)載均衡器是通過(guò) LoadBalancerClient 來(lái)實(shí)現(xiàn)的,在應(yīng)用啟動(dòng)的時(shí)候,LoadBalancerClient 默認(rèn)會(huì)從 EurekaClient 獲取服務(wù)列表,并將服務(wù)注冊(cè)列表緩存在本地,當(dāng)調(diào)用 LoadBalancerClient 的 choose() 方法的時(shí)候, 根據(jù)負(fù)載均衡策略 IRule 來(lái)選擇一個(gè)可用的服務(wù),從而實(shí)現(xiàn)負(fù)載均衡。
當(dāng)然,LoadBalancerClient 也可以不從 EurekaClient 中獲取服務(wù)列表,這是需要自己維護(hù)一個(gè)服務(wù)注冊(cè)列表信息,具體操作如下:
ribbon: eureka: enabled: false stores: ribbon: listOfServers: baidu.com, google.com
主要流程:
1. 當(dāng)應(yīng)用啟動(dòng)的時(shí)候,ILoadBalancer 從 EurekaClient 獲取服務(wù)列表
2. 然后每 10 秒 向 EurekaClient 發(fā)送一次心跳檢測(cè),如果注冊(cè)列表發(fā)生了變化,則更新獲取重新獲取
3. LoadBalancerClient 調(diào)用 choose() 方法來(lái)選擇服務(wù)的時(shí)候,會(huì)調(diào)用 ILoadBalancer 的 chooseServer() 來(lái)獲取一個(gè)可以的服務(wù),
4. 在 ILoadBalancer 進(jìn)行獲取服務(wù)的時(shí)候,會(huì)根據(jù)負(fù)載均衡策略 IRule 來(lái)進(jìn)行選擇
5. 返回可用的服務(wù)
下面就來(lái)看看每個(gè)類(lèi)的實(shí)現(xiàn)原理
RibbonLoadBalancerClient 它是 Ribbon 負(fù)載均衡實(shí)現(xiàn)的一個(gè)重要的類(lèi),最終的負(fù)載均衡的請(qǐng)求處理都由它來(lái)執(zhí)行,先來(lái)看下它的類(lèi)圖:
它實(shí)現(xiàn)了 LoadBalancerClient 接口,而 LoadBalancerClient 接口實(shí)現(xiàn)了 ServiceInstanceChooser 接口:
該接口用來(lái)從負(fù)載均衡器中獲取一個(gè)可用的服務(wù),只有一個(gè)方法:
public interface ServiceInstanceChooser { /** * @param serviceId:服務(wù)ID * @return 可用的服務(wù)實(shí)例 */ ServiceInstance choose(String serviceId); }
表示負(fù)載均衡的客戶(hù)端,是一個(gè)接口,繼承了 ServiceInstanceChooser 接口 ,共有三個(gè)方法:
public interface LoadBalancerClient extends ServiceInstanceChooser { /** * 執(zhí)行請(qǐng)求 * @param serviceId :用于查找 LoadBalancer的服務(wù)ID * @param request:允許實(shí)現(xiàn)執(zhí)行前后操作 */ <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException; /** * 執(zhí)行請(qǐng)求 * @param serviceId :用于查找 LoadBalancer的服務(wù)ID * @param serviceInstance :執(zhí)行請(qǐng)求的服務(wù) * @param request:允許實(shí)現(xiàn)執(zhí)行前后操作 */ <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException; /** * 創(chuàng)建具有真實(shí)主機(jī)和端口的正確URI,有些系統(tǒng)使用帶有邏輯服務(wù)名的URL作為主機(jī),調(diào)用該方法將會(huì)使用 host:port 來(lái)替換邏輯服務(wù)名 * @param instance :用于重建URI的服務(wù)實(shí)例 * @param original :具有邏輯服務(wù)名的URL * @return A reconstructed URI. */ URI reconstructURI(ServiceInstance instance, URI original); }
主要看下從 ServiceInstanceChooser,LoadBalancerClient 中實(shí)現(xiàn)的接口方法
public class RibbonLoadBalancerClient implements LoadBalancerClient { // 工廠(chǎng):主要用來(lái)創(chuàng)建客戶(hù)端,創(chuàng)建負(fù)載均衡器,進(jìn)行客戶(hù)端配置等 // 對(duì)于每一個(gè)客戶(hù)端名稱(chēng)都會(huì)創(chuàng)建一個(gè)Spring ApplicationContext,可以從中獲取需要的bean private SpringClientFactory clientFactory; protected ILoadBalancer getLoadBalancer(String serviceId) { return this.clientFactory.getLoadBalancer(serviceId); } .................. } public class SpringClientFactory extends NamedContextFactory<RibbonClientSpecification> { // 獲取客戶(hù)端 public <C extends IClient<?, ?>> C getClient(String name, Class<C> clientClass) { return getInstance(name, clientClass); } // 獲取負(fù)載均衡器 public ILoadBalancer getLoadBalancer(String name) { return getInstance(name, ILoadBalancer.class); } //獲取客戶(hù)端配置 public IClientConfig getClientConfig(String name) { return getInstance(name, IClientConfig.class); } // 獲取 RibbonLoadBalancerContext public RibbonLoadBalancerContext getLoadBalancerContext(String serviceId) { return getInstance(serviceId, RibbonLoadBalancerContext.class); } // 獲取對(duì)應(yīng)的bean public <T> T getInstance(String name, Class<T> type) { AnnotationConfigApplicationContext context = getContext(name); ..... return context.getBean(type); ..... } }
該方法主要用來(lái)獲取一個(gè)可用的服務(wù)實(shí)例
public ServiceInstance choose(String serviceId, Object hint) { Server server = getServer(getLoadBalancer(serviceId), hint); if (server == null) { return null; } // RibbonServer 實(shí)現(xiàn)了 ServiceInstance return new RibbonServer(serviceId, server, isSecure(server, serviceId), serverIntrospector(serviceId).getMetadata(server)); } // 根據(jù)服務(wù)ID獲取負(fù)載均衡器,會(huì)調(diào)用 SpringClientFactory 的方法進(jìn)行獲取 protected ILoadBalancer getLoadBalancer(String serviceId) { return this.clientFactory.getLoadBalancer(serviceId); } // 根據(jù)負(fù)載均衡器來(lái)獲取可用的服務(wù) protected Server getServer(ILoadBalancer loadBalancer, Object hint) { if (loadBalancer == null) { return null; } return loadBalancer.chooseServer(hint != null ? hint : "default"); }
最后會(huì)調(diào)用 ILoadBalancer.chooseServer 來(lái)獲取可用服務(wù),后面再來(lái)說(shuō) ILoadBalancer 。
該方法執(zhí)行請(qǐng)求
public <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException { Server server = null; if (serviceInstance instanceof RibbonServer) { server = ((RibbonServer) serviceInstance).getServer(); } RibbonLoadBalancerContext context = this.clientFactory.getLoadBalancerContext(serviceId); // 狀態(tài)記錄器,記錄著服務(wù)的狀態(tài) RibbonStatsRecorder statsRecorder = new RibbonStatsRecorder(context, server); ........... T returnVal = request.apply(serviceInstance); statsRecorder.recordStats(returnVal); return returnVal; ........... } // apply 方法調(diào)用如下,最終返回 ClientHttpResponse public ListenableFuture<ClientHttpResponse> intercept(final HttpRequest request, final byte[] body, final AsyncClientHttpRequestExecution execution) throws IOException { final URI originalUri = request.getURI(); String serviceName = originalUri.getHost(); return this.loadBalancer.execute(serviceName, new LoadBalancerRequest<ListenableFuture<ClientHttpResponse>>() { @Override public ListenableFuture<ClientHttpResponse> apply( final ServiceInstance instance) throws Exception { HttpRequest serviceRequest = new ServiceRequestWrapper(request, instance, AsyncLoadBalancerInterceptor.this.loadBalancer); return execution.executeAsync(serviceRequest, body); } }); }
以上就是負(fù)載均衡器流程圖左邊部分的原理,接下來(lái)看下右邊的部分
通過(guò)上面的分析,負(fù)載均衡器獲取一個(gè)可用的服務(wù),最終會(huì)調(diào)用 ILoadBalancer 的 chooseServer 方法,下面就來(lái)看下 ILoadBalancer 的實(shí)現(xiàn)原理
首先來(lái)看下 ILoadBalancer 的整體類(lèi)圖:
在上面的類(lèi)圖中,主要的邏輯實(shí)在 BaseLoadBalancer 中實(shí)現(xiàn),而 DynamicServerListLoadBalancer 主要提供動(dòng)態(tài)獲取服務(wù)列表的能力。
首先來(lái)看下 ILoadBalancer,它表示一個(gè)負(fù)載均衡器接口,
public interface ILoadBalancer { // 添加服務(wù) public void addServers(List<Server> newServers); //獲取服務(wù) public Server chooseServer(Object key); //標(biāo)記某個(gè)服務(wù)下線(xiàn) public void markServerDown(Server server); //獲取狀態(tài)為UP的所有可用服務(wù)列表 public List<Server> getReachableServers(); //獲取所有服務(wù)列表,包括可用的和不可用的 public List<Server> getAllServers(); }
實(shí)現(xiàn) ILoadBalancer 接口,提供一些默認(rèn)實(shí)現(xiàn)
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); // 獲取狀態(tài) public abstract LoadBalancerStats getLoadBalancerStats(); }
客戶(hù)端配置
public interface IClientConfigAware { public abstract void initWithNiwsConfig(IClientConfig clientConfig); }
負(fù)載均衡器的主要實(shí)現(xiàn)邏輯,在該類(lèi)中,會(huì)根據(jù)負(fù)載均衡策略 IRule 來(lái)獲取可用的服務(wù),會(huì)通過(guò) IPing 來(lái)檢測(cè)服務(wù)的可用性,此外,該類(lèi)中從 EurkaClient 獲取到服務(wù)列表后,會(huì)在該類(lèi)中保存下來(lái),會(huì)維護(hù)所有的服務(wù)列表和可用的服務(wù)列表。
首先來(lái)看下它的一些屬性,然后再來(lái)看每個(gè)對(duì)應(yīng)的方法
public class BaseLoadBalancer extends AbstractLoadBalancer implements PrimeConnections.PrimeConnectionListener, IClientConfigAware { // 默認(rèn)的負(fù)載均衡策略:輪詢(xún)選擇服務(wù)實(shí)例 private final static IRule DEFAULT_RULE = new RoundRobinRule(); protected IRule rule = DEFAULT_RULE; // 默認(rèn) ping 的策略,會(huì)調(diào)用 IPing 來(lái)檢測(cè)服務(wù)是否可用 private final static SerialPingStrategy DEFAULT_PING_STRATEGY = new SerialPingStrategy(); protected IPingStrategy pingStrategy = DEFAULT_PING_STRATEGY; protected IPing ping = null; // 所有服務(wù)列表 protected volatile List<Server> allServerList = Collections.synchronizedList(new ArrayList<Server>()); // 狀態(tài)為 up 的服務(wù)列表 protected volatile List<Server> upServerList = Collections.synchronizedList(new ArrayList<Server>()); // 鎖 protected ReadWriteLock allServerLock = new ReentrantReadWriteLock(); protected ReadWriteLock upServerLock = new ReentrantReadWriteLock(); // 定時(shí)任務(wù),去 ping 服務(wù)是否可用 protected Timer lbTimer = null; // ping 的時(shí)間間隔,10秒 protected int pingIntervalSeconds = 10; // ping 的最大次數(shù) protected int maxTotalPingTimeSeconds = 5; // 負(fù)載均衡器的狀態(tài) protected LoadBalancerStats lbStats; // 客戶(hù)端配置 private IClientConfig config; // 服務(wù)列表變化監(jiān)聽(tīng)器 private List<ServerListChangeListener> changeListeners = new CopyOnWriteArrayList<ServerListChangeListener>(); // 服務(wù)狀態(tài)變化監(jiān)聽(tīng)器 private List<ServerStatusChangeListener> serverStatusListeners = new CopyOnWriteArrayList<ServerStatusChangeListener>(); // 構(gòu)造方法,使用默認(rèn)的配置來(lái)創(chuàng)建負(fù)載均衡器,還有其他重載的構(gòu)造方法,可用根據(jù)需要來(lái)創(chuàng)建負(fù)載均衡器 public BaseLoadBalancer() { this.name = DEFAULT_NAME; this.ping = null; setRule(DEFAULT_RULE); setupPingTask(); lbStats = new LoadBalancerStats(DEFAULT_NAME); } ..................... }
在上面的屬性中,Ribbon 提供了一些默認(rèn)的配置:
IClientConfig 表示客戶(hù)端的配置,實(shí)現(xiàn)類(lèi)為 DefaultClientConfigImpl,在該類(lèi)中配置了默認(rèn)的值,:
public class DefaultClientConfigImpl implements IClientConfig { // ping 的默認(rèn)策略 DummyPing public static final String DEFAULT_NFLOADBALANCER_PING_CLASSNAME = "com.netflix.loadbalancer.DummyPing"; // DummyPing.class.getName(); public static final String DEFAULT_NFLOADBALANCER_RULE_CLASSNAME = "com.netflix.loadbalancer.AvailabilityFilteringRule"; public static final String DEFAULT_NFLOADBALANCER_CLASSNAME = "com.netflix.loadbalancer.ZoneAwareLoadBalancer"; public static final int DEFAULT_MAX_TOTAL_TIME_TO_PRIME_CONNECTIONS = 30000; public static final int DEFAULT_MAX_RETRIES_PER_SERVER_PRIME_CONNECTION = 9; ............................................. }
IRule 表示 負(fù)載均衡策略,即如何去選擇服務(wù)實(shí)例,默認(rèn)為 RoundRobinRule,即通過(guò)輪詢(xún)的方式選擇服務(wù)。Ribbon 默認(rèn)提供的有 7 種。
IPing 表示檢測(cè)服務(wù)是否可用策略,Ribbon 也提供了很多策略,共有 5 種,默認(rèn)為 DummyPing
關(guān)于 IRule 和 IPing 的策略,后面會(huì)專(zhuān)門(mén)進(jìn)行研究。
在 BaseLoadBalancer 中,除了提供一個(gè)無(wú)參的構(gòu)造方法(使用的是默認(rèn)的配置)外,還提供了很多重載的構(gòu)造方法,下面來(lái)看下根據(jù)客戶(hù)端的配置來(lái)創(chuàng)建BaseLoadBalancer :
// 根據(jù)客戶(hù)端配置來(lái)創(chuàng)建 BaseLoadBalancer public BaseLoadBalancer(IClientConfig config) { initWithNiwsConfig(config); } @Override public void initWithNiwsConfig(IClientConfig clientConfig) { // 負(fù)載均衡策略 String ruleClassName = (String) clientConfig.getProperty(CommonClientConfigKey.NFLoadBalancerRuleClassName); // ping 策略 String pingClassName = (String) clientConfig.getProperty(CommonClientConfigKey.NFLoadBalancerPingClassName); IRule rule = (IRule) ClientFactory.instantiateInstanceWithClientConfig(ruleClassName, clientConfig); IPing ping = (IPing) ClientFactory.instantiateInstanceWithClientConfig(pingClassName, clientConfig); // 狀態(tài) LoadBalancerStats stats = createLoadBalancerStatsFromConfig(clientConfig); // 初始化配置 initWithConfig(clientConfig, rule, ping, stats); } void initWithConfig(IClientConfig clientConfig, IRule rule, IPing ping, LoadBalancerStats stats) { this.config = clientConfig; String clientName = clientConfig.getClientName(); this.name = clientName; // ping 的周期 int pingIntervalTime = Integer.parseInt(clientConfig.getProperty(CommonClientConfigKey.NFLoadBalancerPingInterval,Integer.parseInt("30"))); // 最大 ping 的次數(shù) int maxTotalPingTime = Integer.parseInt(clientConfig.getProperty(CommonClientConfigKey.NFLoadBalancerMaxTotalPingTime,Integer.parseInt("2"))); setPingInterval(pingIntervalTime); setMaxTotalPingTime(maxTotalPingTime); setRule(rule); setPing(ping); setLoadBalancerStats(stats); rule.setLoadBalancer(this); if (ping instanceof AbstractLoadBalancerPing) { ((AbstractLoadBalancerPing) ping).setLoadBalancer(this); } ................. // 注冊(cè)監(jiān)控/可忽略 init(); }
在上面的構(gòu)造方法中,可用根據(jù)客戶(hù)端配置的信息來(lái)創(chuàng)建一個(gè)BaseLoadBalancer,如客戶(hù)端可以配置負(fù)載均衡策略,ping的策略,ping的時(shí)間間隔和最大次數(shù)等。
在 Ribbon 中,負(fù)載均衡器多久才去更新獲取服務(wù)列表呢?在 BaseLoadBalancer 類(lèi)中,有一個(gè) setupPingTask 方法,在該方法內(nèi)部,會(huì)創(chuàng)建 PingTask 定時(shí)任務(wù)去檢測(cè)服務(wù)的可用性,而 PingTask 又會(huì)創(chuàng)建 Pinger 對(duì)象,在 Pinger 對(duì)象的 runPinger() 方法中,會(huì)根據(jù)ping策略即 pingerStrategy 的 pingServers(ping, allServer) 來(lái)獲取服務(wù)的可用性,主要邏輯如下:
void setupPingTask() { if (canSkipPing()) { return; } // 如果已經(jīng)有了定時(shí)任務(wù),則取消 if (lbTimer != null) { lbTimer.cancel(); } // 第二個(gè)參數(shù)為true,表示它是一個(gè)deamon線(xiàn)程 lbTimer = new ShutdownEnabledTimer("NFLoadBalancer-PingTimer-" + name, true); // 創(chuàng)建 PingTask, 它繼承于 TimerTask,定時(shí)執(zhí)行 run 方法 lbTimer.schedule(new PingTask(), 0, pingIntervalSeconds * 1000); ...... } class PingTask extends TimerTask { public void run() { // 默認(rèn) pingStrategy = new SerialPingStrategy() new Pinger(pingStrategy).runPinger(); } } public void runPinger() throws Exception { // 如果正在ping,則返回 if (!pingInProgress.compareAndSet(false, true)) { return; // Ping in progress - nothing to do } // 所有的服務(wù),包括不可用的服務(wù) Server[] allServers = null; boolean[] results = null; Lock allLock = null; Lock upLock = null; try { allLock = allServerLock.readLock(); allLock.lock(); allServers = allServerList.toArray(new Server[allServerList.size()]); allLock.unlock(); // 所有服務(wù)的數(shù)量 int numCandidates = allServers.length; // 所有服務(wù)ping的結(jié)果 results = pingerStrategy.pingServers(ping, allServers); // 狀態(tài)可用的服務(wù)列表 final List<Server> newUpList = new ArrayList<Server>(); // 狀態(tài)改變的服務(wù)列表 final List<Server> changedServers = new ArrayList<Server>(); for (int i = 0; i < numCandidates; i++) { // 最新的狀態(tài) boolean isAlive = results[i]; Server svr = allServers[i]; // 老的狀態(tài) boolean oldIsAlive = svr.isAlive(); // 更新?tīng)顟B(tài) svr.setAlive(isAlive); // 如果狀態(tài)改變了,則放到集合中,會(huì)進(jìn)行重新拉取 if (oldIsAlive != isAlive) { changedServers.add(svr); } // 狀態(tài)可用的服務(wù) if (isAlive) { newUpList.add(svr); } } upLock = upServerLock.writeLock(); upLock.lock(); upServerList = newUpList; upLock.unlock(); // 變態(tài)改變監(jiān)聽(tīng)器 notifyServerStatusChangeListener(changedServers); } finally { // ping 完成 pingInProgress.set(false); } } // 檢測(cè)服務(wù)的狀態(tài) @Override public boolean[] pingServers(IPing ping, Server[] servers) { int numCandidates = servers.length; boolean[] results = new boolean[numCandidates]; for (int i = 0; i < numCandidates; i++) { results[i] = false; if (ping != null) { results[i] = ping.isAlive(servers[i]); } } return results; }
在上面的邏輯中,Ribbon 每10秒向 EurekaClient 發(fā)送 ping 來(lái)判斷服務(wù)的可用性,如果服務(wù)的可用性發(fā)生了改變或服務(wù)的數(shù)量和之前的不一致,則會(huì)更新或重新拉取服務(wù)。有了這些服務(wù)之后,會(huì)根據(jù)負(fù)載均衡策略 IRule 來(lái)選擇一個(gè)可用的服務(wù)。
在前文說(shuō)到 Ribbon 客戶(hù)端 RibbonLoadBalancerClient 選擇服務(wù)的時(shí)候,最終會(huì)調(diào)用 ILoadBalancer.chooseServer 來(lái)選擇服務(wù),接下來(lái)就來(lái)看下這個(gè)方法:
public Server chooseServer(Object key) { ....... //rule= new RoundRobinRule() return rule.choose(key); .... }
關(guān)于 Ribbon 的負(fù)載均衡策略 IRule, Ribbon 提供了 7 種,后面再來(lái)分析,現(xiàn)在只需要知道通過(guò) IRule 來(lái)選擇服務(wù)就可以了。
在上面的分析中,Ribbon 會(huì)每10秒定時(shí)的去檢測(cè)服務(wù)的可用性,如果服務(wù)狀態(tài)發(fā)生了變化則重新獲取,之后,再根據(jù)負(fù)載均衡策略 IRule 來(lái)選擇一個(gè)可用的服務(wù);但是,在初始化的時(shí)候,是從哪里獲取服務(wù)列表呢?下面就來(lái)分析這個(gè)問(wèn)題
BaseLoadBalancer 有個(gè)子類(lèi) DynamicServerListLoadBalancer,它具有使用動(dòng)態(tài)源獲取服務(wù)器列表的功能。即服務(wù)器列表在運(yùn)行時(shí)可能會(huì)更改。此外,還可以通過(guò)條件來(lái)過(guò)濾掉不符合所需條件的服務(wù)。
public class DynamicServerListLoadBalancer<T extends Server> extends BaseLoadBalancer { // 是否正在進(jìn)行服務(wù)列表的更新 protected AtomicBoolean serverListUpdateInProgress = new AtomicBoolean(false); // 服務(wù)列表 volatile ServerList<T> serverListImpl; // 服務(wù)過(guò)濾器 volatile ServerListFilter<T> filter; }
在 DynamicServerListLoadBalancer 中,有個(gè) restOfInit 方法,在初始化時(shí)進(jìn)行調(diào)用,在該方法中,會(huì)從 Eureka 客戶(hù)端中拉取所有的服務(wù)列表:
void restOfInit(IClientConfig clientConfig) { ............. updateListOfServers(); ........ } public void updateListOfServers() { List<T> servers = new ArrayList<T>(); if (serverListImpl != null) { // 獲取所有服務(wù)列表 servers = serverListImpl.getUpdatedListOfServers(); // 根據(jù)條件過(guò)濾服務(wù) if (filter != null) { servers = filter.getFilteredListOfServers(servers); } } updateAllServerList(servers); } protected void updateAllServerList(List<T> ls) { if (serverListUpdateInProgress.compareAndSet(false, true)) { try { for (T s : ls) { s.setAlive(true); // 狀態(tài)設(shè)置為可用 } setServersList(ls); super.forceQuickPing(); // 強(qiáng)制檢測(cè)服務(wù)狀態(tài) } finally { serverListUpdateInProgress.set(false); } } }
獲取所有服務(wù)列表 servers = serverListImpl.getUpdatedListOfServers(); 最終會(huì)調(diào)用 DiscoveryEnabledNIWSServerList 的方法:
servers = serverListImpl.getUpdatedListOfServers(); public List<DiscoveryEnabledServer> getUpdatedListOfServers(){ return obtainServersViaDiscovery(); } private List<DiscoveryEnabledServer> obtainServersViaDiscovery() { List<DiscoveryEnabledServer> serverList = new ArrayList<DiscoveryEnabledServer>(); ........ // 通過(guò) eurekaClient 來(lái)獲取注冊(cè)的服務(wù)列表 EurekaClient eurekaClient = eurekaClientProvider.get(); if (vipAddresses!=null){ for (String vipAddress : vipAddresses.split(",")) { List<InstanceInfo> listOfInstanceInfo = eurekaClient.getInstancesByVipAddress(vipAddress, isSecure, targetRegion); for (InstanceInfo ii : listOfInstanceInfo) { if (ii.getStatus().equals(InstanceStatus.UP)) { ..... DiscoveryEnabledServer des = createServer(ii, isSecure, shouldUseIpAddr); serverList.add(des); } } ...... } } return serverList; }
通過(guò)上面方法的分析,Ribbon 最終會(huì)通過(guò) EurekaClient 來(lái)獲取服務(wù)列表的,而 EurekaClient 的實(shí)現(xiàn)類(lèi)是 DiscoveryClient,而在 Eureka 中,DiscoveryClient 類(lèi)具有服務(wù)的注冊(cè),發(fā)現(xiàn),續(xù)約,獲取服務(wù)列表等功能。
此外,該類(lèi)中還可以通過(guò)過(guò)濾器來(lái)獲取不符合條件的服務(wù)。
以上就是 Ribbon 負(fù)載均衡器的一個(gè)實(shí)現(xiàn)原理。最后再來(lái)看下流程圖,加深印象:
關(guān)于Ribbon中怎么使用 LoadBalancer 實(shí)現(xiàn)負(fù)載均衡就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。
新聞標(biāo)題:Ribbon中怎么使用LoadBalancer實(shí)現(xiàn)負(fù)載均衡
文章分享:http://jinyejixie.com/article6/jjgoig.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供建站公司、用戶(hù)體驗(yàn)、網(wǎng)站維護(hù)、做網(wǎng)站、標(biāo)簽優(yōu)化、全網(wǎng)營(yíng)銷(xiāo)推廣
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)