.NET-架構優化實戰-底層服務優化

前言

問題分析

  在本系列第一篇文章我們提到,底層問題主要存在以下兩點:

  • 代碼冗餘
  • 時效低

代碼冗餘

例如:

  • 領獎方法不統一,一次性的寫一套,可循環的又寫一套。
  
    •  
  • 每個類型任務都需要獨自的實現該任務的完成任務 JOB 與發放獎勵 JOB

  

  以上問題直接導致了後續開發、日常維護成本過高。

  因爲早期開發時缺少溝通,沒有封裝成公共的方法,而JOB每個開發人員都單獨實現了一套,當然他們未必那麼蠢,可能是某個先完成了,後續的先前COPY後修改一下。

  試想一下,沒新增一個任務類型就要重寫一份完成任務的JOB和自動發獎的JOB,這是一個N*2的工作量。如果後續有個規則改了,那是不是每個JOB都跑去改一次?

時效低

  由於任務完成是由定時服務根據業務數據源定時批量執行:

  1. 定時任務頻率低,則導致數據集中過多處理
  2. 定時任務頻率高,則導致 Job 對數據庫的壓力劇增或者 99%的無用查詢,無結果並不代表不會造成消耗,因爲查詢都是要經過下面步驟,建立連接、詞法分析、語法分析、選取執行方式、到存儲引擎讀取數據、返回客戶端。
  3. 隨着數據源數據量增加,查詢耗時也逐漸增加

  以上問題直接導致了,用戶完成任務後無法及時查看完成任務並領獎,如需及時查看狀態需要在展示頁面邏輯額外添加查詢後更新的操作

優化實施

流程圖

方案一(抽離公共點)

目的:減少代碼冗餘,提高可維護性,提高後續新任務的開發效率

具體實施:從業務流程圖可以直觀的觀察出,整個底層業務流程基本一致,只有數據源上的差異,因此可以從以下方面入手優化:

  1. 抽離出唯一的自動發獎 Job,發獎JOB基於【任務完成結果】進行發獎,逐步去除原個性任務自動發獎 Job。
  2. 自動發獎與手動領獎的具體執行流程一致的,可將其封裝成公共方法。分別由H5領獎按鈕與領獎JOB進行調用。
  3. 任務完成 Job 使用模板模式,由基類統一業務執行流程,每個任務類型只需繼承任務父類,再由子類重寫查詢數據源。當然也可以簡單粗暴點不使用設計模式,把查詢數據源後的完成任務的方法封裝成一個公共方法供不同任務類型的JOB去調用。

從我角度來看,這種方案處理沒有任何壞處的。如果真要計較,那就是所涉及的JOB都得改,但是從上述分析出,如果真要重構,工作量也是在寫父類模板和封裝公共方法,查詢數據源代碼是可以複用的。但是帶來的收益就是良好的擴展性和可維護性。

方案二(業務埋點)

該方案主要對任務參與的觸發方式變更,不同的任務類型由對應的業務最終流程的完成點進行發送隊列消息,由任務服務(消費端)訂閱相關消息執行任務完成流程。

通俗講叫業務埋點,當然也可以稱其爲事件驅動。

架構圖

事件驅動架構

  服務之間是高內聚的,它們的耦合度應該很低,當服務需要相互協作時,假設服務“A”需要觸發服務“B”中的某段邏輯,平常的方式是讓服務A直接串行調用服務B中的某個方法。但前提是A必須知道B的存在,如果B出異常了就會影響到A的正常執行。

這樣它們之間就是強耦合的,A必須依賴於B了。這樣使得系統更難以維護與擴展,因此引入事件驅動來降低服務間的耦合度。

  當服務A需要觸發服務B的邏輯時,不要直接調用它,我們可以將消息發送到消息隊列,由服務B訂閱相應的隊列,並在事件發生時異步執行操作。這意味着服務A、B都依賴於中間件消息隊列,但他們之間將不需要知道彼此的存在,因此它們之間於此解耦。

如果將此方案引入我們的活動業務中,收益主要分爲短期與長期。

短期收入

  1.  減少無用重複的查詢:無需重複查詢數據源,只需由業務端推送可靠的消息,減少對數據庫的多餘壓力
  2. 用戶體驗良好:時效性高,原集中時間點批量處理,現分散到不同的時間點執行
  3. 伸縮性優秀:RabbitMQ 自帶負載均衡功能,在消費能力不足情況下,可以做到業務無損的動態橫向擴展。雖然JOB也可以做到,但是需要對物理表做特殊處理,增加中間狀態

長期收益

  事件驅動架構長期收益比短期要大,以RabbitMQ與投資業務舉個例子。初期完成核心業務投資理財,投資後我們需要APP通知用戶,在此投資無論成功與否都往RabbitMQ發送消息,投資成功RouteKey=TZ.SUCCESS,投資失敗RouteKey=TZ.FAILE。APP通知服務訂閱隊列NoticeQueue綁定RouteKey=TZ.#,其中包括成功和失敗的消息,服務根據消息狀態發送APP通知。哪天業務拓展需要增加投資成功積分,只需要添加積分服務訂閱隊列IntegrationQueue並綁定RouteKey=TZ.SUCCESS消息即可。接着又多了任務活動、信用消費等,如此類推。

  由此可見,如同廣播一樣,我不知道你們誰要,如果你們需要的就好好監聽着,不需要就當耳旁風。

複雜點

分佈式事務

  既然我們使用了RabbitMQ中間件,那麼分佈式事務會選擇基於可靠消息的方案:

  1. 消息可靠性:保證業務端的本地事務執行成功的同時也保證隊列消息正常發佈
  2. 消息補償:保證消息消費端的正常消費,如果消費失敗後需重新投遞,如果重新投遞失敗可由補償服務補償發送。
  3. 冪等處理:因存在自動重試機制,避免重複執行業務導致的意外問題。

模型圖

  

  這種基於可靠消息的方案,也叫本地消息事務表的方案,可根據自己情況自研解決,也可使用類似開源分佈式事務框架 CAP 解決。https://github.com/dotnetcore/CAP

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章