ユーレカシリーズ(07)登録とアクティブなサービスをオフライン

ユーレカシリーズ(07)登録とアクティブなサービスをオフライン

[TOC]

春の雲シリーズカタログ - ユーレカの記事

前にユーレカ系列放送(05)メッセージいくつかの記事は、ハートビートを自動的に更新期限が切れると、他のインプリメンテーション・メカニズム、ローカルサービス登録の詳細な分析、組立ラインオフイニシアチブであろう後ユーレカソースコードにブロードキャストメッセージでは、分析されます。

  • PeerAwareInstanceRegistryImpl クラスタは、内部メッセージングを担当しています。
  • AbstractInstanceRegistry いくつかの記事の後に注目されているローカル・サービス情報管理を担当。
表1:ユーレカOPEN API
リソース 機能 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サービスインスタンスの登録プロセス

図1:ユーレカサービスインスタンス登録のタイミング図
ApplicationResourceオーバーシーケンス図参加ApplicationResource参加PeerAwareInstanceRegistryImpl参加AbstractInstanceRegistry参加PeerEurekaNode注:POST:/ euraka /アプリ/ {appNameは} <BR/> ADDINSTANCE(instanceInfo、isReplication)ApplicationResource - >> PeerAwareInstanceRegistryImpl:登録要求(instanceInfo、isReplication)PeerAwareInstanceRegistryImplレジスタ - 2.1データ同期:replicateInstanceActionsToPeers PeerAwareInstanceRegistryImpl - >> PeerEurekaNode:2.2レジスタ(instanceInfo) - > POST - >> AbstractInstanceRegistry:1.ローカルデータの更新>> PeerAwareInstanceRegistryImpl他のノードユーレカサーバPeerAwareInstanceRegistryImplに同期レジスタ(instanceInfo、leaseDuration、isReplication)ループ:/ euraka /アプリ/ {} appNameの端

概要:ユーレカの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)十分にこのポイント。**実際の使用の将来の詳細についてはユーレカは、綿密な調査を続けます。


毎日少しを記録する意向。おそらく、内容は重要ではありませんが、習慣は非常に重要です!

おすすめ

転載: www.cnblogs.com/binarylei/p/11618566.html