1. 程式人生 > >架構設計 | 非同步處理流程,多種實現模式詳解

架構設計 | 非同步處理流程,多種實現模式詳解

本文原始碼:[GitHub·點這裡](https://github.com/cicadasmile/data-manage-parent) || [GitEE·點這裡](https://gitee.com/cicadasmile/data-manage-parent) # 一、非同步處理 ## 1、非同步概念 非同步處理不用阻塞當前執行緒來等待處理完成,而是允許後續操作,直至其它執行緒將處理完成,並回調通知此執行緒。 必須強調一個基礎邏輯,非同步是一種設計理念,非同步操作不等於多執行緒,MQ中介軟體,或者訊息廣播,這些是可以實現非同步處理的方式。 同步處理和非同步處理相對,需要實時處理並響應,一旦超過時間會結束會話,在該過程中呼叫方一直在等待響應方處理完成並返回。同步類似電話溝通,需要實時對話,非同步則類似簡訊交流,傳送訊息之後無需保持等待狀態。 ## 2、非同步處理優點 雖然非同步處理不能實時響應,但是處理複雜業務場景,多數情況都會使用非同步處理。 - 非同步可以解耦業務間的流程關聯,降低耦合度; - 降低介面響應時間,例如使用者註冊,非同步生成相關資訊表; - 非同步可以提高系統性能,提升吞吐量; - 流量削峰即把請求先承接下來,然後在非同步處理; - 非同步用在不同服務間,可以隔離服務,避免雪崩; 非同步處理的實現方式有很多種,常見多執行緒,訊息中介軟體,釋出訂閱的廣播模式,其根據邏輯在於先把請求承接下來,放入容器中,在從容器中把請求取出,統一排程處理。 **注意**:一定要監控任務是否產生積壓過度情況,任務如果積壓到雪崩之勢的地步,你會感覺每一片雪花都想勇闖天涯。 ## 3、非同步處理模式 非同步流程處理的實現有好多方式,但是實際開發中常用的就那麼幾種,例如: - 基於介面非同步響應,常用在第三方對接流程; - 基於訊息生產和消費模式,解耦複雜流程; - 基於釋出和訂閱的廣播模式,常見系統通知 非同步適用的業務場景,對資料強一致性的要求不高,非同步處理的資料更多時候追求的是最終一致性。 # 二、介面響應非同步 ## 1、流程描述 基於介面非同步響應的方式,有一個本地業務服務,第三方介面服務,流程如下: ![](https://img2020.cnblogs.com/blog/1691717/202006/1691717-20200604213312766-506220106.png) - 本地服務發起請求,呼叫第三方服務介面; - 請求包含業務引數,和成功或失敗的回撥地址; - 第三方服務實時響應流水號,作為該呼叫的標識; - 之後第三方服務處理請求,得到最終處理結果; - 如果處理成功,回撥本地服務的成功通知介面; - 如果處理失敗,回撥本地服務的失敗通知介面; - 整個流程基於部分非同步和部分實時的模式,完整處理; **注意**:如果本地服務多次請求第三方服務,需要根據流水號判斷該請求的狀態,業務的狀態設計也是極其複雜,要根據流水號和狀態追溯整個流程的執行進度,避免錯亂。 ## 2、流程實現案例 **模擬基礎介面** ```java @RestController public class ReqAsyncWeb { private static final Logger LOGGER = LoggerFactory.getLogger(ReqAsyncWeb.class); @Resource private ReqAsyncService reqAsyncService ; // 本地交易介面 @GetMapping("/tradeBegin") public String tradeBegin (){ String sign = reqAsyncService.tradeBegin("TradeClient"); return sign ; } // 交易成功通知介面 @GetMapping("/tradeSucNotify") public String tradeSucNotify (@RequestParam("param") String param){ LOGGER.info("tradeSucNotify param={"+ param +"}"); return "success" ; } // 交易失敗通知介面 @GetMapping("/tradeFailNotify") public String tradeFailNotify (@RequestParam("param") String param){ LOGGER.info("tradeFailNotify param={"+ param +"}"); return "success" ; } // 第三方交易介面 @GetMapping("/respTrade") public String respTrade (@RequestParam("param") String param){ LOGGER.info("respTrade param={"+ param +"}"); reqAsyncService.respTrade(param); return "NO20200520" ; } } ``` **模擬第三方處理** ```java @Service public class ReqAsyncServiceImpl implements ReqAsyncService { private static final String serverUrl = "http://localhost:8005" ; @Override public String tradeBegin(String param) { String orderNo = HttpUtil.get(serverUrl+"/respTrade?param="+param); if (StringUtils.isEmpty(orderNo)){ return "Trade..Fail..."; } return orderNo ; } @Override public void respTrade(String param) { try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } Thread thread01 = new Thread( new RespTask(serverUrl+"/tradeSucNotify?param="+param),"SucNotify"); Thread thread02 = new Thread( new RespTask(serverUrl+"/tradeFailNotify?param="+param),"FailNotify"); thread01.start(); thread02.start(); } } ``` # 三、生產消費非同步 ## 1、流程描述 這裡基於Kafka中介軟體,演示流程訊息生成,訊息處理的非同步解耦流程,基本步驟: ![](https://img2020.cnblogs.com/blog/1691717/202006/1691717-20200604213258019-304684157.png) - 訊息生成之後,寫入Kafka佇列 ; - 訊息處理方獲取訊息後,進行流程處理; - 訊息在中介軟體提供的佇列中持久化儲存 ; - 訊息發起方如果掛掉,不影響訊息處理 ; - 消費方如果掛掉,不影響訊息生成; 基於這種訊息中介軟體模式,完成業務解耦,提高系統吞吐量,是架構中常用的方式。 ## 2、流程實現案例 **訊息傳送** ```java @Service public class KafkaAsyncServiceImpl implements KafkaAsyncService { @Resource private Kafka