eureka client自己本身,是不斷的去從eureka server每隔30秒更新一次註冊表,拉取增量註冊表。所以說ribbon和eureka整合的機制裏,肯定得有一個組件,負責每隔一定的時間,從本地的eureka client裏刷新一下服務的註冊表到LoadBalancer中。。。
(1)調用PollingServerListUpdater實現類的start方法啓動一個定時線程
public class DynamicServerListLoadBalancer<T extends Server> extends BaseLoadBalancer {
/**
* 實現了ServerListUpdater的UpdateAction()方法,直接調用updateListOfServers()來更新註冊表
* 其實就是從eureka client裏去獲取一下註冊表,重新更新到LoadBalancer中去
*/
protected final ServerListUpdater.UpdateAction updateAction = new ServerListUpdater.UpdateAction() {
@Override
public void doUpdate() {
updateListOfServers();
}
};
void restOfInit(IClientConfig clientConfig) {
boolean primeConnection = this.isEnablePrimingConnections();
// turn this off to avoid duplicated asynchronous priming done in BaseLoadBalancer.setServerList()
this.setEnablePrimingConnections(false);
/**
* 啓動一個定時線程,每30s更新一次ServiceA的server list
* 就去從eureka client刷新註冊表到自己的ribbon的LoadBalancer中來
*/
enableAndInitLearnNewServersFeature();
//從eureka client那裏獲取到ServiceA的server list
updateListOfServers();
if (primeConnection && this.getPrimeConnections() != null) {
this.getPrimeConnections()
.primeConnections(getReachableServers());
}
this.setEnablePrimingConnections(primeConnection);
LOGGER.info("DynamicServerListLoadBalancer for client {} initialized: {}", clientConfig.getClientName(), this.toString());
}
public void enableAndInitLearnNewServersFeature() {
LOGGER.info("Using serverListUpdater {}", serverListUpdater.getClass().getSimpleName());
//調用PollingServerListUpdater實現類的start方法啓動一個定時線程
serverListUpdater.start(updateAction);
}
@VisibleForTesting
public void updateListOfServers() {
List<T> servers = new ArrayList<T>();
if (serverListImpl != null) {
//真正調用的是DiscoveryEnabledNIWSServerList實現類的getUpdatedListOfServers()方法
servers = serverListImpl.getUpdatedListOfServers();
LOGGER.debug("List of Servers for {} obtained from Discovery client: {}",
getIdentifier(), servers);
if (filter != null) {
//從一個服務中過濾掉某些server,不要去訪問那些server
servers = filter.getFilteredListOfServers(servers);
LOGGER.debug("Filtered List of Servers for {} obtained from Discovery client: {}",
getIdentifier(), servers);
}
}
//將從eurekaclient獲取的servers列表設置進BaseLoadBalancer的服務實例列表allServerList,這將覆蓋原有服務器列表。
updateAllServerList(servers);
}
}
(2)給PollingServerListUpdater的start()方法傳入了一個UpdateAction,代表的是實際的更新註冊表的行爲。。。其實呢,每次PollingServerListUpdater定時更新註冊表的時候,執行的實際的行爲,就是上一篇博客看到的那個updateListOfServers()方法,其實就是從eureka client裏去獲取一下註冊表,重新更新到LoadBalancer中去。。。。
在PollingServerListUpdater中,創建了一個Runnable線程,裏面就是執行UpdateAction的行爲。默認的是1秒鐘過後,會第一次執行那個Runnable線程,以後是每隔30秒執行一下那個Runnable線程,就去從eureka client刷新註冊表到自己的ribbon的LoadBalancer中來。
public class PollingServerListUpdater implements ServerListUpdater {
@Override
public synchronized void start(final UpdateAction updateAction) {
if (isActive.compareAndSet(false, true)) {
//創建了一個Runnable線程,裏面就是執行UpdateAction的行爲
final Runnable wrapperRunnable = new Runnable() {
@Override
public void run() {
if (!isActive.get()) {
if (scheduledFuture != null) {
scheduledFuture.cancel(true);
}
return;
}
try {
/**
* updateAction其實是直接調用updateListOfServers()
* 其實就是從eureka client裏去獲取一下註冊表,重新更新到LoadBalancer中去
*/
updateAction.doUpdate();
lastUpdated = System.currentTimeMillis();
} catch (Exception e) {
logger.warn("Failed one update cycle", e);
}
}
};
/**
* 默認的是1秒鐘過後,會第一次執行那個Runnable線程,以後是每隔30秒執行一下那個Runnable線程,
* 就去從eureka client刷新註冊表到自己的ribbon的LoadBalancer中來。
*/
scheduledFuture = getRefreshExecutor().scheduleWithFixedDelay(
wrapperRunnable,
initialDelayMs,
refreshIntervalMs,
TimeUnit.MILLISECONDS
);
} else {
logger.info("Already active, no-op");
}
}
}
總結:ribbon如何持續的從eureka中獲取註冊表 流程圖