點選「 IT碼徒 」, 關註,置頂 公眾號
每日技術幹貨,第一時間送達!
1、前言
良好的系統設計必須要做到開閉原則,隨著業務的不斷叠代更新,核心程式碼也會被不斷改動,出錯的機率也會大大增加。但是大部份增加的功能都是在擴充套件原有的功能,既要保證效能又要保證品質,我們往往都會使用異步執行緒池來處理,然而卻增加了很多不確定性因素。
由此我設計了一套通用的異步處理SDK,可以很輕松的實作各種異步處理
2、目的
透過異步處理不僅能夠保證方法能夠得到有效的執行而且不影響主流程
更重要的是各種兜底方法保證數據不遺失,從而達到最終一致性
3、優點
無侵入設計,獨立資料庫,獨立定時任務,獨立訊息佇列,獨立人工執行界面(統一登入認證)
使用spring事務事件機制,即使異步策略解析失敗也不會影響業務
如果你的方法正在執行事務,會等事務送出後或回滾後再處理事件
就算事務送出了,異步策略解析失敗了,我們還有兜底方案執行(除非資料庫有問題,訊息佇列有問題,方法有bug)
4、原理
容器初始化bean完成後遍歷所有方法,把有@AsyncExec註解的方法緩存起來
方法執行時透過AOP切面釋出事件
事務事件監聽處理異步執行策略
@TransactionalEventListener(fallbackExecution = true, phase = TransactionPhase.AFTER_COMPLETION)
fallbackExecution=true 沒有事務正在執行,依然處理事件
TransactionPhase.AFTER_COMPLETION 事務送出後和事務回滾後都處理事件
5、元件
kafka 訊息佇列
xxl job 定時任務
mysql 資料庫
spring 切面
vue 界面
6、設計模式
策略
樣版方法
動態代理
7、流程圖
CREATE TABLE async_req(
id bigint NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
application_name varchar(100) NOT NULL DEFAULT '' COMMENT '套用名稱',
sign varchar(50) NOT NULL DEFAULT '' COMMENT '方法簽名',
class_name varchar(200) NOT NULL DEFAULT '' COMMENT '全路徑類名稱',
method_name varchar(100) NOT NULL DEFAULT '' COMMENT '方法名稱',
async_type varchar(50) NOT NULL DEFAULT '' COMMENT '異步策略型別',
exec_status tinyint NOT NULL DEFAULT '0' COMMENT '執行狀態 0:初始化 1:執行失敗 2:執行成功',
exec_count int NOT NULL DEFAULT '0' COMMENT '執行次數',
param_json longtext COMMENT '請求參數',
remark varchar(200) NOT NULL DEFAULT '' COMMENT '業務描述',
create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '建立時間',
update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新時間',
PRIMARY KEY(id) USING BTREE,
KEY idx_applocation_name(application_name) USING BTREE,
KEY idx_exec_status(exec_status) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='異步處理請求';
CREATE TABLE async_log(
id bigint NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
async_id bigint NOT NULL DEFAULT '0' COMMENT '異步請求ID',
error_data longtext COMMENT '執行錯誤資訊',
create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '建立時間',
PRIMARY KEY (id) USING BTREE,
KEY idx_async_id(async_id) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='異步處理日誌';
9、異步策略
10、安全級別
11、執行狀態
12、流程圖
13、apollo 配置
# 開關:預設關閉
async.enabled=true
# 套用名稱
spring.application.name=xxx
# 資料來源 druid
spring.datasource.driver- class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/fc_async?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowMultiQueries=true&rewriteBatchedStatements=true
spring.datasource.username=user
spring.datasource.password=xxxx
spring.datasource.filters=config
spring.datasource.connectionProperties=config.decrypt=true;config.decrypt.key=yyy
#靜態地址
spring.resources.add-mappings=true
spring.resources.static-locations= classpath:/static/
# 以下配置都有預設值
# 核心執行緒數
async.executor.thread.corePoolSize=10
# 最大執行緒數
async.executor.thread.maxPoolSize=50
# 佇列容量
async.executor.thread.queueCapacity=10000
# 活躍時間
async.executor.thread.keepAliveSeconds=600
# 執行成功是否刪除記錄:預設刪除
async.exec.deleted=true
# 自訂佇列名稱字首:預設套用名稱
async.topic=${spring.application.name}
# 重試執行次數:預設5次
async.exec.count=5
# 重試最大查詢數量
async.retry.limit=100
# 補償最大查詢數量
async.comp.limit=100
# 登入攔截:預設false
async.login=false
14、用法
1,異步開關
scm.async.enabled=true
2,在需要異步執行的方法加註解 (必須是spring代理方法)
@AsyncExec(type = AsyncExecEnum.SAVE_ASYNC, remark = "數據字典")
3,人工處理地址
http://localhost:8004/async/index.html
15、註意
1,套用名稱
spring.application.name
2,佇列名稱
${async.topic:${spring.application.name}}_async_queue
自訂topic:
async.topic=xxx
3,自己業務要做冪等
4,一個套用公用一個佇列
自產自消
5,定時任務
異步重試定時任務(2分鐘重試一次,可配置重試次數)
異步補償定時任務(一小時補償一次,建立時間在一小時之前的)
16、效果展示
17、github地址
https://github.com/xiongyanokok/fc-async.git
來源:juejin.cn/post/7266087843239084090
— END —
PS:防止找不到本篇文章,可以收藏點贊,方便翻閱尋找哦。
往期推薦