最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring中的Eureka服務(wù)過期詳細(xì)解析

 更新時(shí)間:2023年11月21日 09:25:10   作者:dalianpai  
這篇文章主要介紹了Spring中的Eureka服務(wù)過期詳細(xì)解析,如果有一些服務(wù)過期了,或者宕機(jī)了,就不會調(diào)用shutdown()方法,也不會去發(fā)送請求下線服務(wù)實(shí)例,需要的朋友可以參考下

Eureka 過期

如果有一些服務(wù)過期了,或者宕機(jī)了,就不會調(diào)用shutdown()方法,也不會去發(fā)送請求下線服務(wù)實(shí)例。

eureka就專門實(shí)現(xiàn)了一套過期的策略,去下線一些過期的服務(wù)。

它的入口就是在eureka server在啟動(dòng)初始化的時(shí)候,registry.openForTraffic(applicationInfoManager, registryCount);。

image-20211014185500470

于是就點(diǎn)進(jìn)方法,下面為它的代碼

@Override
    public void openForTraffic(ApplicationInfoManager applicationInfoManager, int count) {
        // Renewals happen every 30 seconds and for a minute it should be a factor of 2.
        this.expectedNumberOfClientsSendingRenews = count;
        updateRenewsPerMinThreshold();
        logger.info("Got {} instances from neighboring DS node", count);
        logger.info("Renew threshold is: {}", numberOfRenewsPerMinThreshold);
        this.startupTime = System.currentTimeMillis();
        if (count > 0) {
            this.peerInstancesTransferEmptyOnStartup = false;
        }
        DataCenterInfo.Name selfName = applicationInfoManager.getInfo().getDataCenterInfo().getName();
        boolean isAws = Name.Amazon == selfName;
        if (isAws && serverConfig.shouldPrimeAwsReplicaConnections()) {
            logger.info("Priming AWS connections for all replicas..");
            primeAwsReplicas(applicationInfoManager);
        }
        logger.info("Changing status to UP");
        applicationInfoManager.setInstanceStatus(InstanceStatus.UP);
        super.postInit();
    }

expectedNumberOfClientsSendingRenews為從注冊表獲取的注冊服務(wù)實(shí)例的數(shù)量。

protected void updateRenewsPerMinThreshold() {
        this.numberOfRenewsPerMinThreshold = (int) (this.expectedNumberOfClientsSendingRenews
                * (60.0 / serverConfig.getExpectedClientRenewalIntervalSeconds())
                * serverConfig.getRenewalPercentThreshold());
    }

getExpectedClientRenewalIntervalSeconds 默認(rèn)為30秒,getRenewalPercentThreshold 是檢測的一個(gè)系數(shù)為85%,這個(gè)公式會算出期望的存活的數(shù)量的。如果注冊的數(shù)量為20個(gè)* 2 * 0.85 =34,這個(gè)是在自我保護(hù)機(jī)制中進(jìn)行對比的,判斷是否進(jìn)入保護(hù)機(jī)制,進(jìn)入的話,則不能摘除服務(wù),不會走下面的方法 。下面一段代碼都不是太重要,當(dāng)來到super.postInit();的時(shí)候,顧名思義,是要做一些初始化的事情。下面為詳細(xì)代碼:

protected void postInit() {
        renewsLastMin.start();
        if (evictionTaskRef.get() != null) {
            evictionTaskRef.get().cancel();
        }
        evictionTaskRef.set(new EvictionTask());
        evictionTimer.schedule(evictionTaskRef.get(),
                serverConfig.getEvictionIntervalTimerInMs(),
                serverConfig.getEvictionIntervalTimerInMs());
    }

renewsLastMin.start();看上去是要開啟一個(gè)線程,看名字是續(xù)租最后一分鐘,代碼設(shè)計(jì)的還是很巧妙的,設(shè)置出2個(gè)Bucket,一個(gè)專門存當(dāng)前時(shí)間,一個(gè)存一分鐘之前的時(shí)間,這個(gè)線程1分鐘運(yùn)行一次,這樣就可以拿到一分鐘之前的時(shí)間了。

private final long sampleInterval;  //1分鐘  
 
  public synchronized void start() {
        if (!isActive) {
            timer.schedule(new TimerTask() {
 
                @Override
                public void run() {
                    try {
                        // Zero out the current bucket.
                        //每分鐘這塊調(diào)度異常
                        //currentBucket 是用來更新當(dāng)前這一分鐘的次數(shù)的
                        //lastBucket 是保留了上一分鐘的心跳次數(shù)
                        //timer調(diào)度任務(wù),1分鐘來一次,就將上一分鐘的心跳次數(shù)設(shè)置到lastBucket中去
                        lastBucket.set(currentBucket.getAndSet(0));
                    } catch (Throwable e) {
                        logger.error("Cannot reset the Measured Rate", e);
                    }
                }
            }, sampleInterval, sampleInterval);
 
            isActive = true;
        }
    }

evictionTaskRef.set(new EvictionTask());這里會new一個(gè)task,下面就看一下,它到底做了什么,compensation的意思是補(bǔ)償,那這個(gè)compensationTimeMs就是補(bǔ)償時(shí)間(毫秒)。在getCompensationTimeMs這個(gè)方法中,會用當(dāng)前時(shí)間減去上一次執(zhí)行的時(shí)間,在減去摘除間隔時(shí)間(60s),在判斷這個(gè)時(shí)間是否大于0,如果大于0,這說明延遲了,則會得到一個(gè)補(bǔ)償時(shí)間,這個(gè)時(shí)間很關(guān)鍵,因?yàn)楹竺嫠惴?wù)實(shí)例是否過期要下線的時(shí)候,也和它有關(guān)系。

/* visible for testing */ class EvictionTask extends TimerTask {
 
        private final AtomicLong lastExecutionNanosRef = new AtomicLong(0l);
 
        @Override
        public void run() {
            try {
                long compensationTimeMs = getCompensationTimeMs();
                logger.info("Running the evict task with compensationTime {}ms", compensationTimeMs);
                evict(compensationTimeMs);
            } catch (Throwable e) {
                logger.error("Could not run the evict task", e);
            }
        }
 
        /**
         * compute a compensation time defined as the actual time this task was executed since the prev iteration,
         * vs the configured amount of time for execution. This is useful for cases where changes in time (due to
         * clock skew or gc for example) causes the actual eviction task to execute later than the desired time
         * according to the configured cycle.
         */
        //比預(yù)期的時(shí)間晚
        long getCompensationTimeMs() {
            //先獲取當(dāng)前時(shí)間
            long currNanos = getCurrentTimeNano();
            //上一次這個(gè)EvictionTask被執(zhí)行的時(shí)間。
            long lastNanos = lastExecutionNanosRef.getAndSet(currNanos);
            if (lastNanos == 0l) {
                return 0l;
            }
 
            long elapsedMs = TimeUnit.NANOSECONDS.toMillis(currNanos - lastNanos);
            long compensationTime = elapsedMs - serverConfig.getEvictionIntervalTimerInMs();
            return compensationTime <= 0l ? 0l : compensationTime;
        }
 
        long getCurrentTimeNano() {  // for testing
            return System.nanoTime();
        }
 
    }

接著就把補(bǔ)償時(shí)間帶到摘除的方法中,代碼如下:

public void evict(long additionalLeaseMs) {
        logger.debug("Running the evict task");
 
        //是否運(yùn)行主動(dòng)刪除故障的實(shí)例,自我保護(hù)機(jī)制有關(guān)
        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();
                    //如果超過3分鐘加上補(bǔ)償時(shí)間,就認(rèn)為故障了
                    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.
 
        //20
        int registrySize = (int) getLocalRegistrySize();
        // 20*0.85
        int registrySizeThreshold = (int) (registrySize * serverConfig.getRenewalPercentThreshold());
        //3
        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());
            //隨機(jī)挑選3個(gè)服務(wù)
            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);
                //對這個(gè)隨機(jī)挑選出來的,這個(gè)也是shutdown方法調(diào)用的
                internalCancel(appName, id, false);
            }
        }
    }

isLeaseExpirationEnabled()這個(gè)方法,主要就是自我保護(hù),前面已經(jīng)說過了,此處就不在介紹了。

接著會遍歷拿到所有的服務(wù)實(shí)例,里面包含它的續(xù)租時(shí)間,會判斷它有沒有過期,過期的話就會加到要摘除的集合中。公式就是當(dāng)前時(shí)間是否大約最后一次修改的時(shí)候加上續(xù)租時(shí)間和補(bǔ)償時(shí)間,大于的話就是過期了。

public boolean isExpired(long additionalLeaseMs) {
        //當(dāng)前時(shí)間是否大于上一次心跳時(shí)間加上90s+再加上補(bǔ)償時(shí)間
        return (evictionTimestamp > 0 || System.currentTimeMillis() > (lastUpdateTimestamp + duration + additionalLeaseMs));
    }

這塊代碼中,會計(jì)算出一個(gè)最大的摘除的個(gè)數(shù),如果是20個(gè)的話,最大摘除3個(gè)。因此最后會選擇這3和故障的6個(gè)選擇一個(gè)最小的,進(jìn)行隨機(jī)摘除,然后調(diào)用下線的方法。

到此這篇關(guān)于Spring中的Eureka服務(wù)過期詳細(xì)解析的文章就介紹到這了,更多相關(guān)Eureka服務(wù)過期內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring中配置和讀取多個(gè)Properties文件的方式方法

    Spring中配置和讀取多個(gè)Properties文件的方式方法

    本篇文章主要介紹了Spring中配置和讀取多個(gè)Properties文件的方式方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2017-04-04
  • Java利用布隆過濾器實(shí)現(xiàn)快速檢查元素是否存在

    Java利用布隆過濾器實(shí)現(xiàn)快速檢查元素是否存在

    布隆過濾器是一個(gè)很長的二進(jìn)制向量和一系列隨機(jī)映射函數(shù)。布隆過濾器可以用于檢索一個(gè)元素是否在一個(gè)集合中。本文就來詳細(xì)說說實(shí)現(xiàn)的方法,需要的可以參考一下
    2022-10-10
  • RocketMQ之NameServer架構(gòu)設(shè)計(jì)及啟動(dòng)關(guān)閉流程源碼分析

    RocketMQ之NameServer架構(gòu)設(shè)計(jì)及啟動(dòng)關(guān)閉流程源碼分析

    這篇文章主要為大家介紹了RocketMQ之NameServer架構(gòu)設(shè)計(jì)及啟動(dòng)關(guān)閉流程源碼分析詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2021-11-11
  • SpringBoot集成Swagger2生成接口文檔的方法示例

    SpringBoot集成Swagger2生成接口文檔的方法示例

    我們提供Restful接口的時(shí)候,API文檔是尤為的重要,它承載著對接口的定義,描述等,本文主要介紹了SpringBoot集成Swagger2生成接口文檔的方法示例,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-12-12
  • 教你Java中的Lock鎖底層AQS到底是如何實(shí)現(xiàn)的

    教你Java中的Lock鎖底層AQS到底是如何實(shí)現(xiàn)的

    本文是基于ReentrantLock來講解,ReentrantLock加鎖只是對AQS的api的調(diào)用,底層的鎖的狀態(tài)(state)和其他線程等待(Node雙向鏈表)的過程其實(shí)是由AQS來維護(hù)的,對Java?Lock鎖AQS實(shí)現(xiàn)過程感興趣的朋友一起看看吧
    2022-05-05
  • 淺析Spring?Cloud?Gateway中的令牌桶限流算法

    淺析Spring?Cloud?Gateway中的令牌桶限流算法

    這篇文章主要為大家淺析了Spring?Cloud?Gateway中的令牌桶限流算法原理,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2022-02-02
  • springboot+vue實(shí)現(xiàn)七牛云頭像的上傳

    springboot+vue實(shí)現(xiàn)七牛云頭像的上傳

    本文將介紹如何在Spring Boot項(xiàng)目中利用七牛云進(jìn)行圖片上傳并將圖片存儲在云存儲中,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-08-08
  • springtask 的使用方法和 cron 表達(dá)式解析

    springtask 的使用方法和 cron 表達(dá)式解析

    這篇文章主要介紹了springtask 的使用方法和 cron 表達(dá)式解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10
  • Java ObjectMapper使用詳解

    Java ObjectMapper使用詳解

    ObjectMapper類是Jackson的主要類,它可以幫助我們快速的進(jìn)行各個(gè)類型和Json類型的相互轉(zhuǎn)換,本文給大家介紹Java ObjectMapper的相關(guān)知識,感興趣的朋友跟隨小編一起看看吧
    2024-07-07
  • @Value如何獲取yml和properties配置參數(shù)

    @Value如何獲取yml和properties配置參數(shù)

    這篇文章主要介紹了@Value如何獲取yml和properties配置參數(shù)的操作,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07

最新評論

新田县| 北流市| 布拖县| 连城县| 兴城市| 东平县| 闽侯县| 梧州市| 永登县| 澳门| 四平市| 郁南县| 栖霞市| 孝昌县| 威远县| 游戏| 永吉县| 休宁县| 虹口区| 克拉玛依市| 容城县| 苏尼特右旗| 进贤县| 临汾市| 汉川市| 垫江县| 巩留县| 比如县| 县级市| 乐昌市| 兴和县| 峨边| 郧西县| 佛坪县| 清流县| 星座| 兖州市| 依兰县| 林州市| 河源市| 诸城市|