首頁 > 科技

Spring Cloud Netflix Eureka的參數調優

2021-06-13 14:23:43

下面主要分為Client端和Server端兩大類進行簡述,Eureka的幾個核心參數

客戶端參數

Client端的核心參數

定時任務參數

http參數

Eureka Client底層httpClient與Eureka Server通訊,提供的相關參數

服務端端參數

主要包含這幾類:基本參數、response cache參數、peer相參數、http參數

基本參數

response cache參數

Eureka Server為了提升自身REST API介面的效能,提供了兩個快取:一個是基於ConcurrentMap的readOnlyCacheMap,一個是基於Guava Cache的readWriteCacheMap。其相關參數如下:

peer相關參數

http參數

Eureka Server需要與其他peer節點進行通訊,複製例項資訊,其底層使用httpClient,提供相關的參數

參數調優

常見問題

1.為什麼服務下線了,Eureka Server介面返回的資訊還會存在?

2.為什麼服務上線了,Eureka Client不能及時獲取到?

3.為什麼會有以下提示:

EMERGENCY!EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY’RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE

解決方法:

1.Eureka Server並不是強一致的,因此registry中會議保留過期的例項資訊。原因如下:

  • 應用例項異常掛掉,沒能在掛掉之前告知Eureka Server要下線掉該服務例項資訊。這個就需要依賴Eureka Server的EvictionTask去剔除。
  • 應用例項下線是有告知Eureka Server下線,但是由於Eureka Server的REST API有response cache,因此需要等待快取過期才能更新。
  • 由於Eureka Server開啟並以入了SELF PRESERVATION(自我保護)模式,導致registry的資訊不會因為過期而被剔除掉,直到退出SELF PRESERVATION(自我保護)模式。

針對Client下線而沒有通知Eureka Server的問題,可以調整EvictionTask的排程頻率,比如把預設的時間間隔60s,調整為5s:

eureka:  server:    eviction-interval-timer-in-ms: 5000

針對response cache的問題,可以根據情況考慮關閉readOnlyCacheMap:

eureka:  server:    use-read-only-response-cache: false

或者調整readWriteCacheMap的過期時間:

eureka:  server:    response-cache-auto-expiration-in-seconds: 60

針對SELF PRESERVATION(自我保護)的問題,在測試環境可以將enable-self-preservation設定為false:

eureka:  server:    enable-self-preservation: false

關閉之後會提示:

THE SELF PRESER VAT ION MODE IS TURNED OFF.  THIS MAY NOT PRO TECT INSTANCE EXPIRY IN CASE OF NETWORK/OTHER PROBLEMS.

或者:

RENEWALS ARE LESSER THAN THE THRESHOLD.THE SELF PRESERVATION MODE IS TURNED OFF.THIS MAY  NOT PROTECT INSTANCE EXPIRY IN CASE OF NETWORK/OTHER PROBLEMS.

2.針對新服務上線,Eureka Client獲取不及時的問題,在測試環境,可以適當提高client端拉取Server註冊資訊的頻率,例如下面將預設的30s改為5s:

eureka:  client:    registry-fetch-interval-seconds: 5

3.在實際生產過程中,經常會有網路抖動等問題造成服務例項與Eureka Server的心跳未能如期保持,但是服務例項本身是健康的,這個時候如果按照租約剔除機制剔除的話,會造成誤判無果大範圍誤判的話,可能導致整個服務註冊列表的大部分註冊資訊被刪除,從而沒有可用服務。Eureka為了解決這個問題引入了SELF PRESERVATION機制,當最近一分鐘接收到的租約次數小於等於指定閾值的話,則關閉租約失效剔除,禁止定時任務失效的例項,從而保護註冊資訊。

在生產環境下,可以吧renewwalPercentThreshold及leaseRenewalIntervalInSeconds參數調小一點,從而提高觸發SELF PRESERVATION機制的閾值。

eureka:  instance:    lease-renewal-interval-in-seconds: 10 #預設是30    renewal-percent-threshold: 0.49       #預設是0.85

監控指標

Eureka內建了基於servo的指標統計,具體在com.netflix.eureka.util.EurekaMonitors。Spring Boot 2.x版本改為使用Micrometer,不再支援Neflix Servo,轉而支援Neflix Servo的替代品Neflix Spectator。不過對於Servo,可以通過DefaultMonitorRegistry.getInstance().getRegisteredMonitors來獲取所有註冊了的Monitor,進而獲取其指標值。

//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)//package com.netflix.eureka.util;import com.netflix.appinfo.AmazonInfo;import com.netflix.appinfo.ApplicationInfoManager;import com.netflix.appinfo.DataCenterInfo;import com.netflix.appinfo.AmazonInfo.MetaDataKey;import com.netflix.appinfo.DataCenterInfo.Name;import com.netflix.servo.DefaultMonitorRegistry;import com.netflix.servo.annotations.DataSourceType;import com.netflix.servo.annotations.Monitor;import com.netflix.servo.monitor.Monitors;import java.util.concurrent.atomic.AtomicLong;public enum EurekaMonitors {    // 自啟動以來收到的總續約次數    RENEW("renewCounter", "Number of total renews seen since startup"),    // 自啟動以來收到的總取消租約次數    CANCEL("cancelCounter", "Number of total cancels seen since startup"),    // 自啟動以來查詢registry的總次數    GET_ALL_CACHE_MISS("getAllCacheMissCounter", "Number of total registery queries seen since startup"),    // 自啟動以來delta查詢registry的總次數    GET_ALL_CACHE_MISS_DELTA("getAllCacheMissDeltaCounter", "Number of total registery queries for delta seen since startup"),    // 自啟動以來使用remote region查詢registry的總次數    GET_ALL_WITH_REMOTE_REGIONS_CACHE_MISS("getAllWithRemoteRegionCacheMissCounter", "Number of total registry with remote region queries seen since startup"),  // 自啟動以來使用remote region及delta方式查詢registry的總次數  GET_ALL_WITH_REMOTE_REGIONS_CACHE_MISS_DELTA("getAllWithRemoteRegionCacheMissDeltaCounter", "Number of total registry queries for delta with remote region seen since startup"),    // 自啟動以來查詢delta的總次數    GET_ALL_DELTA("getAllDeltaCounter", "Number of total deltas since startup"),    // 自啟動以來傳遞regions查詢delta的總次數    GET_ALL_DELTA_WITH_REMOTE_REGIONS("getAllDeltaWithRemoteRegionCounter", "Number of total deltas with remote regions since startup"),    // 自啟動以來查詢'/{version}/apps'的次數    GET_ALL("getAllCounter", "Number of total registry queries seen since startup"),    // 自啟動以來傳遞regions參數查詢'/{version}/apps'的次數    GET_ALL_WITH_REMOTE_REGIONS("getAllWithRemoteRegionCounter", "Number of total registry queries with remote regions, seen since startup"),    // 自啟動以來請求/{version}/apps/{appId}的總次數    GET_APPLICATION("getApplicationCounter", "Number of total application queries seen since startup"),    // 自啟動以來register的總次數    REGISTER("registerCounter", "Number of total registers seen since startup"),    // 自啟動以來剔除過期例項的總次數    EXPIRED("expiredCounter", "Number of total expired leases since startup"),    // 自啟動以來statusUpdate的總次數    STATUS_UPDATE("statusUpdateCounter", "Number of total admin status updates since startup"),    // 自啟動以來deleteStatusOverride的總次數    STATUS_OVERRIDE_DELETE("statusOverrideDeleteCounter", "Number of status override removals"),    // 自啟動以來收到cancel請求時對應例項找不到的次數    CANCEL_NOT_FOUND("cancelNotFoundCounter", "Number of total cancel requests on non-existing instance since startup"),    // 自啟動以來收到renew請求時對應例項找不到的次數    RENEW_NOT_FOUND("renewNotFoundexpiredCounter", "Number of total renew on non-existing instance since startup"),    REJECTED_REPLICATIONS("numOfRejectedReplications", "Number of replications rejected because of full queue"),    FAILED_REPLICATIONS("numOfFailedReplications", "Number of failed replications - likely from timeouts"),    // 由於開啟rate limiter被丟棄的請求數量    RATE_LIMITED("numOfRateLimitedRequests", "Number of requests discarded by the rate limiter"),    // 如果開啟rate limiter的話,將被丟棄的請求數    RATE_LIMITED_CANDIDATES("numOfRateLimitedRequestCandidates", "Number of requests that would be discarded if the rate limiter's throttling is activated"),    // 開啟rate limiter時請求全量registry被丟棄的請求數    RATE_LIMITED_FULL_FETCH("numOfRateLimitedFullFetchRequests", "Number of full registry fetch requests discarded by the rate limiter"),    // 如果開啟rate limiter時請求全量registry將被丟棄的請求數    RATE_LIMITED_FULL_FETCH_CANDIDATES("numOfRateLimitedFullFetchRequestCandidates", "Number of full registry fetch requests that would be discarded if the rate limiter's throttling is activated");    private final String name;    private final String myZoneCounterName;    private final String description;    @Monitor(        name = "count",        type = DataSourceType.COUNTER    )    private final AtomicLong counter = new AtomicLong();    @Monitor(        name = "count-minus-replication",        type = DataSourceType.COUNTER    )    private final AtomicLong myZoneCounter = new AtomicLong();    private EurekaMonitors(String name, String description) {        this.name = name;        this.description = description;        DataCenterInfo dcInfo = ApplicationInfoManager.getInstance().getInfo().getDataCenterInfo();        if (dcInfo.getName() == Name.Amazon) {            this.myZoneCounterName = ((AmazonInfo)dcInfo).get(MetaDataKey.availabilityZone) + "." + name;        } else {            this.myZoneCounterName = "dcmaster." + name;        }    }    public void increment() {        this.increment(false);    }    public void increment(boolean isReplication) {        this.counter.incrementAndGet();        if (!isReplication) {            this.myZoneCounter.incrementAndGet();        }    }    public String getName() {        return this.name;    }    public String getZoneSpecificName() {        return this.myZoneCounterName;    }    public String getDescription() {        return this.description;    }    public long getCount() {        return this.counter.get();    }    public long getZoneSpecificCount() {        return this.myZoneCounter.get();    }    public static void registerAllStats() {        EurekaMonitors[] var0 = values();        int var1 = var0.length;        for(int var2 = 0; var2 < var1; ++var2) {            EurekaMonitors c = var0[var2];            Monitors.registerObject(c.getName(), c);        }    }    public static void shutdown() {        EurekaMonitors[] var0 = values();        int var1 = var0.length;        for(int var2 = 0; var2 < var1; ++var2) {            EurekaMonitors c = var0[var2];            DefaultMonitorRegistry.getInstance().unregister(Monitors.newObjectMonitor(c.getName(), c));        }    }}

作者:8aceSuper
連結:https://juejin.cn/post/6972785798298992648
來源:掘金


IT145.com E-mail:sddin#qq.com