背景:
有一次在生產環境,突然出現了很多筆還款單被掛起,后來排查原因,發現是內部系統調用時出現了hystrix調用異常。在開發過程中,因為核心線程數設置的比較大,沒有出現這種異常。放到了測試環境,偶爾有出現這種情況,后來在網上查找解決方案,網上的方案是調整maxqueuesize屬性就好了,當時調整了一下,確實有所改善。可沒想到在生產環境跑了一段時間后卻又出現這種了情況,此時我第一想法就是去查看maxqueuesize屬性,可是maxqueuesize屬性是設置值了。當時就比較納悶了,為什么maxqueuesize屬性不起作用,后來通過查看官方文檔發現hystrix還有一個queuesizerejectionthreshold屬性,這個屬性是控制隊列最大閾值的,而hystrix默認只配置了5個,因此就算我們把maxqueuesize的值設置再大,也是不起作用的。兩個屬性必須同時配置
先看一下正確的hystrix配置姿勢。
application.yml:
1
2
3
4
5
6
|
hystrix: threadpool: default : coresize: 200 #并發執行的最大線程數,默認 10 maxqueuesize: 1000 #blockingqueue的最大隊列數,默認值- 1 queuesizerejectionthreshold: 800 #即使maxqueuesize沒有達到,達到queuesizerejectionthreshold該值后,請求也會被拒絕,默認值 5 |
接下來編寫一個測試類,來驗證幾種錯誤配置,看看會出現什么情況。
測試類代碼(a調用方):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
/** * @author: xiongfeng * @description: * @date: created in 11:12 2018/6/11 */ public class repaymenthelpertest extends fundapplicationtests { @autowired repaymenthelper repaymenthelper; @autowired private routerfeign routerfeign; @test public void hystrixtest() throws interruptedexception { for ( int i = 0 ; i < 135 ; i++) { new thread( new runnable() { @override public void run() { job(); } }).start(); } thread.currentthread().join(); } public void job() { string repaymentno = "xf1002" ; string transno = "t4324324234" ; string reqno = "xf1002" ; string begintime = "20180831130030" ; string endtime = "20180831130050" ; transrecqueryreqdto transrecqueryreqdto = new transrecqueryreqdto(); transrecqueryreqdto.settransno(transno); transrecqueryreqdto.setbegintime(begintime); transrecqueryreqdto.setendtime(endtime); transrecqueryreqdto.setreqno(reqno); resp<list<transrecdto>> querytransreclistresp = routerfeign.querytransrec( new req<>(repaymentno, "2018080200000002" , null , null , transrecqueryreqdto)); system.out.println(string.format( "獲取結果為:【%s】" , jsonutil.tojson(querytransreclistresp))); } } |
這個測試類的作用就是創建135個線程,通過routerfeign類并發請求b服務方,看看請求結果是否出現異常。
feign調用代碼:
1
2
3
4
5
6
7
8
9
10
11
12
|
@feignclient (value = "${core.name}" , fallbackfactory = routerfeignbackfactory. class , path = "/router" ) public interface routerfeign { /** * 代扣結果查詢 * @param transrecqueryreqdtoreq * @return */ @postmapping ( "/querytransrec" ) resp<list<transrecdto>> querytransrec( @requestbody req<transrecqueryreqdto> transrecqueryreqdtoreq); } |
這個類,就是通過feign方式去調用b服務方的客戶端
服務提供方代碼(b服務方):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
/** * @author: xiongfeng * @description: * @date: created in 16:04 2018/5/24 */ @api ( "還款服務" ) @refreshscope @restcontroller @requestmapping ( "/router" ) public class testcontroller { private static logger logger = loggerfactory.getlogger(testcontroller. class ); // 計數器 private static atomicinteger count = new atomicinteger( 1 ); @apioperation (value = "代扣結果查詢" ) @postmapping ( "/querytransrec" ) resp<list<transrecdto>> querytransrec( @requestbody req<transrecqueryreqdto> transrecqueryreqdtoreq) throws interruptedexception { system.out.println(string.format( "查詢支付結果......計數: %s" , count.getandadd( 1 ))); thread.sleep( 500 ); return resp.success(respstatus.success.getdesc(), null ); } |
這個類的作用,就是一個服務提供方,計數并返回結果。
下面我們看一下幾種錯誤的配置。
案例一(將核心線程數調低,最大隊列數調大一點,但是隊列拒絕閾值設置小一點):
1
2
3
4
5
6
|
hystrix: threadpool: default : coresize: 10 maxqueuesize: 1000 queuesizerejectionthreshold: 20 |
此時的結果:
左窗口是b服務方,右窗口是a調用方。從結果可以看出,調用135次,成功32次左右,其余線程全部拋異常。
案例二(將核心線程數調低,最大隊列數調小一點,但是隊列拒絕閾值設置大一點):
1
2
3
4
5
6
|
hystrix: threadpool: default : coresize: 10 maxqueuesize: 15 queuesizerejectionthreshold: 2000 |
此時的結果:
java.util.concurrent.rejectedexecutionexception: task java.util.concurrent.futuretask@7d6d472b rejected from java.util.concurrent.threadpoolexecutor@17f8bcb7[running, pool size = 3, active threads = 3, queued tasks = 15, completed tasks = 0]
左窗口是b服務方,右窗口是a調用方。從結果可以看出,調用135次,成功25次左右,其余線程全部拋異常。。
案例三(將核心線程數調低,最大隊列數調大一點,但是隊列拒絕閾值不設置值):
1
2
3
4
5
|
hystrix: threadpool: default : coresize: 10 maxqueuesize: 1500 |
此時的結果:
java.util.concurrent.rejectedexecutionexception: rejected command because thread-pool queuesize is at rejection threshold.
左窗口是b服務方,右窗口是a調用方。此時的結果和案例一的情況一樣,調用135次,成功47次左右,其余線程全部拋異常。報錯跟案例一一樣
案例四(將核心線程數調低,最大隊列數不設值,但是隊列拒絕閾值設置的比較大):
1
2
3
4
5
|
hystrix: threadpool: default : coresize: 10 queuesizerejectionthreshold: 1000 |
此時的結果:
java.util.concurrent.rejectedexecutionexception: task java.util.concurrent.futuretask@23d268ea rejected from java.util.concurrent.threadpoolexecutor@66d0e2f4[running, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]
at java.util.concurrent.threadpoolexecutor$abortpolicy.rejectedexecution(threadpoolexecutor.java:2063)
at java.util.concurrent.threadpoolexecutor.reject(threadpoolexecutor.java:830)
at java.util.concurrent.threadpoolexecutor.execute(threadpoolexecutor.java:1379)
at java.util.concurrent.abstractexecutorservice.submit(abstractexecutorservice.java:112)
左窗口是b服務方,右窗口是a調用方。此時的結果和案例二的情況一樣,調用135次,成功10次左右,其余線程全部拋異常。報錯跟案例二一樣
下面來看一看正確的配置案例
案例一:將核心線程數調低,最大隊列數和隊列拒絕閾值的值都設置大一點):
1
2
3
4
5
6
|
hystrix: threadpool: default : coresize: 10 maxqueuesize: 1500 queuesizerejectionthreshold: 1000 |
此時的結果:
左窗口是b服務方,右窗口是a調用方。此時的結果就完全正常了,并發請求了135次,全部成功!
結論:官方默認隊列閾值只有5個, 如果要調整隊列,必須同時修改maxqueuesize和queuesizerejectionthreshold屬性的值,否則都會出現異常!參考文檔:
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:https://segmentfault.com/a/1190000018049081