華為雲服務治理 — 隔離倉的作用

禿頭也愛科技發表於2023-01-18

服務治理通常是指透過限流、熔斷等手段,保障微服務的可靠執行,即執行時治理。更加寬泛的服務治理還包括微服務持續整合(開源軟體管理、自動化測試等),微服務部署最佳實踐(滾動升級、灰度釋出等),微服務可觀測效能力(日誌、監控、告警等)構建等。

微服務治理專題主要探討執行時治理。隔離倉是適用於大部分故障模式,簡單有效的治理策略,本章介紹隔離倉的原理和作用。

隔離倉的定義和作用

業務請求的處理都會佔用系統資源,包括CPU、記憶體、執行緒池、連線池等。隔離倉是一種限制業務請求對系統資源佔用的服務治理策略,防止單個業務請求或者單個微服務例項過多的佔用系統資源,對其他業務請求以及系統總體的效能產生嚴重影響。

執行緒池是治理策略應用最廣泛的系統資源,通常所有請求都在一個共享的執行緒池處理,常見的隔離倉實現,都是限制請求對執行緒池的過多佔用。本文以  Spring Cloud Huawei   為例,演示其隔離倉在兩種故障場景下的作用。

·       場景一

微服務A呼叫微服務B,A和B分別有M個例項,模擬N個併發客戶端連續不斷的請求A。然後給B擴容1個例項。觀察應用治理策略和不應用策略的情況下,時延和TPS的變化情況。

·       場景二

微服務A呼叫微服務B,A和B分別有M個例項,B有兩個介面 X 和 Y, 其中X處理100ms,Y處理500 ms,模擬N 個併發客戶端透過A連續請求X介面,N 個併發客戶端透過A連續請求Y介面。觀察應用治理策略和不應用策略的情況下,時延和TPS的變化情況。

Spring Cloud Huawei 客戶端隔離倉的工作原理和效果

Spring Cloud Huawei  客戶端隔離倉   的主要作用是限制一個例項、或者一個例項的某個介面最大併發數,當一個例項的最大併發處理大於設定的閾值maxConcurrentCalls的時候,後續請求會在當前執行緒等待maxWaitDuration時間,如果這段時間有請求處理完畢,那麼後續請求會繼續處理,否則就會被丟棄,返回408錯誤。
Spring Cloud Huawei 
服務端隔離倉   的主要作用是限制一個介面的最大併發數,當一個介面的最大併發處理大於設定的閾值maxConcurrentCalls的時候,後續請求會在當前執行緒等待maxWaitDuration時間,如果這段時間有請求處理完畢,那麼後續請求會繼續處理,否則就會被丟棄,返回408錯誤。

·       場景一

微服務A的隔離倉配置:

servicecomb:
  matchGroup:
    allOperation: |
      matches:
        - apiPath:
            prefix: "/"
  instanceBulkhead:
    ## 隔離倉限制正在處理的請求數為20個,新來的請求等待1000毫秒沒有獲取到
    ## 許可,將被拒絕。
    allOperation: |
      maxConcurrentCalls: 20
      maxWaitDuration: 1000
# 為了匹配測試用例,設定微服務A的執行緒池大小為20
server:
  tomcat:
    threads:
      max: 20
      minSpare: 20

微服務A呼叫微服務B,A和B分別有1個例項,模擬40個併發客戶端連續不斷的請求A。然後給B擴容1個例項。觀察應用治理策略和不應用策略的情況下,時延和TPS的變化情況。

測試結果:

不使用隔離倉:

Total time:121852
Success count:200000
Timeout count:0
Error count:0
Average Latency:24
|(10,7942)||(20,90667)||(50,93017)||(100,7041)||(200,1151)||(500,173)||(1000,9)|

使用隔離倉:

Total time:112440
Success count:200000
Timeout count:0
Error count:0
Average Latency:22
|(10,8683)||(20,100275)||(50,86137)||(100,4106)||(200,679)||(500,120)||(1000,0)|

從上述結果可以看出使用隔離倉的情況下,時延大於200ms的請求明顯減少。 這個結果說明隔離倉的使用並沒有降低系統的處理效能,甚至可能帶來一些效能的改善,減少時延偏差較大的請求數量。上述測試場景,並沒有演示新啟動例項導致故障的場景。如果需要模擬這種場景,可以考慮微服務A部署10個例項,並且採用500個併發客戶端訪問。

·       場景二

微服務A的隔離倉配置:

servicecomb:
  matchGroup:
    allOperation: |
      matches:
        - apiPath:
            # 對耗時的介面配置隔離倉
            prefix: "/benchmark/delay/z100"
  instanceBulkhead:
    ## 隔離倉限制正在處理的請求數為20個,新來的請求等待1000毫秒沒有獲取到
    ## 許可,將被拒絕。
    allOperation: |
      maxConcurrentCalls: 20
      maxWaitDuration: 1000
 

# 為了匹配測試用例,設定微服務A的執行緒池大小為40
server:
  tomcat:
    threads:
      max: 40
      minSpare: 40

微服務A呼叫微服務B,A和B分別有1個例項,B有兩個介面 X 和 Y, 其中X處理1ms,Y處理100 ms,模擬20 個併發客戶端透過A連續請求X介面,20 個併發客戶端透過A連續請求Y介面。觀察應用治理策略和不應用策略的情況下,時延和TPS的變化情況。

測試結果:

不使用隔離倉:

Total time:69029
Success count:40000
Timeout count:0
Error count:0
Average Latency:68
|(10,2175)||(20,12078)||(50,5727)||(100,17)||(200,20003)||(500,0)||(1000,0)||(10000,0)|

使用隔離倉:

Total time:107354
Success count:40000
Timeout count:0
Error count:0
Average Latency:106
|(10,2217)||(20,14264)||(50,3506)||(100,7)||(200,15738)||(500,4268)||(1000,0)||(10000,0)|

從上述結果可以看出使用隔離倉的情況下,時延小於20ms的請求有所增加,但是時延超過500ms的請求增加更加明顯。這是因為測試場景屬於IO密集型場景,使用隔離倉,降低了Y介面的併發度,大量請求排隊,導致整體的時延大幅增長。下面把客戶端隔離倉去掉,改為服務端隔離倉,再看看效果。

微服務B的隔離倉配置:

servicecomb:
  matchGroup:
    allOperation: |
      matches:
        - apiPath:
            # 對耗時的介面配置隔離倉
            prefix: "/benchmark/delay/z100"
  bulkhead:
    ## 隔離倉限制正在處理的請求數為20個,新來的請求等待1000毫秒沒有獲取到
    ## 許可,將被拒絕。
    allOperation: |
      maxConcurrentCalls: 10
      maxWaitDuration: 1000
 

# 為了匹配測試用例,設定微服務B的執行緒池大小為20
server:
  tomcat:
    threads:
      max: 20
      minSpare: 20

微服務A呼叫微服務B,A和B分別有1個例項,B有兩個介面 X 和 Y, 其中X處理1ms,Y處理100 ms,模擬20 個併發客戶端透過A連續請求X介面,20 個併發客戶端透過A連續請求Y介面。觀察應用治理策略和不應用策略的情況下,時延和TPS的變化情況。

測試結果:

不使用隔離倉:

Total time:110685
Success count:40000
Timeout count:0
Error count:0
Average Latency:109
|(10,160)||(20,1207)||(50,4378)||(100,14091)||(200,19906)||(500,258)||(1000,0)||(10000,0)|

使用隔離倉:

Total time:214565
Success count:40000
Timeout count:0
Error count:0
Average Latency:213
|(10,46)||(20,734)||(50,279)||(100,3941)||(200,14972)||(500,19995)||(1000,33)||(10000,0)|

從上述結果可以看出使用隔離倉的情況下,平均時延和效能同樣會下降。我們適當調整下隔離倉的限制,快速丟棄一些請求:

servicecomb:
  matchGroup:
    allOperation: |
      matches:
        - apiPath:
            # 對耗時的介面配置隔離倉
            prefix: "/benchmark/delay/z100"
  bulkhead:
    ## 隔離倉限制正在處理的請求數為20個,新來的請求等待1000毫秒沒有獲取到
    ## 許可,將被拒絕。
    allOperation: |
      maxConcurrentCalls: 10
      maxWaitDuration: 10
 

# 為了匹配測試用例,設定微服務B的執行緒池大小為20
server:
  tomcat:
    threads:
      max: 20
      minSpare: 20

使用隔離倉的測試結果:

Total time:68189
Success count:22733
Timeout count:1
Error count:17266
Average Latency:115
|(10,53)||(20,2096)||(50,19470)||(100,13025)||(200,3885)||(500,1361)||(1000,109)||(10000,1)|

上述結果可以看出,快速丟棄請求的情況下,時延小於50ms的請求大於20000個。隔離倉保證了處理很快的介面能夠得到快速成功執行,前提條件是處理很慢的介面不佔用資源,快速失敗。

隔離倉總結

隔離倉的使用,在計算密集型場景下,對系統的效能影響很小,甚至可以起到一定的效能改善作用。在IO密集型場景下,由於隔離倉降低了請求的併發執行執行緒,會導致吞吐量降低和時延增加。

也可以看出,在IO等待比較長的情況下,系統的吞吐量和系統的可靠性是兩個沒法同時滿足的目標,如果要保證成功率不降低,並且吞吐量增加,那麼勢必增加業務執行緒等系統資源佔用,從而對系統整體的可靠性產生影響。對於耗時的請求,只能透過快速丟棄超過資源使用限制的部分,才能夠保證系統吞吐量不下降,並且避免產生系統性的全域性功能影響。因此,系統應該合理的設計部分耗時請求的最大併發,在超過這些指標的時候,快速丟棄多餘的請求。過度追求耗時請求的吞吐量而擴大執行緒池、連線池等,是很多應用系統最常見的設計誤區。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70022909/viewspace-2932718/,如需轉載,請註明出處,否則將追究法律責任。

相關文章