爲什麼要用異步?
在我們平時的業務系統中,文件導入,文件導出是一個很常見的業務需求。正常情況下,同步導出就可以滿足我們80%的需求。但是對於數據量大,業務拼接複雜的系統來說,導出超時,導入超時是不可避免的,而且是無法忍受的。異步能讓業務線程在後臺運行,沒有等待時間,處理完成通知出來就行了。這種場景在現實生活中也很常見,比如醫院裏面拍CT,做體檢時的體檢報告,都是延後去拿結果的。
異步導出的使用場景
那什麼時候會需要用到異步呢?統計、導入、導出、發送模板消息、訂單狀態變更後的複雜業務處理。。。
它們都有共同的特點:
1.處理耗時長
2.業務優先級低
3.容易超時
4.數據量大
文件導出
異步導出的優缺點
異步的優點:
它能解決導出超時問題,能大大的提高接口請求處理速度,提高吞吐量,提升系統性能
任何事情都有兩面性,也許不具有絕對性,但是在這裏是成立的。既然它有那麼多優點,當然也會有缺點。
異步的缺點:
它比同步導出要複雜得多,接口多了幾倍,所需服務器也要多,學習成本高,開發成本高
架構圖設計
架構解析
按流程來:
1.前端發出導出請求
2.接口服務器接到請求並校驗參數
3.如果參數不符,直接彈出校驗結果,流程結束!
4.生成一個任務實體,狀態設爲處理中並將實體寫入redis。開啓異步線程,在異步方法中調用導出接口。返回給前端在處理中狀態
5.前端接受到已經在處理中返回值,開啓ajax輪詢,每隔10秒請求一次任務查詢狀態接口
6.導出接口將數據拼接完成
7.將數據傳到文件服務器生成文件並返回url
8.從redis中取出任務實體將url寫入,並且將狀態設爲已完成並更新redis(後端處理流程就結束了)
9.前端ajax請求發現返回值狀態變成已完成後,取出url並停止輪詢。
10.前端請求清除任務實體接口,通過後端接口將redis中的對象移除。
11.前端展示導出結果,自動下載或者手動點擊可以根據業務來。
這裏還有一個頁面初始化的按鈕變化流程。
1.打開頁面後導出按鈕置灰不可點擊
2.ajax請求查詢任務狀態接口,如果顯示沒有任務在進行中,那就讓導出按鈕可以點擊。如果狀態是導出已完成,則顯示下載按鈕相關頁面
另外,爲了防止意外出現redis死鎖的情況,導致客戶一直用不了導出功能,每個任務redis對象都有過期時間,設置爲30分鐘。也就是說,不管導出任務執行是否完成,30分鐘後任務將放棄,用戶可以再次點擊導出按鈕。
數據來源
接口設計
接口列表
1.獲取任務狀態 getTaskStatus
返回實體TaskResultOut:
字段 | l類型 | 是否可爲空 | 註釋 |
status |
int | 不,默認0 | 任務狀態(0=未開始,1=進行中 2=已完成) |
message | string | 是 | 提示信息(正確或錯誤) |
url | string | 是 | 文件地址 |
state | bool | 不,默認fasle | 任務成功還是失敗(y) |
2.註冊導出任務(導出) registerExportTask
返回true/false,表明是否註冊成功
3.清除任務狀態 clearTaskInfo
返回true/fasle,表明清除是否成功
前端設計
前端js由前端編寫,具體的由於嵌套太深,就不貼出來了,在架構解析中已經說的很詳細了。
"export": function(e) {
return t.post(r.api.form["export"], e, {})
},
getTaskStatus: function(e) {
return t.post(r.api.form.getTaskStatus, e, {})
},
registerExportTask: function(e) {
return t.post(r.api.form.registerExportTask, e, {})
},
clearTaskInfo: function(e) {
return t.post(r.api.form.clearTaskInfo, e, {})
}
項目實際應用
點擊取消後
異步導出的整個流程和設計就全在這裏了。
文件導入的設計
由於篇幅有限,且導入的流程大同小異。直接奉上一副設計圖吧。
多級異步導入方案
最後
代碼是沒有滴,東西是要自己創造滴!
--------------------------------------------------神祕的分界線---------------------------------------------------
2018-04-15補充
一些人說需要貼代碼,但這個是涉及3個服務器的協作,(前端服務器,node層web服務器,純後端接口服務器),代碼太過於零散且沒有多餘的技術含量,無法貼上來,加上這套機制我在C#大型電商項目和java的多個項目中都有部署應用。對於不同語言有不同的實現。就目前來說,在電商項目中穩定運行了一年多,它的可靠性已經得到了實際應用的考驗。
服務器需求
組成這套系統最少要求(web服務器一臺,接口服務器一臺,redis服務器一臺,文件服務器一臺)
如果在java體系裏面,前後端完全分離,且有服務器資源充足的情況下
前端服務器
node層服務器(集羣)
後端接口層服務器(集羣)
redis服務器
文件服務器
架構定位
對於小公司來說,服務器資源沒有那麼充足,可能實施起來有難度,且開發和學習成功較高
對於大型公司來說,對於大數據量和複雜業務的導出,可能早就有了成熟穩定的框架來支持,例如任務中心這種完善的異步消息來實現,具有高可用,可伸縮的等穩定性很強的系統,也用不到了,
因此這套架構適合於中型規模的公司
各層級職責解析
node或者web
如果有疑問可以找我解答。