第一種死法:Big ball of Mud
架構里最常用的反面案例是 big ball of mud。很大程度上可以說打格子,把復雜的系統拆解成小格子是架構師最重要的工作。這個小格子有很多種名字,比如:組件,模塊,子系統,庫,bounded context林林種種。
但是仔細想想?為什么需要打這些格子?為什么要把一個進程干的活拆分出這么多進程去干?

一個東西打成多少個格子來做,不是受一種因素影響的。不同類型的應用,其面臨的主要挑戰是不同的,所以上面三種因素里對解決方案的影響的權重就不同。
比如說:如果我們做的是微信的架構。微信的主要架構問題是什么?其實是給海量低價值的用戶情況下提供免費服務。微信的后臺架構里決定因素的是成本,所以在騰訊的后臺業務里決定架構師能否做得好,主導的是對計算機體系架構是否足夠精通。微信的kv存儲能夠做到同城三園區容災,同時比競爭對手少一分備份達到同樣的數據安全性,這就是核心競爭力之一。在海量但是業務邏輯簡單的系統里,主要要考慮是怎樣打格子可以最大化利用現代計算機體系架構。也就是這些格式主要是為了非功能性需求切分出來的。一個進程掛了就掛了,三個進程負載均衡就可以做到很高的可用性。一個流程寫在一個函數內,一次執行需要很長時間,并發來跑可能需要很多進程。但是考慮SEDA的因素,可能把一個流程切成三個函數來寫,每個函數獨立成不同的線程或者進程來并發可以獲得更好的總并發性能。等等這些,切分的模塊的時候考慮的是內核,cache友好,網卡帶寬,copy-less這些因素。如果我們做的業務是海量的簡單邏輯的互聯網業務,不精通Linux內核,TCP/IP協議棧和算法與數據結構是無法做一個好的架構師,打好格子做出高性能低成本的架構的。這個方面的架構師的典型代表是:Google 的 Jeff Dean,以及 Map/reduce Spanner 為代表的經典分布式架構。
但是系統是多種多樣的。除了海量簡單邏輯的業務,世界的另外一端是業務極端復雜但是使用量并不大的架構,比如典型的企業流程自動化系統。在處理復雜業務的時候,業務架構就是主要的影響因素。什么是業務架構?比如說電子商務要處理真實世界的商品交易流程,就需要把系統與真實世界的業務邊界對應起來。一個電子商務系統需要拆分成“庫存管理系統”,“定價系統”,“商品目錄系統”等等。這種拆分不是因為架構師精通紅黑樹,認為這幾個模塊的數據結構不一樣必須分開,而是不這么分的業務復雜度無法控制。越是架構做得好的系統,其子系統越是可以寫得簡單,因為每個都只處理一個領域的業務邏輯,而不是把不同的業務邏輯交織地扯在一塊來寫。決定系統的架構必須跟著業務架構走的根本原因在于普通人的腦容量是有限,不分治之,復雜度根本hold不住。這個方面的架構師典型代表是:Eric Evan 和 Udi Dahan,以及他們代表的領域驅動設計思想。
世界是多樣的,很多事情不是在臺面上的。擺在臺面上的拆分系統的理由往往是業務邏輯,性能與穩定性等等。實際上真正主宰一個系統的模塊怎么拆分的其實是組織架構。如果開發者向同一個管理40人左右的leader匯報,那么這些命運緊密相關的人(從年終獎的角度)無論寫的系統是什么很難不緊密耦合,如果兩個leader帶的團隊共同參與一個項目開發,很難去阻止他們把工作拆成兩個模塊來寫,中間再各自加一道隔離層來保護自己。要是哪天這哪個團隊合了,或許他們做的第一件事情就是把兩個模塊給合回去,名義可能是這樣開發效率更高。這個現象叫Conway's Law,最有名的架構師是:James Coplien,以及他所撰寫的Organization Patterns(http://orgpatterns.wikispaces.com/BookOutline)
big ball of mud的系統有三種死法:
- 因為性能和穩定性不滿足要求而死,這個時候需要懂內核懂數據結構的架構師來好好做一下拆分。
- 因為業務邏輯復雜得hold不住而死,開發效率慢到爆,這個時候需要做過復雜業務的架構師來重新梳理一下模塊拆分。
- 因為軟件架構不符合組織架構,導致團隊間吵架吵到死的,這個時候老板重新思考什么樣的組織架構才是合適的(大boss通過組織架構體現其才是最終極的一切的架構師)。
如果一個系統兼具三個難點,簡直難到爆:首先對延遲及其敏感,需要超級懂計算機體系的人。其次業務邏輯很復雜,需要很強的建模能力。同時又開發工作量巨大,需要很多人參與從而引入各種政治問題。金融衍生品交易等領域可能符合這些特征。假如微信的架構師來做辦公自動化系統,上來就搞共享內存和高性能隊列,我只能呵呵了。
第二種死法:Dependency Hell or RPC Hell

這是淘寶的某個人寫的ppt的截圖。QZone的后臺其實也差不多。互聯網現在解決big ball of mud的所謂最佳實踐就是“微服務”。把一個大的系統拆成小的服務,用RPC一級級連接起來。A調用B,B再調用C。一個用戶的請求要經過n個團隊的系統轉一圈出來。現在干什么事情都要講求資歷,而資歷往往又和業務成功是掛鉤的。淘寶的業務牛x了,意味著其架構就是完美無缺的么?當然我沒有身披某某大公司技術副總裁的光環,而自動具有資格來評價這個問題。但是僅僅從一些技術細節的狹窄視角來看,這個架構也是有很多問題的,我稱之為dependency hell:
1、從業務解耦的角度來看:RPC與共享數據庫沒有本質區別,拆開之后兩個系統仍然是強依賴

這很糟糕

但是改成這樣就真的更好了么?服務C和DB沒有什么本質區別。
2、從非功能需求的角度。RPC依賴雙方是綁死的。多次RPC調用疊加的可用性是疊加下降的,每個點都要保證自己的高可用,這對基礎設施(運維自動化,集群管控)提出了很高的要求。而且對升級的依賴關系造成了很大挑戰,哪個升級會影響哪個。同時對于容量規劃簡直是災難,誰都不知道一個服務降級之后對其他所有依賴的方的雪崩效應到底是如何的。像QZone為了理解自己的后臺服務架構到底是怎樣互相依賴的,已經開始用上網絡抓包的手段了,因為已經沒有人知道這個網狀的關系到底是怎樣的了。從一個具體的技術細節來看,RPC調用需要主調方保留上下文的context在內存中(以及tcp socket),下游相應越慢對上游保留context的壓力就越大。當然這一切都可以通過加機器,更好的負載均衡,更好的高可用機制來彌補。無非就是請幾個高工來做集群管理系統,再加上機器和帶寬費用嘛。大部分互聯網公司的估值不是因為這個公司如何能節省成本,而是如何能花錢。所以非功能性需求不是決定性因素。
3、從組織架構的角度,要想獲得最大的效率,必須要團隊自治。RPC Hell的后果是每個團隊都與其他團隊緊耦合了。做個小功能,也需要拉一個跨組織架構的虛擬團隊來協調接口。每個開發者脫離了所謂的那個線下環境就無法開發了,每個功能都有n個rpc call別人的系統,而別人的系統當然是我們自己搭不起來的。因為你去搭A系統的時候就會發現依賴B系統,B系統依賴C系統。在沒有很好的基礎設施支撐的情況下,比如分布式日志收集,docker的開發環境管理。開發者在這個微服務架構下是欲死欲仙的,干什么都是聯調。每個人都對別的團隊做阻塞的call,體現出來是日常開發也是阻塞的。老板為了提高整體開發團隊的產出,就是加線程的方式,招更多的人。而招更多人為了職級晉升又需要把組織架構劃分得更加的細。這個和網絡異步編程的原理其實是一樣的。
其實在我看來,這種RPC的解法的來源應該是來自于這個循環:
需求做不完=>那么加人吧=>加人沒有坑,那么加坑吧=>我是leader我做主,咱們拆分模塊吧=>模塊拆分哪家強,RPC誰都懂,那就上吧=>繼續循環
RPC可能不是最優的解法
誠然,BAT都是RPC嵌套的解法。誠然,我也不是什么專家。但是拆分子系統顯然不是只有RPC一途,Event Driven的架構其實歷史同樣悠久。

具體的做法三言兩語講不清楚。最好有實際的案例。這里有兩個非常具體的案例:
電子商務的案例:http://pan.baidu.com/s/1i3o6J7f
醫療記錄的案例:http://pan.baidu.com/s/1c05BXLm
星巴克:http://pan.baidu.com/s/1eQvy31g
浙公網安備 33010602011771號