ユーレカシリーズ(07)登録とアクティブなサービスをオフライン
[TOC]
春の雲シリーズカタログ - ユーレカの記事
前にユーレカ系列放送(05)メッセージいくつかの記事は、ハートビートを自動的に更新期限が切れると、他のインプリメンテーション・メカニズム、ローカルサービス登録の詳細な分析、組立ラインオフイニシアチブであろう後ユーレカソースコードにブロードキャストメッセージでは、分析されます。
PeerAwareInstanceRegistryImpl
クラスタは、内部メッセージングを担当しています。AbstractInstanceRegistry
いくつかの記事の後に注目されているローカル・サービス情報管理を担当。
リソース | 機能 | URL |
---|---|---|
ApplicationsResource | すべてまたは増分サービスインスタンス情報をキャプチャするには | GET /apps GET /apps/delta |
ApplicationResource | 1つのアプリケーションの情報を取得する 登録情報の2例 |
GET /apps/{appName} POST /apps/{appName} |
InstanceResource | CURDサービスインスタンス: 情報取得の例1. 修正メタ情報サービスインスタンス2は、 インスタンス情報サービスをオフライン削除 ハートビートを送信するために4を |
GET /apps/{appName}/{id} PUT /apps/{appName}/{id}/metadata DELETE /apps/{appName}/{id} PUT /apps/{appName}/{id} |
InstancesResource | 直接事例IDに応じて、取得した情報の一例 | GET /instances/{id} |
PeerReplicationResource | クラスタバルクデータの同期中 | POST /peerreplication/batch |
ServerInfoResource | ??? | POST /serverinfo/statusoverrides |
StatusResource | ??? | GET /statusoverrides |
注:インスタンスIDを表す、アプリケーションまたはサービスIDの名前を表します。EG:HTTP:// localhostを:8080 /ユーリカ/アプリ
1.サービス登録
1.1サービスインスタンスの登録プロセス
概要:ユーレカのWebジャージーコンテナサービス登録要求を使用しては、入力方法ApplicationResource、あるリクエストのパスを登録していますPOST:/euraka/apps/{appName}
。
1.2 ApplicationResource
// ApplicationResource HTTP请求入口
@POST
@Consumes({"application/json", "application/xml"})
public Response addInstance(InstanceInfo info,
@HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String isReplication) {
... // 数据检验
registry.register(info, "true".equals(isReplication));
return Response.status(204).build(); // 204 to be backwards compatible
}
概要: ApplicationResourceメインエントランスパラメトリック検定で、メインロジックが完了PeerAwareInstanceRegistryImplに委任されています。
注意:isReplication引数を、それがある場合は、クライアントの要求が偽だった、他のサーバーにニュース放送の必要性を表明しました。クラスタのメッセージブロードキャストが本当だった場合、それは放送循環の問題を引き起こすであろう、放送を継続する必要はもはやありません。
// PeerAwareInstanceRegistryImpl 默认注册器实现
@Override
public void register(final InstanceInfo info, final boolean isReplication) {
// 租约的过期时间,默认90秒
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);
}
概要: PeerAwareInstanceRegistryImplこのクラスは非常に精通している必要がありますが、クラスタ間の内部通信を担当し、その親AbstractInstanceRegistryは、ローカル・サービス情報管理を担当し、また、この記事の研究の焦点です。
1.3 AbstractInstanceRegistry
ユーレカ、メモリに格納されているサービス登録情報は、データ構造ではConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>> registry
、ネストされた層地図、外層はappNameの鍵であり、鍵メモリのInstanceIdあります。
private final ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>> registry
= new ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>>();
public void register(InstanceInfo registrant, int leaseDuration, boolean isReplication) {
try {
read.lock();
// 1. 获取该服务对应的所有服务实例,如果不存在就创建一个新的Map
Map<String, Lease<InstanceInfo>> gMap = registry.get(registrant.getAppName());
REGISTER.increment(isReplication);
if (gMap == null) {
final ConcurrentHashMap<String, Lease<InstanceInfo>> gNewMap = new ConcurrentHashMap<String, Lease<InstanceInfo>>();
gMap = registry.putIfAbsent(registrant.getAppName(), gNewMap);
if (gMap == null) {
gMap = gNewMap;
}
}
// 2. 两种情况:一是实例已经注册,二是实例没有注册
Lease<InstanceInfo> existingLease = gMap.get(registrant.getId());
// 2.1 实例已经注册,就需要PK,PK原则:谁最后一次更新就是谁赢
// 也就是说如果已经注册的实例最近更新了,就不用重新更新了
if (existingLease != null && (existingLease.getHolder() != null)) {
Long existingLastDirtyTimestamp = existingLease.getHolder().getLastDirtyTimestamp();
Long registrationLastDirtyTimestamp = registrant.getLastDirtyTimestamp();
// 已经注册的实例PK赢了
if (existingLastDirtyTimestamp > registrationLastDirtyTimestamp) {
registrant = existingLease.getHolder();
}
// 2.2 没有注册,很好处理。更新注册的实例个数
} else {
synchronized (lock) {
if (this.expectedNumberOfClientsSendingRenews > 0) {
this.expectedNumberOfClientsSendingRenews = this.expectedNumberOfClientsSendingRenews + 1;
updateRenewsPerMinThreshold();
}
}
}
// 3. 更新注册信息(核心步骤)
Lease<InstanceInfo> lease = new Lease<InstanceInfo>(registrant, leaseDuration);
if (existingLease != null) {
lease.setServiceUpTimestamp(existingLease.getServiceUpTimestamp());
}
// (核心步骤)
gMap.put(registrant.getId(), lease);
// 添加到最近的注册队列里面去,以时间戳作为Key,名称作为value,主要是为了运维界面的统计数据
synchronized (recentRegisteredQueue) {
recentRegisteredQueue.add(new Pair<Long, String>(
System.currentTimeMillis(),
registrant.getAppName() + "(" + registrant.getId() + ")"));
}
// 4. 更新实例状态 InstanceStatus
if (!InstanceStatus.UNKNOWN.equals(registrant.getOverriddenStatus())) {
if (!overriddenInstanceStatusMap.containsKey(registrant.getId())) {
overriddenInstanceStatusMap.put(registrant.getId(), registrant.getOverriddenStatus());
}
}
InstanceStatus overriddenStatusFromMap = overriddenInstanceStatusMap.get(registrant.getId());
if (overriddenStatusFromMap != null) {
registrant.setOverriddenStatus(overriddenStatusFromMap);
}
InstanceStatus overriddenInstanceStatus = getOverriddenInstanceStatus(registrant, existingLease, isReplication);
registrant.setStatusWithoutDirty(overriddenInstanceStatus);
if (InstanceStatus.UP.equals(registrant.getStatus())) {
lease.serviceUp();
}
// 5. 清理缓存等善后工作
registrant.setActionType(ActionType.ADDED);
// 租约变更记录队列,记录了实例的每次变化, 用于注册信息的增量获取
recentlyChangedQueue.add(new RecentlyChangedItem(lease));
registrant.setLastUpdatedTimestamp();
// 清理缓存 ,传入的参数为key
invalidateCache(registrant.getAppName(), registrant.getVIPAddress(), registrant.getSecureVipAddress());
} finally {
read.unlock();
}
}
概要:すでに原則的には、PKのための必要性について存在するロジックの最初の3つのステップは非常に明確である、目的はメモリ内のインスタンス情報を更新することで、単なる例の場合に注意を払う必要があり、それが最後の更新を獲得した人が誰であるか、です。
ステータス更新サービス第四工程、OverriddenStatus基準の例OverriddenStatusにおける役割InstanceInfo
キャッシュと他のリハビリ工事をクリアするごとに5つのステップ。今のところ、をgMap.put(registrant.getId(), lease)
十分にこのポイント。
組立ラインオフ2.イニシアチブ
OPEN API対応サービスはオフラインです DELETE /apps/{appName}/{id}
protected boolean internalCancel(String appName, String id, boolean isReplication) {
try {
read.lock();
CANCEL.increment(isReplication);
// 1. 清空registry中注册的实例信息(核心步骤)
Map<String, Lease<InstanceInfo>> gMap = registry.get(appName);
Lease<InstanceInfo> leaseToCancel = null;
if (gMap != null) {
leaseToCancel = gMap.remove(id);
}
// 2. 添加到 recentCanceledQueue 队列中
synchronized (recentCanceledQueue) {
recentCanceledQueue.add(new Pair<Long, String>(System.currentTimeMillis(), appName + "(" + id + ")"));
}
InstanceStatus instanceStatus = overriddenInstanceStatusMap.remove(id);
if (leaseToCancel == null) {
CANCEL_NOT_FOUND.increment(isReplication);
return false;
} else {
// 3. 和注册时一样,也要做一下清除缓存等善后工作
leaseToCancel.cancel();
InstanceInfo instanceInfo = leaseToCancel.getHolder();
String vip = null;
String svip = null;
if (instanceInfo != null) {
instanceInfo.setActionType(ActionType.DELETED);
recentlyChangedQueue.add(new RecentlyChangedItem(leaseToCancel));
instanceInfo.setLastUpdatedTimestamp();
vip = instanceInfo.getVIPAddress();
svip = instanceInfo.getSecureVipAddress();
}
invalidateCache(appName, vip, svip);
return true;
}
} finally {
read.unlock();
}
}
概要:登録およびアクティブダウン論理サービスはまだ非常に明確です。**今のところ、をgMap.remove(id)
十分にこのポイント。**実際の使用の将来の詳細についてはユーレカは、綿密な調査を続けます。
毎日少しを記録する意向。おそらく、内容は重要ではありませんが、習慣は非常に重要です!