Spring Cloud Netflix之Eureka原始碼系列文章一共分為六個片段
Spring Cloud Netflix-Eureka(一)、服務注冊與發現
Spring Cloud Netflix-Eureka(二)、資訊存盤原理
Spring Cloud Netflix-Eureka(三)、自我保護機制
Spring Cloud Netflix-Eureka(四)、心跳續約機制
Spring Cloud Netflix-Eureka(五)、多級快取機制
Spring Cloud Netflix-Eureka(六)、集群資料同步
Spring Cloud Netflix-Eureka、集群資料同步
- 一、Eureka Server是如何保證集群之間的資料一致性
- 二、Eurke集群資料同步具體實作
- 2.1 PeerAwareInstanceRegistryImpl.replicateToPeers()
一、Eureka Server是如何保證集群之間的資料一致性
Eureka Server 集群不區分主從節點,所有節點相同角色(也就是沒有角色 ),完全對等,是 peer to peer 模式,沒有一致性演算法,全靠復制,是最終一致性,
Eureka Client 可以向任意 Eureka Server 發起任意讀寫操作,Eureka Server 將操作復制到另外的 Eureka Server 以達到最終一致性,基本原理如下圖所示,

二、Eurke集群資料同步具體實作
在 Spring Cloud Netflix-Eureka(一)、服務注冊與發現 中,我們分析了服務的注冊程序,其中在 PeerAwareInstanceRegistryImpl.register() 這個方法中,當完成服務資訊保存后,會呼叫 replicateToPeers(); 同步資訊到集群,實際上,服務的注冊、下線、心跳等都會呼叫該方法進行資料同步,保證資料的最終一致性,具體實作如下,
@Singleton
public class PeerAwareInstanceRegistryImpl extends AbstractInstanceRegistry implements PeerAwareInstanceRegistry {
// 服務注冊
public void register(final InstanceInfo info, final boolean isReplication) {
int leaseDuration = Lease.DEFAULT_DURATION_IN_SECS;
if (info.getLeaseInfo() != null && info.getLeaseInfo().getDurationInSecs() > 0) {
leaseDuration = info.getLeaseInfo().getDurationInSecs();
}
super.register(info, leaseDuration, isReplication);
// 資料同步
replicateToPeers(Action.Register, info.getAppName(), info.getId(), info, null, isReplication);
}
// 服務下線
public boolean cancel(final String appName, final String id,
final boolean isReplication) {
if (super.cancel(appName, id, isReplication)) {
// 資料同步
replicateToPeers(Action.Cancel, appName, id, null, null, isReplication);
return true;
}
return false;
}
// 心跳
public boolean renew(final String appName, final String id, final boolean isReplication) {
if (super.renew(appName, id, isReplication)) {
// 資料同步
replicateToPeers(Action.Heartbeat, appName, id, null, null, isReplication);
return true;
}
return false;
}
// 狀態更新
public boolean statusUpdate(final String appName, final String id,
final InstanceStatus newStatus, String lastDirtyTimestamp,
final boolean isReplication) {
if (super.statusUpdate(appName, id, newStatus, lastDirtyTimestamp, isReplication)) {
// 資料同步
replicateToPeers(Action.StatusUpdate, appName, id, null, newStatus, isReplication);
return true;
}
return false;
}
// 洗掉狀態并進行覆寫
public boolean deleteStatusOverride(String appName, String id,
InstanceStatus newStatus,
String lastDirtyTimestamp,
boolean isReplication) {
if (super.deleteStatusOverride(appName, id, newStatus, lastDirtyTimestamp, isReplication)) {
// 資料同步
replicateToPeers(Action.DeleteStatusOverride, appName, id, null, null, isReplication);
return true;
}
return false;
}
}
2.1 PeerAwareInstanceRegistryImpl.replicateToPeers()
@Singleton
public class PeerAwareInstanceRegistryImpl extends AbstractInstanceRegistry implements PeerAwareInstanceRegistry {
// 資料同步
private void replicateToPeers(Action action, String appName, String id,
InstanceInfo info /* optional */,
InstanceStatus newStatus /* optional */, boolean isReplication) {
Stopwatch tracer = action.getTimer().start();
try {
if (isReplication) {// 是復制請求
numberOfReplicationsLastMin.increment();
}
// If it is a replication already, do not replicate again as this will create a poison replication
// 集群為空,并且為復制請求
if (peerEurekaNodes == Collections.EMPTY_LIST || isReplication) {
return;
}
// 遍歷集群節點,進行資料同步
for (final PeerEurekaNode node : peerEurekaNodes.getPeerEurekaNodes()) {
// If the url represents this host, do not replicate to yourself.
if (peerEurekaNodes.isThisMyUrl(node.getServiceUrl())) {
continue;
}
// 發送資料同步請求
replicateInstanceActionsToPeers(action, appName, id, info, newStatus, node);
}
} finally {
tracer.stop();
}
}
// 發送資料同步請求
private void replicateInstanceActionsToPeers(Action action, String appName,
String id, InstanceInfo info, InstanceStatus newStatus,
PeerEurekaNode node) {
try {
InstanceInfo infoFromRegistry;
CurrentRequestVersion.set(Version.V2);
switch (action) {
case Cancel: // 下線
node.cancel(appName, id);
break;
case Heartbeat: // 心跳
InstanceStatus overriddenStatus = overriddenInstanceStatusMap.get(id);
infoFromRegistry = getInstanceByAppAndId(appName, id, false);
node.heartbeat(appName, id, infoFromRegistry, overriddenStatus, false);
break;
case Register: // 注冊
node.register(info);
break;
case StatusUpdate: // 狀態更新
infoFromRegistry = getInstanceByAppAndId(appName, id, false);
node.statusUpdate(appName, id, newStatus, infoFromRegistry);
break;
case DeleteStatusOverride: // 狀態洗掉并覆寫
infoFromRegistry = getInstanceByAppAndId(appName, id, false);
node.deleteStatusOverride(appName, id, infoFromRegistry);
break;
}
} catch (Throwable t) {
logger.error("Cannot replicate information to {} for action {}", node.getServiceUrl(), action.name(), t);
} finally {
CurrentRequestVersion.remove();
}
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/413854.html
標籤:其他
上一篇:基于單機hdfs安裝hive
