本文源自 Martin Fowler 的 Bliki 上 2014 年的文章Microservices and the First Law of Distributed Objects
當我寫《企業(yè)應用架構(gòu)模式》一書時聪黎,我提出了一個我稱之為分布式對象設計第一法則:“不要分布你的對象”雇初。最近幾個月業(yè)界對微服務的熱情增加扬舒,讓一些朋友對在微服務場景下對這一法則產(chǎn)生疑問仰税,并且如果法則仍然成立惰赋,為什么我還要贊同微服務。
非常重要的一點就是我在第一法則中用了“分布式對象”的說法堕战。它反映了一個在 90 年代末 00 年代初相當流行但此后(正確地)失寵的想法蹋绽。分布式對象的想法是你可以設計對象并在進程內(nèi)或遠程選擇使用相同的對象,遠程則指的是在同一臺機器的另外一個進城里逃魄,或者不同的機器里荤西。比較聰明的中間件,比如嗅钻,DCOM 或者一個 CORBA 實現(xiàn)皂冰,將會處理進程內(nèi)或者遠程之間的差別。因此你可以把你的系統(tǒng)拆分成以多個獨立的進程來設計养篓。
我對分布式對象概念的反對意見是:盡管逆可以在對象邊界內(nèi)封裝許多東西秃流,但逆不能封裝遠程/進程內(nèi)的區(qū)別。 進程內(nèi)函數(shù)調(diào)用很快并且總是成功(因為任何異常都是由于應用程序造成的柳弄,而不僅僅是由于進行調(diào)用的事實)舶胀。 但是概说,遠程調(diào)用速度要慢幾個數(shù)量級,并且由于遠程進程或連接失敗嚣伐,調(diào)用總是有失敗的可能糖赔。
這種差異的結(jié)果是 API 的設計方式不同。 進程調(diào)用可以是細粒度的轩端,如果你想要 100 個產(chǎn)品價格和庫存放典,你可以調(diào)用你的產(chǎn)品價格函數(shù) 100 次,另外 100 次調(diào)用庫存基茵。 但是奋构,如果該功能是一個遠程調(diào)用,你最好將所有這些批處理在到一個調(diào)用中實現(xiàn)拱层,一次調(diào)用所有 100 個價格和庫存弥臼。 這會導致產(chǎn)品對象的界面有很大差異。 因此根灯,你不能采用相同的類(主要是和接口相關)并以進程內(nèi)或遠程方式透明地使用它径缅。
與我交談過的微服務倡導者非常清楚這種區(qū)別,而且我還沒有聽到他們談論進程內(nèi)/遠程調(diào)用的透明性烙肺。 所以他們并沒有試圖做分布式對象試圖做的事情纳猪,因此不違反第一定律。 相反茬高,他們提倡通過 HTTP 或輕量級消息和文檔進行粗粒度交互兆旬。
所以本質(zhì)上,我對分布式對象的看法和微服務的倡導者們對微服務的看法并不矛盾怎栽。 盡管存在這種基本的非沖突,但現(xiàn)在還需要提出另一個問題宿饱。 微服務意味著小型分布式單元通過遠程連接進行通信熏瞄,這比單體應用要多得多。這不違反第一定律的精神谬以,即使它符合它的字面意思嗎强饮?
雖然我承認有正當理由為許多系統(tǒng)進行分布式設計,但我確實認為分布式是復雜性的助推器为黎。 粗粒度的 API 比細粒度的 API 更尷尬邮丰。 你需要決定如何處理遠程調(diào)用失敗以及一致性和可用性的后果。 即使你通過協(xié)議設計最小化遠程調(diào)用铭乾,仍然需要更多地它們的性能問題剪廉。 在設計單體應用時,你必須擔心模塊之間的職責劃分炕檩,而對于分布式系統(tǒng)斗蒋,你必須擔心模塊之間的職責分配和分布因素。
雖然小型的微服務確實更加簡單,但我擔心這會將復雜性推向服務之間的通信泉沾,由于通信的不明確捞蚂,因此更難發(fā)現(xiàn)問題。 當你必須跨越遠程邊界進行重構(gòu)時跷究,會更加困難姓迅。 微服務倡導者吹捧你會從異步通信中降低耦合,但異步是另一個復雜性助推器俊马。千篇一律的擴展允許你在不增加分布式復雜性的情況下處理海量請求队贱。
因此,我對分布式持謹慎態(tài)度潭袱,我是傾向整體設計柱嫌。 鑒于此,為什么我要花費大量精力來描述微服務并支持倡導它的同事屯换? 答案是因為我知道我的直覺并不總是正確编丘。我不能否認許多團隊已經(jīng)采用了微服務方法并取得了成功,無論是像 Netflix 和(可能)亞馬遜這樣的知名公共案例彤悔,還是我在 Thoughtworks 內(nèi)外都與之交談過的各種團隊嘉抓。 我天生就是一個經(jīng)驗主義者,相信經(jīng)驗證據(jù)勝過理論晕窑,即使這個理論比我的直覺要好得多抑片。
并不是說我認為這件事已經(jīng)有定論了。在軟件交付中杨赤,成功是一件很難定義的事情敞斋。盡管像 Netflix 和 Spotify 這樣的組織已經(jīng)大肆宣傳他們早先在微服務上的成功,但也有像 Etsy 或 Facebook 這樣的例子在單體架構(gòu)上取得了成功疾牲。無論團隊認為自己使用微服務多么成功植捎,唯一真正的比較是違反事實的——如果他們使用單體的方式構(gòu)建應用會更好嗎?微服務方法只出現(xiàn)了相對較短的時間阳柔,所以我們沒有太多證據(jù)來自十年前的遺留微服務架構(gòu)焰枢。但可以將微服務與我們非常不喜歡的那些古老的單體應用進行比較。并且可能存在我們尚未確定的因素舌剂,這意味著在某些情況下單體應用更好济锄,而其他情況則有利于微服務。鑒于在軟件開發(fā)中收集證據(jù)的困難霍转,即使在多年過去之后荐绝,也很可能不會做出有利于其中一個或另一個的令人信服的決定。
鑒于這種不確定性谴忧,像我這樣的作家能做的最重要的事情就是盡可能清楚地傳達我們認為我們已經(jīng)學到的教訓很泊,即使它們是矛盾的角虫。 讀者將自己做出決定,而作為作家委造,我們的工作是確保這些決定是明智的戳鹅,無論他們落在架構(gòu)決策的哪一邊。
(完)