spring非同步請求action以及預設配置坑爹的效能以及對應效能調優
前言
非同步請求----客戶端一旦發起請求,伺服器立刻將請求丟到其他執行緒處理,而當前的接收執行緒就能閒下來繼續接收客戶端請求了,這個看起來效能槓槓的,這篇文章就來入坑非同步請求。
spring非同步請求的配置
預設配置下的非同步請求效能表現
進行這個操作前,請先確認已經配置好了,然後能夠執行起來,還有,順便看一看visual vm的用法,這次要實踐了。
jvm效能監控–visualvm的簡單說明及用法
正式開始:
注意,
mvc:async-support是在mvc:annotation-driven下面配置的,而不是task:annotation-driven,還有,mvc:annotation-driven是在spring-mvc.xml下配置的—即,這些個配置都是mvc上下文下面的,因為controller本來就在mvc上下文下面。。
不要配錯了!
編寫action程式碼,設定sleep為的是模擬耗時操作:
然後啟動伺服器,訪問這個api:
好了,開啟jvisual vm 工具:
可以看到tomcat已經在了,開啟,分別檢視幾個標籤,記住執行緒總數,活動執行緒數量。
var Ajax={ get: function(url, fn) { // XMLHttpRequest物件用於在後臺與伺服器交換資料 var xhr = new XMLHttpRequest(); xhr.open('GET', url, true); xhr.onreadystatechange = function() { // readyState == 4說明請求已完成 if (xhr.readyState == 4 && xhr.status == 200 || xhr.status == 304) { // 從伺服器獲得資料 fn.call(this, xhr.responseText); } }; xhr.send(); }, // datat應為'a=a1&b=b1'這種字串格式,在jq裡如果data為物件會自動將物件轉成這種字串格式 post: function (url, data, fn) { var xhr = new XMLHttpRequest(); xhr.open("POST", url, true); // 新增http頭,傳送資訊至伺服器時內容編碼型別 xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); xhr.onreadystatechange = function() { if (xhr.readyState == 4 && (xhr.status == 200 || xhr.status == 304)) { fn.call(this, xhr.responseText); } }; xhr.send(data); } }; var __call_times=0; var _call_interval=setInterval(function(){ __call_times++; Ajax.get('/api/region/getChildrenByCallable.do',function(){ console.log('呼叫中...');}); if(__call_times>1000){ clearInterval(_call_interval); } }, 10);
然後:
然後,檢視jvisual vm,觀測執行緒情況:
活動執行緒已經有了 MvcAsync等等命名的執行緒了,那麼已經完成的執行緒有:
隔一段時間再看:
活動執行緒有:
已經完成的執行緒有:
可以認為,預設的非同步請求處理方式是不停新建一個新的執行緒,這樣還真的有點坑爹,詳情可以參考下面文章,作者也是深深被坑過的兄dei:
那麼,解決方案是什麼?
非同步請求處理效能優化方案
解決方案是,定義一個專用執行緒池,替換掉spring的預設執行緒池。
注意,在 mvc:async-support 標籤裡設定 task-executor。
然後,重啟伺服器,重複上述步驟:
好了,開動瀏覽器,測試:
第一次觀測:
從這裡起碼可以看出來,已經採用了定製的執行緒池了。。因為。。連執行緒的名字都變了,變成actionAsyncExecutor+編號形式。
隔一段時間來看:
看到這裡已經可以放心了。。
沒有新的執行緒產生,一直都是那幾個執行緒在忙,執行緒也不會變更為完成狀態直接退休。
這是解決方案之一。
總結
這篇非同步請求處理以及效能調休的篇幅雖然不多,然而裡面涉及的東西是相當多的。有興趣的話可以親自動手試試,保證有所收穫的。