服務治理通常是指通過限流、熔斷等手段,保障微服務的可靠運行,即運行時治理。更加寬泛的服務治理還包括微服務持續集成(開源軟件管理、自動化測試等),微服務部署最佳實踐(滾動升級、灰度發布等),微服務可觀測性能力(日志、監控、告警等)構建等。
??微服務治理專題主要探討運行時治理。隔離倉是適用于大部分故障模式,簡單有效的治理策略,本章介紹隔離倉的原理和作用。
隔離倉的定義和作用
??業務請求的處理都會占用系統資源,包括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等待比較長的情況下,系統的吞吐量和系統的可靠性是兩個沒法同時滿足的目標,如果要保證成功率不降低,并且吞吐量增加,那么勢必增加業務線程等系統資源占用,從而對系統整體的可靠性產生影響。對于耗時的請求,只能通過快速丟棄超過資源使用限制的部分,才能夠保證系統吞吐量不下降,并且避免產生系統性的全局功能影響。因此,系統應該合理的設計部分耗時請求的最大并發,在超過這些指標的時候,快速丟棄多余的請求。過度追求耗時請求的吞吐量而擴大線程池、連接池等,是很多應用系統最常見的設計誤區。
審核編輯 黃宇
-
IO
+關注
關注
0文章
448瀏覽量
39134 -
華為云
+關注
關注
3文章
2445瀏覽量
17410
發布評論請先 登錄
相關推薦
評論