模塊、單體和微服務(wù)_第1頁
模塊、單體和微服務(wù)_第2頁
模塊、單體和微服務(wù)_第3頁
模塊、單體和微服務(wù)_第4頁
模塊、單體和微服務(wù)_第5頁
已閱讀5頁,還剩5頁未讀 繼續(xù)免費(fèi)閱讀

付費(fèi)下載

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

模塊、單體和微服務(wù)最近,有人問我在什么情況下使用微服務(wù)是個(gè)好主意。在“系統(tǒng)設(shè)計(jì)詮釋世界”一文中,我談到了像第二系統(tǒng)效應(yīng)、創(chuàng)新者困境等宏觀問題。系統(tǒng)設(shè)計(jì)能回答微服務(wù)的問題嗎?https://apenwarr.ca/log/20201227是的,但你可能不喜歡這個(gè)答案。首先,我們需要了解一些歷史資料。1什么是微服務(wù)?你可以在網(wǎng)上找到各種各樣的定義。我的觀點(diǎn)是:微服務(wù)是對單體的最極端的抵制。當(dāng)你將整個(gè)應(yīng)用程序所需要的全部東西鏈接成一個(gè)很大的程序,并將其作為一個(gè)大型二進(jìn)制包部署時(shí),就會(huì)發(fā)生這樣的情況。單體有很長的歷史,可以追溯到像CGI、Django、Rails和PHP這樣的框架?,F(xiàn)在,我們要放棄這樣的假設(shè):單體和微服務(wù)群是僅有的兩個(gè)選項(xiàng)。在“一個(gè)無所不能的巨型服務(wù)”和“無數(shù)個(gè)幾乎什么都不做的微型服務(wù)”之間,存在著一個(gè)廣泛而微妙的連續(xù)體。如果你趕時(shí)髦,你至少有那么一次已經(jīng)構(gòu)建了一個(gè)單體(不管是有意的,還是因?yàn)閭鹘y(tǒng)框架鼓勵(lì)你這么做),后來發(fā)現(xiàn)了單體存在的一些問題,然后,你聽說微服務(wù)就是自己需要的答案,于是開始把一切都重新設(shè)計(jì)成微服務(wù)。但是,不要趕時(shí)髦。在這兩個(gè)極端之間,還有許多點(diǎn)。其中一個(gè)可能很適合你。更好的方法是從你想要將接口放在哪里開始。2方框和箭頭接口是模塊之間的連接。模塊是相關(guān)代碼的集合。在系統(tǒng)設(shè)計(jì)中,我們討論“方框和箭頭”設(shè)計(jì):模塊是方框,接口是箭頭。更深層次的問題是:每個(gè)方框要多大?里面放多少東西?我們?nèi)绾螞Q定什么時(shí)候把一個(gè)大方框分成兩個(gè)小方框?連接這些方框最好的方法是什么?有很多方法可以做到這一點(diǎn)。沒人知道什么是最好的。這是軟件架構(gòu)中最困難的問題之一。在過去幾十年里,我們經(jīng)歷了許多種“方框”。Goto語句被“認(rèn)為是有害的”,主要是因?yàn)樗鼈兺耆鲆暳巳魏螌哟谓Y(jié)構(gòu)。然后我們添加了函數(shù)或過程;這些都是非常簡單的方框,它們之間有接口(參數(shù)和返回碼)。https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf根據(jù)你選擇的編程路線,你會(huì)了解到遞歸函數(shù)、選擇符(combinator)、靜態(tài)函數(shù)原型、庫(靜態(tài)鏈接或運(yùn)行時(shí)鏈接)、對象(OOP)、協(xié)程、受保護(hù)的虛擬內(nèi)存、進(jìn)程、線程、JIT、命名空間、沙盒、chroot、Jails、容器、虛擬機(jī)、supervisor、hypervisor、微內(nèi)核和unikernel。/wiki/Unikernel這還只是方框!一旦有了彼此隔離的方框,就需要用箭頭連接它們。為此,我們有ABI、API、系統(tǒng)調(diào)用、套接字、RPC、文件系統(tǒng)、數(shù)據(jù)庫、消息傳遞系統(tǒng)和“虛擬化硬件”。如果你想為現(xiàn)代Unix系統(tǒng)畫一個(gè)完整的方框和箭頭圖(我不會(huì)這樣做),那太瘋狂了:函數(shù)在線程內(nèi),線程在進(jìn)程內(nèi),進(jìn)程在容器內(nèi),容器在用戶空間內(nèi),下層是內(nèi)核,內(nèi)核在VM里,運(yùn)行在云提供商數(shù)據(jù)中心里機(jī)架上的一臺硬件上,而這些硬件是通過一個(gè)編排系統(tǒng)連接在一起的,等等。每個(gè)抽象層上的每個(gè)方框都以某種方式隔離開來,然后連接到同層或其他層上的其他方框。有些方框在其他方框內(nèi)部。如果你想在二維空間中畫出這幅畫的真實(shí)版本,那么其中的線條肯定縱橫交錯(cuò)。這一切都是經(jīng)過幾十年的演變發(fā)展而來的。時(shí)髦的人稱之為“路徑依賴”。我稱之為一個(gè)爛攤子。我們要清楚:其中的大部分已經(jīng)沒有多少價(jià)值。與其把注意力集中在那些丑陋的進(jìn)化結(jié)果上,我們不妨來談?wù)劊藗冊诎l(fā)明這些東西的時(shí)候想要達(dá)成什么目標(biāo)。3對模塊化的探索模塊系統(tǒng)的首要目標(biāo)是下面這幾個(gè):將一部分代碼與其他部分隔離僅在明確指定的位置(通過定義良好的接口)重新連接這些部分保證你修改的部分仍然與其他部分兼容升級、降級以及擴(kuò)展某些部分,其他部分都不需要同步升級計(jì)算機(jī)行業(yè)花費(fèi)了大量時(shí)間,試圖找出所有這些模塊化問題的完美平衡,同時(shí)保證開發(fā)過程盡可能的輕松愉快。一句話,我們沒有成功。到目前為止,我們做得最糟糕的一個(gè)方面是隔離。如果我們能真正有效地將一部分代碼同其他部分隔離開來,那么其他的目標(biāo)也就基本可以實(shí)現(xiàn)了。但我們根本不知道如何做到這一點(diǎn)。隔離是一個(gè)超級困難的問題。天曉得,人們已經(jīng)盡力了。但瀏覽器沙箱逃逸仍然經(jīng)常發(fā)生,未被發(fā)現(xiàn)的特權(quán)升級攻擊在每一個(gè)操作系統(tǒng)上都存在,iOS越獄仍然會(huì)周期性地發(fā)生,DRM從來就無效(無論好壞),虛擬機(jī)和容器會(huì)經(jīng)常被發(fā)現(xiàn)有漏洞,而[在像k8這樣的系統(tǒng)中,其容器的配置默認(rèn)就是不安全的。人們甚至已經(jīng)知道,通過在因特網(wǎng)上適時(shí)地向遠(yuǎn)程服務(wù)器發(fā)送數(shù)據(jù)包,就可以找到加密密鑰。與此同時(shí),近年來,最驚人的隔離事故是Meltdown和Spectre攻擊,它允許計(jì)算機(jī)上的任何程序,甚至是Web瀏覽器中的JavaScript應(yīng)用程序,讀取同一臺計(jì)算機(jī)上其他程序的內(nèi)存,甚至是跨沙盒或虛擬機(jī)。每一種新的隔離技術(shù)都會(huì)經(jīng)歷一個(gè)從樂觀到絕望的周期:新想法:這次我們終于做對了,一勞永逸地!最初的試驗(yàn)似乎有效。(用戶抱怨它比我們上次嘗試的方法更慢、更費(fèi)事。)早期的致命缺陷被發(fā)現(xiàn)并修復(fù)。廣泛部署。越來越微妙的缺陷被陸續(xù)發(fā)現(xiàn)并修復(fù)。最終,我們會(huì)發(fā)現(xiàn)我們根本不知道如何修補(bǔ)的缺陷。不再對這種方法能實(shí)現(xiàn)有效的隔離抱有希望。但我們永遠(yuǎn)不能退役這種隔離方法,因?yàn)楝F(xiàn)在有太多的人依賴它。重復(fù)上述過程。舉例來說,在這一點(diǎn)上,安全人員根本不相信以下任何一項(xiàng)(每一項(xiàng)都是當(dāng)時(shí)最好的技術(shù))是絕對安全的:Unix系統(tǒng)上的進(jìn)程隔離和內(nèi)存保護(hù);當(dāng)允許遠(yuǎn)程執(zhí)行代碼(即安全人員所說的RCE)時(shí),OS進(jìn)程之間的權(quán)限隔離;通過過濾系統(tǒng)調(diào)用來隔離進(jìn)程;互不信任的進(jìn)程共享一個(gè)CPU超線程;位于一個(gè)CPU內(nèi)核上的虛擬機(jī)之間的內(nèi)存隔離。據(jù)我所知,目前最先進(jìn)的隔離技術(shù),是類似于Chrome沙盒或gVisor這樣的東西。大型瀏覽器供應(yīng)商和云計(jì)算提供商都使用這樣的工具。這些工具也不完美,但是供應(yīng)商確實(shí)在盡可能快地追蹤每一個(gè)新出現(xiàn)的漏洞,而且新漏洞出現(xiàn)的速度相當(dāng)緩慢。隔離比以往任何時(shí)候都要好……如果你把所有的隔離都放在虛擬機(jī)(VM)級別,那么云提供商就可以幫你完成,因?yàn)槠渌瞬恢涝趺醋觯蛘邿o法足夠頻繁地更新。如果你信任云提供商的VM隔離,那么就可以希望所有已知的問題都得到了緩解;但我們有充分的理由認(rèn)為,更多的問題將被發(fā)現(xiàn)。從各方面考慮,這其實(shí)很不錯(cuò)。至少我們還有有效的東西。4很好!都用虛擬機(jī)!等一等。為每個(gè)小模塊創(chuàng)建一個(gè)孤立的VM是一件很痛苦的事情。一個(gè)模塊該多大?很久以前,當(dāng)Java第一次出現(xiàn)時(shí),人們的夢想是每個(gè)對象中的每個(gè)函數(shù)的每一行都有嚴(yán)格的權(quán)限限制,甚至是在相同應(yīng)用程序二進(jìn)制文件中的對象之間,這樣就不需要CPU強(qiáng)制施加的內(nèi)存保護(hù)。沒人再相信他們能在這方面取得成功了。除了類似“云函數(shù)”這樣的市場宣傳,沒有人真的認(rèn)為你應(yīng)該嘗試一下。目前,已知的隔離方法中沒有一種是完美的,但每一種都能達(dá)到某種近似的效果。越來越有經(jīng)驗(yàn)的攻擊者,或者越來越有價(jià)值的目標(biāo),需要更好同時(shí)也更惱人的隔離?,F(xiàn)在,我們所知道的最好的隔離是由一級云提供商提供的inter-VM沙箱。在最壞的情況下,它的隔離效果會(huì)降到零。假如驗(yàn)證被跳過,由于大多數(shù)系統(tǒng)的耦合是如此之緊密,一個(gè)相當(dāng)有經(jīng)驗(yàn)的攻擊者可以在模塊之間橫向突破。因此,舉例來說,如果有人可以將惡意庫鏈接到你的Go或C++程序中,那么他們可能會(huì)控制整個(gè)程序。類似地,如果程序具有數(shù)據(jù)庫的寫入權(quán)限,那么攻擊者可能會(huì)讓它寫入數(shù)據(jù)庫中的任何地方。如果它可以連接到網(wǎng)絡(luò),那么他們就可能連接到網(wǎng)絡(luò)中的任何地方。如果它可以執(zhí)行任意的Unix命令或系統(tǒng)調(diào)用,那么他們就可能獲得Unix根訪問權(quán)限。如果它在一個(gè)容器里,那么他們可能會(huì)從容器中掙脫出來,進(jìn)入其他容器。如果惡意數(shù)據(jù)可以使png解碼器崩潰,那么他們就可能讓它做解碼器程序可以做的任何事情,等等。/一種特別強(qiáng)大的攻擊形式是獲得提交代碼的能力,因?yàn)檫@些代碼最終將在開發(fā)人員的機(jī)器上運(yùn)行,而某些開發(fā)人員或某處的生產(chǎn)機(jī)器可能有權(quán)執(zhí)行你想要執(zhí)行的操作。以上說法可能有點(diǎn)過于悲觀,但是做出這些假設(shè),可以幫助我們避免在不提高實(shí)際安全性的情況下使系統(tǒng)變得過于復(fù)雜。在”qmail1.0十年之際關(guān)于安全的一些思考“一文中,DanielJ.Bernstein指出,在qmail中添加的許多防御措施,特別是使用chroot和不同的Unixuid隔離各個(gè)不同的組件,并不值得,而且從未得到回報(bào)。無論如何,我們可以理所當(dāng)然地認(rèn)為,具有代碼執(zhí)行能力的攻擊者“通?!笨梢栽隈詈夏K之間橫向跳轉(zhuǎn),這幾乎適用于任何一種模塊隔離技術(shù)。這意味著只有兩種模塊邊界:可信的:兩個(gè)模塊彼此信任對方不存在惡意,并因此可以使用弱隔離邊界;不可信的:模塊彼此之間相互不信任,因此必須使用強(qiáng)隔離邊界。我在這里并沒有說什么非常深刻的東西?,F(xiàn)代流行的平臺已經(jīng)是圍繞這一區(qū)別構(gòu)建出來的。例如,Chrome在強(qiáng)隔離的沙箱虛擬機(jī)中運(yùn)行任意的WebJavaScript,因?yàn)榫W(wǎng)頁是不可信的。大多數(shù)操作系統(tǒng)僅僅以進(jìn)程(沒有沙箱)的形式運(yùn)行原生應(yīng)用,共享文件系統(tǒng)、網(wǎng)絡(luò)名稱空間等,因?yàn)槲覀冊?jīng)認(rèn)為,它們是相對可信的。(病毒就是這樣產(chǎn)生的。)專家們不再信任多用戶Unix系統(tǒng),因?yàn)榻Y(jié)果證明進(jìn)程隔離很脆弱。云虛擬機(jī)默認(rèn)可以無密碼sudo,因?yàn)閞oot與非root隔離都被證明很脆弱,所以為什么還要麻煩呢。(我們?nèi)匀灰笥脩粼趧h除所有文件或其他東西時(shí)輸入sudo,以減少人為錯(cuò)誤的影響。)來自多個(gè)供應(yīng)商的共享庫和DLL被鏈接到來自其他供應(yīng)商的應(yīng)用程序中,因?yàn)樗写a都被假定是可信的。(這為通過開源庫供應(yīng)商進(jìn)行供應(yīng)鏈攻擊打開了方便之門。我仍然感到驚訝的是,這類攻擊并不經(jīng)常發(fā)生。我有時(shí)懷疑,也許它們確實(shí)存在,只是很少被發(fā)現(xiàn)而已。)手機(jī)操作系統(tǒng)之所以會(huì)被破解,是因?yàn)閼?yīng)用商店的限制應(yīng)該會(huì)讓應(yīng)用沙盒足夠可信,但這種隔離總是被證明太脆弱。Kubernetes和Docker在一臺機(jī)器或VM中運(yùn)行多個(gè)不完全隔離的容器,因?yàn)檫@些容器都被默認(rèn)為可信的。強(qiáng)烈建議你不要嘗試運(yùn)行“多租戶”Kubernetes集群(不可信的應(yīng)用程序代表獨(dú)立的、相互不信任的用戶),因?yàn)槭聦?shí)證明,容器的隔離效果很弱。還有,即使你對每個(gè)服務(wù)使用像gVisor'dVM那樣的強(qiáng)隔離,如果代碼本身不是使用強(qiáng)隔離的工具鏈構(gòu)建的,也不會(huì)有什么幫助。如果一組人可以更新一個(gè)庫,然后鏈接到一組應(yīng)用程序,那么這些應(yīng)用程序并不算是真正的相互隔離,無論它們以什么方式運(yùn)行。5模塊邊界vs服務(wù)邊界如果這么多隔離層都很脆弱,那么我們?yōu)槭裁催€要費(fèi)心使用它們呢?主要是歷史沿革;如果我們拋棄這些層中的大部分,安全性不會(huì)受到太大影響,而簡潔性將得到提升。我預(yù)計(jì),隨著時(shí)間的推移,這會(huì)發(fā)生。我們已經(jīng)看到了這種趨勢。多用戶Unix系統(tǒng)已幾乎絕跡;“無服務(wù)器”服務(wù)器放棄了除最強(qiáng)隔離類型之外的所有隔離類型,并試圖將你鎖定在你所在的云提供商那里。但是,讓我們把歷史放在一邊。我必須介紹所有這些隔離概念,這樣我才能說得簡單點(diǎn):你幾乎從不出于安全原因定義模塊邊界。相反,模塊邊界通常遵循康威定律。人們分解模塊的根據(jù)是他們希望如何細(xì)分團(tuán)隊(duì)中的開發(fā)工作,而模塊之間的通信則取決于團(tuán)隊(duì)和團(tuán)隊(duì)成員之間的溝通方式。(康威定律很吸引人,也很真實(shí),但你可以在很多其他地方讀到它。)/wiki/Conway%27s_law模塊邊界并不能定義部署單元的大小。以操作系統(tǒng)為例:ChromeOS有成千上萬的開發(fā)人員,但用戶收到的一次更新中包含一個(gè)經(jīng)過全面測試的組合,其中有Linux內(nèi)核、設(shè)備驅(qū)動(dòng)程序、窗口管理器、Web瀏覽器等。這些模塊之間的接口可以在任何版本中更改,因?yàn)樗鼈儾恍枰蚝蠹嫒荩ó?dāng)然,硬件和Web除外)。macOS、iOS和Android采用了類似的模式。DebianLinux有數(shù)千名開發(fā)人員,但用戶下載和安裝的是單個(gè)的軟件包。你可以將來自古老的Debian穩(wěn)定版本的程序包,和來自如今的Debian不穩(wěn)定版本的程序包,一起運(yùn)行,而且很可能行得通??赡軟]有人測試過你這樣的特定組合,但它可能可以工作,因?yàn)槌绦虬g有定義得非常好的接口。(人們在開“桌面Linux”不可靠的玩笑時(shí),談?wù)摰目偸堑诙N小眾而難以測試的類型,而不是第一種主流的、容易測試的類型。我不認(rèn)為人們感知到的質(zhì)量差異實(shí)際上是由企業(yè)資金與開源差異所導(dǎo)致的。不同之處在于部署模型。)搜索公眾號后端架構(gòu)師后臺回復(fù)“架構(gòu)整潔”,獲取一份驚喜禮包。兩個(gè)系統(tǒng)都包含許多程序包(模塊),這些包是由不同團(tuán)隊(duì)的許多開發(fā)人員開發(fā)的。它們的模塊之間都有接口。如果你為每個(gè)系統(tǒng)畫一個(gè)方框和箭頭圖,可能看起來會(huì)非常類似:內(nèi)核、驅(qū)動(dòng)程序、窗口系統(tǒng)、沙箱、Web瀏覽器,等等。然而,如果是后端云服務(wù)而不是操作系統(tǒng),我們將分別稱這兩個(gè)模型為單體和微服務(wù),因?yàn)樗鼈兊牟渴鹉P?。一個(gè)只有一個(gè)要部署的“服務(wù)”,而另一個(gè)有許多,每個(gè)都要單獨(dú)部署。相同的模塊架構(gòu)!這是怎么回事呢?模塊邊界和服務(wù)邊界是兩個(gè)不同的東西。6服務(wù)的邊界應(yīng)該在哪里?讓我們回顧一下最初的模塊化目標(biāo):隔離:如果出于安全考慮,確實(shí)需要強(qiáng)隔離,如果你需要單獨(dú)的服務(wù),那么唯一的方法就是分別提供虛擬機(jī)。(不過請注意:這更多的是隔離系統(tǒng)的限制,而非架構(gòu)目標(biāo)。“基礎(chǔ)設(shè)施即代碼”和藍(lán)/綠部署會(huì)設(shè)法讓這些服務(wù)再次同步,所以你可以有一個(gè)單體式的部署模型。)連接:遵循康威定律。模塊邊界傾向于遵循團(tuán)隊(duì)的個(gè)性化溝通模式。但與直覺相反,康威定律并不需要定義服務(wù)邊界。兼容性保證:迫使你轉(zhuǎn)向單體。如果你的單體是用一種類型安全的語言編寫的,比如Go、TypeScript、Rust,甚至是C++,則尤其如此。(例如,Chrome就是一個(gè)巨大的二進(jìn)制文件。)升級、降級和可擴(kuò)展性:這些是決定服務(wù)邊界的主要因素。關(guān)于這一點(diǎn),讓我們再進(jìn)一步探討下。以下是選擇服務(wù)邊界時(shí)需要考慮的一些事項(xiàng):你的單體需要很長時(shí)間才能啟動(dòng)嗎?這讓升級變得很痛苦,所以你可能想把慢的部分分離出來,讓其他東西可以更快的升級。你需要正確的數(shù)據(jù)存儲模式版本嗎?有時(shí),這需要對后端所有實(shí)例進(jìn)行同步升級/降級,以便它們處于相同的模式版本上。同步升級是有風(fēng)險(xiǎn)的,而且往往會(huì)妨礙回滾;有時(shí),你希望使依賴于模式的部分盡可能小。持續(xù)集成測試經(jīng)常失敗嗎?如果是這樣,那真是個(gè)壞消息。那些失敗的測試說明代碼有問題。這是一個(gè)功能!拆分服務(wù)并單獨(dú)推出可能會(huì)欺騙測試,使其通過,但在生產(chǎn)環(huán)境中,你將會(huì)遇到兼容性和版本不對稱問題。那沒

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論