本文源自 Martin Fowler 的 Bliki 上 2014 年的文章Microservices and the First Law of Distributed Objects
當(dāng)我寫《企業(yè)應(yīng)用架構(gòu)模式》一書時,我提出了一個我稱之為分布式對象設(shè)計第一法則:“不要分布你的對象”。最近幾個月業(yè)界對微服務(wù)的熱情增加,讓一些朋友對在微服務(wù)場景下對這一法則產(chǎn)生疑問,并且如果法則仍然成立,為什么我還要贊同微服務(wù)。
非常重要的一點就是我在第一法則中用了“分布式對象”的說法。它反映了一個在 90 年代末 00 年代初相當(dāng)流行但此后(正確地)失寵的想法。分布式對象的想法是你可以設(shè)計對象并在進(jìn)程內(nèi)或遠(yuǎn)程選擇使用相同的對象,遠(yuǎn)程則指的是在同一臺機(jī)器的另外一個進(jìn)城里,或者不同的機(jī)器里。比較聰明的中間件,比如,DCOM 或者一個 CORBA 實現(xiàn),將會處理進(jìn)程內(nèi)或者遠(yuǎn)程之間的差別。因此你可以把你的系統(tǒng)拆分成以多個獨立的進(jìn)程來設(shè)計。
我對分布式對象概念的反對意見是:盡管逆可以在對象邊界內(nèi)封裝許多東西,但逆不能封裝遠(yuǎn)程/進(jìn)程內(nèi)的區(qū)別。 進(jìn)程內(nèi)函數(shù)調(diào)用很快并且總是成功(因為任何異常都是由于應(yīng)用程序造成的,而不僅僅是由于進(jìn)行調(diào)用的事實)。 但是,遠(yuǎn)程調(diào)用速度要慢幾個數(shù)量級,并且由于遠(yuǎn)程進(jìn)程或連接失敗,調(diào)用總是有失敗的可能。

這種差異的結(jié)果是 API 的設(shè)計方式不同。 進(jìn)程調(diào)用可以是細(xì)粒度的,如果你想要 100 個產(chǎn)品價格和庫存,你可以調(diào)用你的產(chǎn)品價格函數(shù) 100 次,另外 100 次調(diào)用庫存。 但是,如果該功能是一個遠(yuǎn)程調(diào)用,你最好將所有這些批處理在到一個調(diào)用中實現(xiàn),一次調(diào)用所有 100 個價格和庫存。 這會導(dǎo)致產(chǎn)品對象的界面有很大差異。 因此,你不能采用相同的類(主要是和接口相關(guān))并以進(jìn)程內(nèi)或遠(yuǎn)程方式透明地使用它。
與我交談過的微服務(wù)倡導(dǎo)者非常清楚這種區(qū)別,而且我還沒有聽到他們談?wù)撨M(jìn)程內(nèi)/遠(yuǎn)程調(diào)用的透明性。 所以他們并沒有試圖做分布式對象試圖做的事情,因此不違反第一定律。 相反,他們提倡通過 HTTP 或輕量級消息和文檔進(jìn)行粗粒度交互。
所以本質(zhì)上,我對分布式對象的看法和微服務(wù)的倡導(dǎo)者們對微服務(wù)的看法并不矛盾。 盡管存在這種基本的非沖突,但現(xiàn)在還需要提出另一個問題。 微服務(wù)意味著小型分布式單元通過遠(yuǎn)程連接進(jìn)行通信,這比單體應(yīng)用要多得多。這不違反第一定律的精神,即使它符合它的字面意思嗎?
雖然我承認(rèn)有正當(dāng)理由為許多系統(tǒng)進(jìn)行分布式設(shè)計,但我確實認(rèn)為分布式是復(fù)雜性的助推器。 粗粒度的 API 比細(xì)粒度的 API 更尷尬。 你需要決定如何處理遠(yuǎn)程調(diào)用失敗以及一致性和可用性的后果。 即使你通過協(xié)議設(shè)計最小化遠(yuǎn)程調(diào)用,仍然需要更多地它們的性能問題。 在設(shè)計單體應(yīng)用時,你必須擔(dān)心模塊之間的職責(zé)劃分,而對于分布式系統(tǒng),你必須擔(dān)心模塊之間的職責(zé)分配和分布因素。
雖然小型的微服務(wù)確實更加簡單,但我擔(dān)心這會將復(fù)雜性推向服務(wù)之間的通信,由于通信的不明確,因此更難發(fā)現(xiàn)問題。 當(dāng)你必須跨越遠(yuǎn)程邊界進(jìn)行重構(gòu)時,會更加困難。 微服務(wù)倡導(dǎo)者吹捧你會從異步通信中降低耦合,但異步是另一個復(fù)雜性助推器。千篇一律的擴(kuò)展允許你在不增加分布式復(fù)雜性的情況下處理海量請求。
因此,我對分布式持謹(jǐn)慎態(tài)度,我是傾向整體設(shè)計。 鑒于此,為什么我要花費大量精力來描述微服務(wù)并支持倡導(dǎo)它的同事? 答案是因為我知道我的直覺并不總是正確。我不能否認(rèn)許多團(tuán)隊已經(jīng)采用了微服務(wù)方法并取得了成功,無論是像 Netflix 和(可能)亞馬遜這樣的知名公共案例,還是我在 Thoughtworks 內(nèi)外都與之交談過的各種團(tuán)隊。 我天生就是一個經(jīng)驗主義者,相信經(jīng)驗證據(jù)勝過理論,即使這個理論比我的直覺要好得多。
并不是說我認(rèn)為這件事已經(jīng)有定論了。在軟件交付中,成功是一件很難定義的事情。盡管像 Netflix 和 Spotify 這樣的組織已經(jīng)大肆宣傳他們早先在微服務(wù)上的成功,但也有像 Etsy 或 Facebook 這樣的例子在單體架構(gòu)上取得了成功。無論團(tuán)隊認(rèn)為自己使用微服務(wù)多么成功,唯一真正的比較是違反事實的——如果他們使用單體的方式構(gòu)建應(yīng)用會更好嗎?微服務(wù)方法只出現(xiàn)了相對較短的時間,所以我們沒有太多證據(jù)來自十年前的遺留微服務(wù)架構(gòu)。但可以將微服務(wù)與我們非常不喜歡的那些古老的單體應(yīng)用進(jìn)行比較。并且可能存在我們尚未確定的因素,這意味著在某些情況下單體應(yīng)用更好,而其他情況則有利于微服務(wù)。鑒于在軟件開發(fā)中收集證據(jù)的困難,即使在多年過去之后,也很可能不會做出有利于其中一個或另一個的令人信服的決定。
鑒于這種不確定性,像我這樣的作家能做的最重要的事情就是盡可能清楚地傳達(dá)我們認(rèn)為我們已經(jīng)學(xué)到的教訓(xùn),即使它們是矛盾的。 讀者將自己做出決定,而作為作家,我們的工作是確保這些決定是明智的,無論他們落在架構(gòu)決策的哪一邊。
(完)