不要把分層當做解耦!


公司的老員工很喜歡一種他們稱之為“解耦”的做法:

先這么進行系統分析:把系統運行拆解為若干個環節,先執行A,再執行B,形成一個一個的步驟。

然后進行“解耦”:把每個環節變成一個服務,環節之間用 MQ 連接。環節銜接的輸入輸出數據形成協議規范。

“解耦”之后得到的好處是:

環節用MQ串聯,當服務死掉后,MQ能存儲消息,等服務重啟可以繼續執行;當MQ無法消化時,可以為這個環節的服務增加機器;當這個環節清閑時,可以裁剪機器。

這套“解耦”的辦法和部門划分一脈相承,部門人員富裕就裁剪,工作量完不成就加入,公文始終堆在那兒。

程序員的特點是手里有錘子到處找釘子,凡是看到系統沒有這么分割的,他們就認為“解耦不充分”。程序人生就是不斷復制這個模型的人生。

很多公司的架構也停留在這種軟件設施級別的架構:如何實施 KAFKA,如何上SPARK,如何玩ZOOKEEPER等等,妄圖通過引入這些靈丹妙葯改變世界。

然而效果如何呢?由於涉及公司內部系統,保密起見這里不做展開,簡單的說,系統爛的一比!

為什么會演變成這樣呢?

第一,系統爛源於業務架構識別不當

如權限方面,本人在05年就搞組織機構無限划分,而這套系統里公司都是平齊的,難道它們都搞扁平化管理了?

權限不是目前系統的核心業務,本系統核心業務對象識別的也一塌糊塗,但涉及公司業務這里不展開。

我認為,系統分析能力主要指的是業務架構的能力,識別核心業務對象,讓業務在層級之間活躍,圍繞業務進行架構。一個解耦得當的系統,首先是業務之間的穿插少,板塊之間相對獨立,不互相污染纏繞。其次,抽象度高,針對上層抽象的邏輯不影響下層抽象。

還是拿組織機構划分來說,在我的設計里,組織機構只有一張表,不論公司、部門、科室還是機場、醫院、學校、院系、場站等等,隸屬關系都記錄在這張表里,表達組織結構就用這個表,需要側重表達時就從這個表繼承,通過共享主鍵繼承派生出醫院表學校表機場表等等、現在有了JSON字段,甚至可以不繼承。這樣的組織機構表,充分表達且僅表達了對權限系統至關重要的層級關系,而與權限系統無關的如公司聯系人注冊資金地址法人等等信息,則根據業務需要發配到JSON或派生表里。派生表和組織機構表,分別表述公司不同的側面,既支持又獨立,這才是真正的本質性的解耦,是符合形式邏輯的結構。從概念來說,組織機構的概念級別更高,機場醫院部門科室的概念層級更低,組織機構包括了機場醫院部門科室,組織機構的性質是管轄-隸屬。這樣的解耦是每個系統都需要的,它能真正節約人工投入,形成清爽愉快的代碼組織架構。

即使這批代碼全部在一個項目一個進程又有何妨,沒有必要隔離時為何要隔離到兩個進程!一個聰明的架構師,要有因地制宜具體問題具體分析的頭腦,要有洞穿現象分離出業務本質的洞察力和思考深度。在一個人體內,神經系統,血液循環,呼吸系統等等,各自獨立又共用一個物理區域,不能把人斬成幾段來划分人體區域。斬成幾段誰不會?是個人就會,那叫莽夫不叫大夫,屬於原始思維不屬於科學思維。

第二,遏制自己到處耍錘子的沖動

公司的老員工特別愛玩消息隊列,卻對 AM 模型一竅不通。

要了解Actor-Message模型最好的途徑就是讀Joe Armstrong關於 erlang 的論文,然后下場用 erlang 實戰做一個小應用。

除了erlang的虛擬機,別的主流的虛擬機或操作系統都不是為 ActorMessage發明的,它們原本是不支持 AM模型的,於是,有人用 erlang 搞了 RabbitMQ,讓其他不是 erlang 虛擬機的程序無需多大代價就能沾點光享受一些AM的好處,但是這種享受是有限的。后面又有其它語言實現的 MQ,以及由於Java畢竟不支持真正的原生 Actor 導致整體往流的方向發展,這里就不展開了。

這里要認識到幾個問題:

1. MQ不是真正的Actor-Message,是跨進程訪問。在erlang里可以隨手建一百萬個Actor,而在MQ里,你只能揀幾個主要的對象關聯到MQ的收發者。這是因為,MQ走的是網絡協議跨進程,其速度再怎么快,也不可能快過進程內部調用。我做過一個測試,通過RabbitMQ做RPC,跑一萬次加法需要15s!當你要做的系統是一個實時系統,不要搞MQ!如果你的運算非常緊密,不要搞MQ!你的電腦有很多傳輸方式,有 PCI、有 PCIE、有 SATA、有 USB,為什么不全用 USB 呢?跨進程通訊的成本永遠高於進程內調用,一個跨進程調用,需要將數據打包成 bytes,要組MQ的包,要組TCP/IP包,要傳輸,再從 bytes 恢復為程序對象,這些步驟的開銷驚人,只要允許請盡量直接訪問同一個進程內的、同一個VM上的程序對象!

2. 你的系統內部用了 Actor-message 嗎?在 erlang 里,Actor位於跨進程的節點和位於同一進程的節點,遞信方式沒有多大差別。如果你的系統本身就是 Actor-Message的,你只需要將系統復制幾份就能獲得增長能力,不需要去拆解成幾個服務!當然,你玩的不是erlang,即使用了Akka框架之類AM框架,和其它語言通訊也是問題。但是這不妨礙你把系統抽一下頭,加幾個MQ的注入點。這樣做的好處是,你的程序代碼還在一起,你還能看懂代碼,而不需要在一堆工程之間跳來跳去才能搞明白一段業務邏輯。公司有一個項目,東西不多,核心功能就那么一點,居然搞出 9 個工程!

3. 你考慮過 erlang 的其它好處嗎?erlang 還有熱部署、無副作用、監督樹等等優勢,你想過你玩的MQ支持嗎?

4. 你知道任務調度嗎?在任務調度眼里,MQ只是一個手段,任務才是重點!!! 能做任務調度的框架有 celery 等等。為什么要上任務調度而不是停留於MQ?人的認識總要往更高層次發展,一個物理層的概念離產品頗有距離,你需要一個真正的任務調度來和業務耦合。業務->任務調度->MQ,這是正確認識。我們知道,在真正的 ActorMessage里,任務也是一個 Actor,但是你用的畢竟是 MQ 而不是 erlang,erlang 可以迅速創建一百萬個 Actor,MQ搞一百萬個隊列試試。

第三、技術層面的解耦不等於拆進程上消息隊列!!

技術層面的解耦,需要認知和發現中立的業務無關的或者業務無知的組件或服務。

技術解耦的結果除了物理分層變成若干進程,也可能形成一種程序組件,或者一種程序概念的邏輯分層。譬如地圖組件就是一種解耦,TTS組件也是一種解耦,解耦得到的組件仍然可以放在一個進程內使用。又如MVC也是一種典型的解耦,解耦后,有的將M層獨立為一個后台服務器,有的將M和VC都放在UI進程。解耦並不意味着跨進程上消息隊列!!

結論

一個系統的所謂解耦,最重要的是業務層面的解耦,業務層面的解耦更多的來自對業務本身的透徹認知。

在實施技術解耦之前要想明白,經過技術解耦后,你的業務會不會流竄到各個技術解耦后的層,如果會,沖動是魔鬼,你需要懸崖勒馬好好反思再做定奪。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM