Eureka server啟動流程圖和原始碼分析
流程圖

原始碼決議
由流程圖看出,Eureka server啟動時會做兩件事
1.服務同步
因為eureka服務可以搭建集群,所以每個服務節點啟動時,會從相鄰的eureka節點中同步實體資料,原始碼如下:
@Override
public int syncUp() {
// Copy entire entry from neighboring DS node
int count = 0;
//當我們配置register-with-eureka: true時候,getRegistrySyncRetries的回傳值為5
for (int i = 0; ((i < serverConfig.getRegistrySyncRetries()) && (count == 0)); i++) {
if (i > 0) {
try {
//從第二次開始,休眠30秒
Thread.sleep(serverConfig.getRegistrySyncRetryWaitMs());
} catch (InterruptedException e) {
logger.warn("Interrupted during registry transfer..");
break;
}
}
//eurekaClient是當前節點的最近一個節點,在啟動時會初始化
Applications apps = eurekaClient.getApplications();
//回圈節點上的實體
for (Application app : apps.getRegisteredApplications()) {
for (InstanceInfo instance : app.getInstances()) {
try {
if (isRegisterable(instance)) {
//將實體同步到本地記憶體
register(instance, instance.getLeaseInfo().getDurationInSecs(), true);
count++;
}
} catch (Throwable t) {
logger.error("During DS init copy", t);
}
}
}
}
return count;
}
當然,若我們的eureka服務為單機的話,可以設定以下配置
eureka:
client:
fetch-registry: false #是否把eureka服務當成client注冊到配置中心
register-with-eureka: false #eureka服務是否需要讀取配置中心的實體
2.服務剔除
當完成服務同步后,eureka會開啟服務剔除的定時任務,原始碼如下:
protected void postInit() {
renewsLastMin.start();
if (evictionTaskRef.get() != null) {
evictionTaskRef.get().cancel();
}
evictionTaskRef.set(new EvictionTask());
//執行java Timer 定時器任務
evictionTimer.schedule(evictionTaskRef.get(),
serverConfig.getEvictionIntervalTimerInMs(), //60秒后執行任務,可配置
serverConfig.getEvictionIntervalTimerInMs()); //每次執行完任務后,間隔60秒再執行一次
}
EvictionTask實作了Runnable方法,其run方法會呼叫evict方法,evict方法原始碼如下
//additionalLeaseMs為當前時間
public void evict(long additionalLeaseMs) {
logger.debug("Running the evict task");
if (!isLeaseExpirationEnabled()) {
logger.debug("DS: lease expiration is currently disabled.");
return;
}
// We collect first all expired items, to evict them in random order. For large eviction sets,
// if we do not that, we might wipe out whole apps before self preservation kicks in. By randomizing it,
// the impact should be evenly distributed across all applications.
List<Lease<InstanceInfo>> expiredLeases = new ArrayList<>();
//回圈實體
for (Entry<String, Map<String, Lease<InstanceInfo>>> groupEntry : registry.entrySet()) {
Map<String, Lease<InstanceInfo>> leaseMap = groupEntry.getValue();
if (leaseMap != null) {
for (Entry<String, Lease<InstanceInfo>> leaseEntry : leaseMap.entrySet()) {
Lease<InstanceInfo> lease = leaseEntry.getValue();
//如果該實體最后一次心跳續約記錄日期與當前時間間隔大于90秒,則add到List,后續執行剔除操作
if (lease.isExpired(additionalLeaseMs) && lease.getHolder() != null) {
expiredLeases.add(lease);
}
}
}
}
// To compensate for GC pauses or drifting local time, we need to use current registry size as a base for
// triggering self-preservation. Without that we would wipe out full registry.
//設定最大剔除數量
int registrySize = (int) getLocalRegistrySize();
int registrySizeThreshold = (int) (registrySize * serverConfig.getRenewalPercentThreshold());
int evictionLimit = registrySize - registrySizeThreshold;
int toEvict = Math.min(expiredLeases.size(), evictionLimit);
if (toEvict > 0) {
logger.info("Evicting {} items (expired={}, evictionLimit={})", toEvict, expiredLeases.size(), evictionLimit);
//隨機剔除實體
Random random = new Random(System.currentTimeMillis());
for (int i = 0; i < toEvict; i++) {
// Pick a random item (Knuth shuffle algorithm)
int next = i + random.nextInt(expiredLeases.size() - i);
Collections.swap(expiredLeases, i, next);
Lease<InstanceInfo> lease = expiredLeases.get(i);
String appName = lease.getHolder().getAppName();
String id = lease.getHolder().getId();
EXPIRED.increment();
logger.warn("DS: Registry: expired lease for {}/{}", appName, id);
internalCancel(appName, id, false);
}
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/243373.html
標籤:其他
