成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

Ribbon中怎么使用LoadBalancer實(shí)現(xiàn)負(fù)載均衡

這篇文章給大家介紹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ù)載均衡器

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

Ribbon 負(fù)載均衡器流程圖

Ribbon中怎么使用 LoadBalancer 實(shí)現(xiàn)負(fù)載均衡

主要流程:

    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ù)

Ribbon 負(fù)載均衡器實(shí)現(xiàn)原理

下面就來(lái)看看每個(gè)類(lèi)的實(shí)現(xiàn)原理

RibbonLoadBalancerClient

RibbonLoadBalancerClient 它是 Ribbon 負(fù)載均衡實(shí)現(xiàn)的一個(gè)重要的類(lèi),最終的負(fù)載均衡的請(qǐng)求處理都由它來(lái)執(zhí)行,先來(lái)看下它的類(lèi)圖:

Ribbon中怎么使用 LoadBalancer 實(shí)現(xiàn)負(fù)載均衡

它實(shí)現(xiàn)了 LoadBalancerClient 接口,而 LoadBalancerClient 接口實(shí)現(xiàn)了 ServiceInstanceChooser 接口:

ServiceInstanceChooser

該接口用來(lái)從負(fù)載均衡器中獲取一個(gè)可用的服務(wù),只有一個(gè)方法:

public interface ServiceInstanceChooser {
	/**
	 * @param serviceId:服務(wù)ID
	 * @return 可用的服務(wù)實(shí)例
	 */
	ServiceInstance choose(String serviceId);
}

LoadBalancerClient

表示負(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);
}

RibbonLoadBalancerClient 實(shí)現(xiàn)如下:

主要看下從 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);
	    .....
	}
}

choose() 方法

該方法主要用來(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 。

execute() 方法

該方法執(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)看下右邊的部分

ILoadBalancer

通過(guò)上面的分析,負(fù)載均衡器獲取一個(gè)可用的服務(wù),最終會(huì)調(diào)用 ILoadBalancer 的 chooseServer 方法,下面就來(lái)看下 ILoadBalancer 的實(shí)現(xiàn)原理

首先來(lái)看下 ILoadBalancer 的整體類(lèi)圖:

Ribbon中怎么使用 LoadBalancer 實(shí)現(xiàn)負(fù)載均衡

在上面的類(lèi)圖中,主要的邏輯實(shí)在 BaseLoadBalancer 中實(shí)現(xiàn),而 DynamicServerListLoadBalancer 主要提供動(dòng)態(tài)獲取服務(wù)列表的能力。

ILoadBalancer

首先來(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();
}

AbstractLoadBalancer

實(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();    
}

IClientConfigAware

客戶(hù)端配置

public interface IClientConfigAware {
    public abstract void initWithNiwsConfig(IClientConfig clientConfig);
}

BaseLoadBalancer

負(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ù)等。

判斷服務(wù)的可用性

在 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ù)。

根據(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ù)就可以了。

初始化獲取所有服務(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;
}

1. 初始化時(shí)獲取所有服務(wù)

在 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)看下流程圖,加深印象:

Ribbon中怎么使用 LoadBalancer 實(shí)現(xiàn)負(fù)載均衡

關(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)

營(yíng)銷(xiāo)型網(wǎng)站建設(shè)
盘锦市| 大渡口区| 武山县| 惠州市| 当阳市| 东阳市| 清涧县| 彭泽县| 达孜县| 安顺市| 曲麻莱县| 凤城市| 牡丹江市| 崇礼县| 江阴市| 丽水市| 定安县| 通化县| 贵港市| 宁乡县| 阿荣旗| 申扎县| 定襄县| 宣城市| 榆林市| 阿城市| 温泉县| 竹北市| 朝阳县| 兰考县| 宁陕县| 朝阳市| 卓尼县| 卓尼县| 黄大仙区| 平原县| 忻城县| 上犹县| 古田县| 远安县| 卢氏县|