對賬流程
對賬流程節點:數據抓取、數據清洗、對賬、結果匯總4個操作節點;
對賬結果:上游單邊(訂單上游存在,下游不存在)、下游單邊、金額不一致(上下游訂單都存在,但是金額不同);
對賬操作節點功能簡介
- 數據抓取:拉取待對賬業務數據,生成原始憑證數據;
- 數據清洗:原始憑證數據清洗,生成對賬憑證數據;
- 對賬:對賬憑證對賬,記錄對賬結果;
- 匯總:對賬結果匯總;
系統設計需要處理的問題
- 數據量較大時,要分組處理;
- 數據分組時,避免相同單號的分到不同的組,導致數據單邊;
- 應用多實例部署,避免多實例并發沖突,避免數據重復處理或數據遺漏;
- 對賬流程,可以個性化配置,不同業務需要的對賬流程可以不同;
- 對賬鏈路中,任意節點的數據,都可以沿著對賬鏈路往下執行;
系統實現方案
- 數據分表存儲,避免后期數據量大了之后再分表時的數據遷移問題,并對數據進行了分組;
- 使用task處理方式,結合分布式定時任務組件xxljob,避免多實例沖突及數據重復處理問題(按表維度創建task任務);
- task處理流程進行模板化,模板方法抽象task處理的公共流程;
使用到的設計模式
- 責任鏈模式;
- 模板模式;
責任鏈模式
- 對于對賬流程,目前的對賬分為抓取、清洗、對賬、匯總4個功能節點;
- 責任鏈模式靈活組裝、增減功能節點的流轉順序和個數;
- 任意節點開始,進入鏈路,都可以繼續鏈路的流轉(常規代碼實現的責任鏈不支持該需求);
模板模式
- 依賴task觸發數據處理;
- task控制任務的并發處理;
代碼結構
模板模式代碼繼承關系
- BaseTask<T>:基礎模板抽象類,描述了Task任務處理的流程(execute方法),及流程處理過程中的抽象方法;
- task解鎖方法:unlockTask();
- task獲取方法:getTasks();
- task分片方法:currentPartition();
- task執行方法:process();
- task執行前處理方法:beforeProcess();
- task執行后處理方法:afterProcess();
- BaseExeTask:繼承了基礎抽象類BaseTask,并具體實現了task流程處理過程中的抽象方法(除process()之外的方法);
- BaseReconcileTask:對賬操作基礎抽象類,其中放置對賬的基礎操作(目前的對賬只一種,所以該類為空);
- ReconcileDefaultTask:具體對賬實現類,實現process(),對賬邏輯在這里實現;
圖中是對賬模塊的繼承關系
image
責任鏈各節點核心處理流程介紹
- 數據抓取
- 提供目標業務數據分組功能,確定數據抓取的范圍,并創建對應數量的task來分組抓取業務數據;
- 提供目標業務數據按組抓取功能,每個task可以按照上面的分組信息抓取指定范圍的業務數據;
- 針對多個對賬目標字段的情況,組裝目標字段為json,便于數據清洗時拆分;
- 數據清洗
- 按照物理表維度創建清洗task,每個task只處理一個物理分表中的數據;
- 完成字段調整映射,統一同一對賬字段名稱,統一方式、渠道、狀態等屬性值;
- 對于多個對賬目標字段的情況,拆分一條原始憑證數據為多條對賬憑證;
- 對賬
- 按照物理表維度創建對賬task,每個task只處理一個物理分表中的數據;
- 借助Redis中Set結構的命令:Sdiffstore、Sinterstore函數實現對賬操作;
- 對賬匯總
- 按照物理表維度創建匯總task,每個task只處理一個物理分表中的數據;
- 每個task統計完該物理表中的匯總數據后,獲取redis鎖,獲取成功后將單個表的匯總結果插入或更新到對賬匯總表中;
責任鏈task節點創建及鏈路流轉過程介紹
- 鏈路節點及節點的順序信息存儲在數據庫中,可以針對每個對賬類型創建一個鏈路,實現對賬流程的高度配置話和自由度;
- 每次對賬執行,創建批次信息,批次信息中記錄當前對賬流轉到的節點及該節點下創建了多少個task;
- 任務開始執行,創建批次信息,task讀取到批次信息后,讀取對應的鏈路配置信息,開始創建第一個節點的task數據,并在批次中記錄節點類型及對應task數量;
- 各個節點對應的task定時掃描表中對應的task,執行各自的任務(按照目標方法中規定的流程執行);
- 批次對應的task任務出發批次執行,校驗該批次當前節點下所有的任務是否都已經執行完成,完成后創建下個節點的任務,未完成則根據規則重試;
對賬流程圖
image