做事不能急,得一步異步的來;
一、業務場景
在系統開發的程序中,必然存在耗時極高的動作,是基于請求回應模式無法解決的問題,通常會采用解耦的思維,并基于異步或者事件驅動的方式去調度整個流程的完整執行;
檔案任務:在系統決議大檔案資料時,在獲取任務之后,會異步處理后續檔案讀寫流程;
中間表:執行復雜場景的資料分析時,收集完待分析的物件之后,會并發執行各個維度的采集動作,并依次將資料寫入臨時的中間表中,方便資料查詢動作;
在上述場景中,基于單次請求回應無法執行整個程序,必須對流程分段分步和異步推進,在流程中根據場景去判斷,是異步有序驅動,還是異步并發處理,并基于各個節點的執行狀態判斷動作是否成功,
二、任務管理
復雜任務的執行周期相對偏長,要確保穩定的執行則需要對任務做精細的設計和管理,通常會基于如下幾個因素去描述任務:

- 場景:定義任務的主題場景,便于將多種任務做統一管理和調度,例如:檔案、資料、報表等;
- 計劃:對任務做好步驟的拆分,并制定和推進相應的執行計劃,例如:有序調度、并發執行等;
- 狀態:針對任務和節點的執行計劃,都要提供細節的狀態定義,例如:開始/結束,進行中/已完成,成功/失敗等;
設計合理的任務結構,以便更高效的管理流程,根據主題場景做任務分類,添加相應的執行計劃,根據狀態跟蹤任務執行程序,并對失敗動作進行捕捉和重試;
三、設計思路
1、同步請求回應
服務之間的通信模式一般分為:同步和異步兩種;同步是指在請求端發出動作之后,會一直等待回應端完成,或者回應超時導致熔斷,即在一次請求呼叫中耦合所有的處理流程;

服務中大部分的請求都是同步回應模式,可以提高系統的回應速度;但是在分布式中,首先要控制超時熔斷的時間,避免在流量高峰期請求堆積,拖垮整個服務;另外對于被大量呼叫的公共服務,要提高并發的支撐能力,降低對請求鏈路的性能影響,
2、異步解耦模式
異步模式的最大優點就是實作請求和回應的完全解耦,任務只需要觸發一次開始動作,后續的流程就會逐步的推進直到結束;各個服務節點處理邏輯不會受到整個請求鏈路的耗時限制;

實作異步有多種方式,例如:請求回呼、發布訂閱、Broker代理等;在之前異步章節中有詳細描述,這里不再贅述;異步消除了服務節點之間的依賴關系,但是也同樣提高了流程的復雜性;
3、事件驅動設計
事件驅動是一個抽象的概念,即通過事件的方式實作多個服務間的協同,驅動整個流程的處理邏輯;在業務層面是一種設計思想,在技術層面通常采用發布訂閱的方式,同樣也可以消除服務間的強依賴關系;

事件和異步在模式上很類似,事件驅動在設計上更加精細,例如在訂單場景中:將訂單的狀態變化作為一個事件,服務間通過訊息傳遞的方式,依次處理庫存服務、物流服務等;由于事件攜帶了一定的業務資訊和狀態,流程解耦更加徹底的同時復雜度也會更高,
四、實踐總結
1、結構設計
在結構設計中圍繞任務、節點、資料三個核心要素,以確保對任務的執行程序有完整的跟蹤和管理,要實作對任務的節點及相關的操作,具備執行重試或者直接取消撤回的控制;

狀態管理是一項很復雜的作業,要衡量任務中各個狀態標識是否合理,就要實時監控狀態的變化,并且基于各種極端情況去驗證流程,例如:重試設計、任務取消、任務暫停,
2、高并發管理
任務型的場景加上復雜的管理流程,執行時間自然也很長,如果場景中涉及到大檔案的決議、或者資料調度,自然會引入任務分割與并發執行的機制;
比較常用的思路:根據任務調度的集群數,對資料核心編號進行哈希計算,可以采用取模和分段兩種演算法,然后基于多執行緒的方式并發處理各自服務內的分管任務,
3、管理模型
不管是觀察者模式,或者發布訂閱模型,又或者說事件驅動設計,都可以理解為生產/消費的關系模型,圍繞生產、存盤、消費三個節點做管理;

- 生產端:負責創建具體的訊息主體,在總線模式中,通常將訊息進行入庫存盤,然后再執行佇列推送,并跟蹤該程序的狀態變化,保證庫和佇列的一致性;
- 訊息體:描述動作的發布方和消費方,關鍵的狀態資訊變化,唯一標識和創建時間及版本,其余則根據場景需要定義即可;
- 消費端:在消費時要關注的核心問題即失敗重試,要避免重試機制引起資料不一致的問題,可以對消費進行加鎖或者訊息狀態校驗,以實作冪等的效果;
- 存盤端:通常采用資料庫和訊息中間件雙存盤的模式,并且需要保證二者動作的同時成功或者失敗,順序為先入庫再執行佇列推送;
整個模型在設計思路上比較合理,但是架構的復雜性也變的很高,比如資料一致性問題、狀態機制、事務、冪等性、流程中斷等;整個鏈路需要詳細的追蹤記錄并且可視化管理,開發補償動作的介面,用來及時解決可能出現的突發問題,
4、組件案例
Spring框架本身就極具復雜度,這里單看事件模型的設計,包含三個核心角色:事件、發布、監聽;與觀察者設計模式在理念上相同;

事件:ApplicationEvent基礎抽象類繼承自JDK中EventObject類,具體事件要繼承該類;source事件源,timestamp發生的系統時間;
public class OrderState {
// 基礎要素
private Integer eventId ;
private String version ;
private Long createTime ;
// 訊息定位
private String source ;
private String target ;
// 狀態變化
private Integer orderId ;
private Integer stateFrom ;
private Integer stateTo ;
}
public class OrderStateEvent extends ApplicationEvent {
public OrderStateEvent (OrderState orderState){
super(orderState);
}
}
發布者:Spring定義的頂級介面ApplicationEventPublisher,提供事件發布的能力;
@Service
public class EventService implements ApplicationContextAware, ApplicationEventPublisherAware {
private ApplicationEventPublisher applicationEventPublisher;
public void changeState (Integer orderId,Integer stateFrom,Integer stateTo){
OrderState orderState = new OrderState() ;
OrderStateEvent orderStateEvent = new OrderStateEvent(orderState) ;
logger.info(Thread.currentThread().getName()+";"+orderStateEvent);
applicationEventPublisher.publishEvent(orderStateEvent);
}
}
監聽者:實作JDK中頂級介面EventListener,Spring擴展了多種事件監聽器,以實作各種場景的需求,例如:有序無序、同步異步等;
@Component
public class OrderStateListener implements ApplicationListener<OrderStateEvent> {
private static final Logger logger = LoggerFactory.getLogger(OrderStateListener.class) ;
@Async
@Override
public void onApplicationEvent(OrderStateEvent orderStateEvent) {
logger.info(Thread.currentThread().getName()+";"+orderStateEvent);
}
}
五、參考原始碼
應用倉庫:
https://gitee.com/cicadasmile/middle-ware-parent
編程檔案:
https://gitee.com/cicadasmile/butte-java-note
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/470550.html
標籤:Java
上一篇:【面試普通人VS高手系列】Spring中事務的傳播行為有哪些?
下一篇:【SSM框架】Mybatis筆記 --- MyBatis 中應用動態代理;#{}占位符與${}占位符;執行DML后回傳主鍵值;UUID
