敖丙帶你了解電商流程引擎
本文轉(zhuǎn)載自微信公眾號「三太子敖丙」,作者三太子敖丙。轉(zhuǎn)載本文請聯(lián)系三太子敖丙公眾號。
正文
在電商里面處理復雜的業(yè)務邏輯場景很多,我們還是以創(chuàng)建商品為列子。很多人可能會問創(chuàng)建商品很復雜嗎?我們接著往下看就知道了。
創(chuàng)建商品流程:
- 參數(shù)必填性校驗
- 參數(shù)數(shù)據(jù)轉(zhuǎn)換
- 商品基礎信息校驗
- 商品與商家之間的校驗
- 類目信息校驗
- 商品交易信息校驗(這個看公司業(yè)務決定)
- SKU相關信息校驗
- 商品是否需要有特定標簽校驗(看公司業(yè)務決定)
- 商品類型校驗(普通,卡片,視頻.......)
- 商品風控校驗
- 保存商品信息
- 保存SKU信息
- 保存商品詳情信息
- 重量模版
- 運費
- 配送區(qū)域
- 。。。。。。。
大家現(xiàn)在看看覺得創(chuàng)建一個上還簡單嗎?這里商品類型里面還涉及到各個業(yè)務場景校驗,我們就先不談了。針對這樣的情況我們應該怎么去寫這個代碼呢?我翻看了一下以前大學寫的一些代碼整體的代碼格式大概也就是這個樣子
這么寫其實也沒有什么問題,功能也能實現(xiàn)。但是這么寫其實有很多弊端的:
- 代碼可讀性不高
- 代碼擴展性不高
- 耦合性太強,有些東西不好公用
- (重點)整體創(chuàng)建執(zhí)行流程時間太長,串行調(diào)用下游服務
看到這樣代碼我們首先都是吐槽一頓,然后還是老老實實是去改。有動手能力強的同學可能會想著去優(yōu)化一下。再看看這個流程,其實在創(chuàng)建商品的時候我們很多校驗和保存數(shù)據(jù)是m沒有依賴且互不影響的,我們完全可以去并行執(zhí)行。
節(jié)省創(chuàng)建商品的流程時間,提高用戶體驗。(PS:就好比兩條高速一條堵車,一條暢通無阻,選哪條?)所以針對這么并行問題我還是給大家畫了一個流程圖:
通過這圖我們看到創(chuàng)建一個商品流程,我們調(diào)用的下游服務可能是有十幾二十個或者更多,假設我們一次RPC調(diào)用的平均返回時間是50毫秒,串行執(zhí)行時間可能就到1-2秒了,那么我們并行執(zhí)行話也就200到300毫秒了。
所以本著這種思想可能有人會問,為什么我不能異步,不能用消息?創(chuàng)建商品假設用異步消息的話,如果消費失敗那用戶創(chuàng)建的商品成功保存其他信息失敗了,那對用戶來說不是更加體驗不好了?
說了這么多我們開始擼代碼了
先創(chuàng)建一個Context 上下文,作為我們的調(diào)用下游服務的返回結果
圖片
第二步創(chuàng)建我們的流程節(jié)點,這相當于就是保存我們整個流程中需要執(zhí)行下游服務的節(jié)點,以Map作為保存數(shù)據(jù),NodeConf 節(jié)點設置參數(shù),自定義請求服務超時時間(因為并行我們是用的線程池或者通過get設置時間get返回值結果)
第三步引擎類,這個也是我們的核心類。通過我們添加的node節(jié)點判斷我們哪些流程是需要串行的那些是需要并行的,通過線程池創(chuàng)建線程放入Feature中,來達到同步執(zhí)行的效果。
在使用線程池的時候我們需要考慮不要設置的參數(shù)過大,開啟另外的線程也是會占用機器內(nèi)脆的,一個線程按1兆來算,你開啟幾百上千個,也會占用很大的一部分內(nèi)存。盡可能的去采用池化思想,這里就按大家實際場景去做測試。
第四步執(zhí)行Call方法,也就是執(zhí)行我們的node節(jié)點。
第5步創(chuàng)建節(jié)點接口,這里我們要定義一個ResultKey,這個Key也就是跟我流程中的這個節(jié)點所綁定,在獲取數(shù)據(jù)的時候也就是通過者key來標識
第6步因為我們在節(jié)點里面存的Class類,所以我們得通過實現(xiàn)ApplicationContextAware類來獲取Spring容器中的bean實例
第7步那就是來創(chuàng)建兩個測試node節(jié)點
最后當然就是我們的測試結果啦,這里我們創(chuàng)建兩個節(jié)點NodeOne 和NodeTwo 作為模擬真實業(yè)務場景的節(jié)點,通過一個后面的three作為一個group 需要并行執(zhí)行的節(jié)點。
看完代碼最后再給大家來一個總體的流程圖吧
看完是不是覺得感覺自己頓悟,以后再面對復雜流程的業(yè)務也就OK拿下了。
思考
其實這里還有很多優(yōu)化點,每個人遇到復雜的場景可能也不一樣,只能說給大家提供一個思想吧,針對不同的場景大家再去做改造吧!!!
給大家做一個擴展:
細心的同學可能會發(fā)現(xiàn)這都是強依賴性,能不能有弱依賴在里面呢?
答案:當然可以有弱依賴了,在 FlowNode.NodeConf中我們既然可以設置超時時間 我們也可以在添加一個參數(shù)來確定是都是弱依賴。在我們的future.get獲取結果的時候當出現(xiàn)異常可以catch住,強依賴則終止流程返回錯誤信息,否則記錄錯誤日志,流程continue
我們流程保存現(xiàn)在是用的靜態(tài)代碼塊,可不可以換其他的方式保存節(jié)點呢?
答案:這個當然也可以,我們保存在數(shù)據(jù)庫,ACM,Apollo等等都是可以的。這個取決于你們自己的業(yè)務和成本問題。因為流程我們一般是不會經(jīng)常換的,所以我還是建議代碼寫死就好了
采用線程池去調(diào)用下游服務,會不會造成服務鏈路追蹤失敗呢?
答案:這個不能說絕對,但是如果是保存在ThreadLocal中那肯定是會失效的,ThreadLocal中的KEY也就跟當前線程的ID有關,都開啟新的線程了,那肯定也就是丟失了
如果采用了ThreadLocal 在節(jié)點中是不是就失效了?
答案:第三點已經(jīng)給出答案了
總結
今天的復雜業(yè)務邏輯的流程引擎也就完結了,在我每次看到新的技術以及知識點的時候我都有一種開悟的感覺,引用 鄧寧-克魯格的心理效應來說,在我們的這個年紀其實就是開悟之坡。后
面我會接著再為大家怒肝設計模式,完了也就會再跟大家聊聊重構。其實也就是用我們的設計模式來優(yōu)化我們的代碼。