电竞比分网-中国电竞赛事及体育赛事平台

分享

溯源微服務(wù):企業(yè)分布式應(yīng)用的一次回顧

 黃爸爸好 2019-05-08

微服務(wù)作為架構(gòu)風(fēng)格幾乎成為云時(shí)代企業(yè)級(jí)應(yīng)用的事實(shí)標(biāo)準(zhǔn),構(gòu)成微服務(wù)的技術(shù)元素本身卻并非革命性。跨平臺(tái)的分布式通信框架、地址無(wú)關(guān)的服務(wù)注冊(cè)與發(fā)現(xiàn)、智能路由與編排等技術(shù)早已在CORBA、SOA時(shí)代實(shí)現(xiàn)了一遍又一遍,我們不禁好奇,微服務(wù)有什么不同?本文是對(duì)企業(yè)分布式應(yīng)用的一次回顧,與前微服務(wù)時(shí)代相比,我們究竟在哪些領(lǐng)域吸取了教訓(xùn),哪些方面持續(xù)搞砸。

我們?cè)谥匦陆缍ǔ橄筮吔缟先〉昧诉M(jìn)展...

架構(gòu)的關(guān)鍵在于構(gòu)造合理的封裝抽象。良好的抽象構(gòu)造如進(jìn)程,由操作系統(tǒng)接管CPU調(diào)度、內(nèi)存地址空間分配和I/O,程序員的心智從此解放,得以聚焦在業(yè)務(wù)邏輯上。糟糕的抽象往往引向萬(wàn)丈深淵,大量精力被浪費(fèi)在抽象泄露帶來(lái)的問(wèn)題上。

在分布式系統(tǒng)中我們關(guān)注組件、組件間的通信以及伴隨的工程實(shí)踐,微服務(wù)在企業(yè)應(yīng)用的上下文中就技術(shù)約束和業(yè)務(wù)價(jià)值間達(dá)成了更好的平衡點(diǎn)。


RPC?不,是API!

讓我們從組件間的通信開(kāi)始,最初人們認(rèn)為這只是需要被解決的技術(shù)要素。

(圖片來(lái)自:維基百科)

關(guān)于如何實(shí)現(xiàn)跨平臺(tái)的分布式通信,30年前誕生的CORBA架構(gòu)在今天來(lái)看仍然非常漂亮:通過(guò)定義IDL/ORB/API我們可以將內(nèi)存對(duì)象任意分布于網(wǎng)絡(luò)中。只要共享IDL,對(duì)象可以由C++/Java等不同的語(yǔ)言實(shí)現(xiàn),其互相調(diào)用就像本地方法一樣簡(jiǎn)單。然而實(shí)踐經(jīng)驗(yàn)告訴我們,分布式系統(tǒng)總是會(huì)出現(xiàn)本地調(diào)用不會(huì)發(fā)生的各種問(wèn)題:網(wǎng)絡(luò)的開(kāi)銷(xiāo)、傳輸?shù)难舆t、消息的超時(shí)和丟包、遠(yuǎn)端系統(tǒng)的崩潰……物理世界的技術(shù)約束是無(wú)法被忽略的,我們沒(méi)有辦法把分布式調(diào)用抽象成簡(jiǎn)單的本地方法。因此Martin Fowler在他的<企業(yè)應(yīng)用架構(gòu)模式>里提出了著名分布式對(duì)象第一定律:“不要分布式你的對(duì)象”。相反,你應(yīng)該把盡可能多的操作置于進(jìn)程之內(nèi),通過(guò)replicate整個(gè)應(yīng)用的方式來(lái)實(shí)現(xiàn)系統(tǒng)的scale。

由分析師們發(fā)起的SOA運(yùn)動(dòng)從另一個(gè)角度看待這個(gè)問(wèn)題,Web Service應(yīng)該是對(duì)企業(yè)資產(chǎn)和業(yè)務(wù)能力的封裝。我們開(kāi)始站在更高的維度,遠(yuǎn)過(guò)程調(diào)用不再只是技術(shù)意義上的集成。WSDL不僅是通信調(diào)用的接口,更是服務(wù)間的契約;UDDI不僅是服務(wù)描述、發(fā)現(xiàn)、集成的中心,更是企業(yè)業(yè)務(wù)與服務(wù)的黃頁(yè)。WS-*在廠商的裹挾下發(fā)展成包羅萬(wàn)象,卻也沒(méi)幾個(gè)人能掌握。開(kāi)發(fā)者們抱怨花了太多時(shí)間寫(xiě)冗余的XML制定所謂的規(guī)范,WSDL生成的客戶端也將不同服務(wù)耦合在一起。是否有更加輕量敏捷的方式,讓我們快點(diǎn)開(kāi)始寫(xiě)第一行生產(chǎn)代碼?

于是我們看到REST的興起。起初是作為反叛,用更加輕量級(jí)的方式(http+json)使用Web。然后我們發(fā)現(xiàn)'企業(yè)級(jí)'應(yīng)用并非需要ESB這樣昂貴的專有中間件,由'消費(fèi)級(jí)'技術(shù)組成的萬(wàn)維網(wǎng)是世界上最大規(guī)模的分布式網(wǎng)絡(luò),我們應(yīng)該向其學(xué)習(xí)如何構(gòu)建健壯、可演化的系統(tǒng)。Roy Fielding那篇論文所提出的無(wú)狀態(tài)、可緩存等特征已經(jīng)深入人心,而狹義上的REST API(基于資源的URI、HTTP動(dòng)詞和狀態(tài)碼的標(biāo)準(zhǔn)接口)也成為API設(shè)計(jì)的最佳實(shí)踐。

既然API和網(wǎng)站一樣都是基于通用Web技術(shù),API是否可以像網(wǎng)站一樣作為產(chǎn)品提供呢(APIs as product)?于是越來(lái)越多的企業(yè)開(kāi)始將自己的業(yè)務(wù)能力封裝成API,提供給消費(fèi)者,隨之而來(lái)的是更彈性的商業(yè)應(yīng)用和更靈活的計(jì)費(fèi)方式。很多組織也著手構(gòu)建自己的API市場(chǎng),把內(nèi)部IT能力整合、復(fù)用,并為孵化外部產(chǎn)品做準(zhǔn)備。API已經(jīng)成為商業(yè)價(jià)值主張的一部分。

我們從聚焦實(shí)現(xiàn)細(xì)節(jié)的rpc出發(fā),來(lái)到了更具價(jià)值導(dǎo)向的REST API。即使構(gòu)建內(nèi)部系統(tǒng),以消費(fèi)者驅(qū)動(dòng)的方式,也總是能幫助我們?cè)O(shè)計(jì)出更加松耦合和易于演進(jìn)的API。


技術(shù)組件?不,是業(yè)務(wù)服務(wù)!

編程語(yǔ)言中的組件構(gòu)造(如Java中的jar, C#中的dll)是軟件架構(gòu)師們封裝可復(fù)用單元的最常用武器。組件作為理論上的最小部署單元,在工程實(shí)踐中卻并不容易獨(dú)立變更。一般應(yīng)用程序需要講多個(gè)組件打包成一個(gè)部署單元(如war包),鏈接在內(nèi)存地址中進(jìn)行調(diào)用。對(duì)單個(gè)組件的熱更新往往對(duì)組件間耦合和對(duì)象狀態(tài)管理有很高的要求,重新部署整個(gè)應(yīng)用一般是默認(rèn)選項(xiàng)。以進(jìn)程為邊界構(gòu)建可獨(dú)立部署的服務(wù)成為架構(gòu)師的另一項(xiàng)選擇。

早期的服務(wù)只是單純的技術(shù)構(gòu)件,大多數(shù)組織從純粹的技術(shù)實(shí)現(xiàn)角度考慮服務(wù)的劃分。SOA的推動(dòng)者們指出企業(yè)的信息資產(chǎn)應(yīng)該被復(fù)用,信息孤島應(yīng)該被打通。通過(guò)將不同的服務(wù)編排組合,我們應(yīng)該能夠?qū)崿F(xiàn)IT對(duì)業(yè)務(wù)更加靈活的支撐。

(圖片來(lái)自:0SOA in practice, Nicolai Josuttism, 2009)

SOA的服務(wù)建模一般采用業(yè)務(wù)流程驅(qū)動(dòng)的方式。一個(gè)典型的SOA設(shè)計(jì)是由業(yè)務(wù)分析師自頂向下地對(duì)企業(yè)現(xiàn)有業(yè)務(wù)流程進(jìn)行分析,通過(guò)BPM引擎對(duì)流程進(jìn)行建模,向下分解成組合服務(wù),并進(jìn)一步拆分成數(shù)據(jù)訪問(wèn)服務(wù)(很多可憐的SOA實(shí)現(xiàn)中數(shù)據(jù)的訪問(wèn)被拆分成不同的讀服務(wù)和寫(xiě)服務(wù))。然而這帶來(lái)的問(wèn)題是,服務(wù)跟服務(wù)間的耦合非常嚴(yán)重。當(dāng)我的業(yè)務(wù)發(fā)生了變化,可能會(huì)需要修改很多不同的服務(wù),涉及到多個(gè)團(tuán)隊(duì)的溝通和協(xié)調(diào)。在運(yùn)行時(shí)層面,服務(wù)器間的通信非常頻繁,用戶在界面上的一次點(diǎn)擊按鈕,對(duì)應(yīng)的后臺(tái)多層服務(wù)間的級(jí)聯(lián)通信。這給系統(tǒng)性能和穩(wěn)定性也帶來(lái)了巨大的挑戰(zhàn)。SOA式的服務(wù)建模從分析型思維出發(fā),卻往往低估了分布式系統(tǒng)和跨團(tuán)隊(duì)協(xié)調(diào)的復(fù)雜度,導(dǎo)致服務(wù)拆分粒度過(guò)細(xì)。

微服務(wù)的名字常常讓人誤解,但實(shí)施正確的微服務(wù)粒度可能并不'微'。Martin Fowler與James Lewis在開(kāi)創(chuàng)微服務(wù)定義的一文中已經(jīng)指出微服務(wù)應(yīng)該圍繞完整的業(yè)務(wù)能力。今天我們?cè)谧鑫⒎?wù)設(shè)計(jì)時(shí),常常利用領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)中的Bounded Context來(lái)進(jìn)行服務(wù)邊界的劃分。假設(shè)你的庫(kù)存管理是一個(gè)獨(dú)立的業(yè)務(wù)子域,針對(duì)庫(kù)存的維護(hù)和操作應(yīng)該被放到通過(guò)一個(gè)上下文和微服務(wù)中,由一個(gè)團(tuán)隊(duì)進(jìn)行開(kāi)發(fā)維護(hù)。多數(shù)業(yè)務(wù)變更都發(fā)生在上下文內(nèi)部,不涉及跨團(tuán)隊(duì)協(xié)調(diào)。單個(gè)codebase內(nèi)的重構(gòu)和部署讓發(fā)布更加容易。維護(hù)庫(kù)存所需要的信息查詢的調(diào)用多發(fā)生在進(jìn)程內(nèi),更好的性能,同時(shí)無(wú)需處理額外的一致性問(wèn)題。

微服務(wù)的另一個(gè)特點(diǎn)在于Product over Project,這需要不同于傳統(tǒng)投資組合的預(yù)算管理與團(tuán)隊(duì)組建。傳統(tǒng)的項(xiàng)目制將預(yù)算分配在相對(duì)短期的服務(wù)開(kāi)發(fā)過(guò)程中,項(xiàng)目團(tuán)隊(duì)關(guān)注的是如何將業(yè)務(wù)范圍(scope)實(shí)現(xiàn),開(kāi)發(fā)結(jié)束后服務(wù)轉(zhuǎn)交運(yùn)維團(tuán)隊(duì)進(jìn)行維護(hù),項(xiàng)目團(tuán)隊(duì)則被解散進(jìn)行其他項(xiàng)目的開(kāi)發(fā)。將微服務(wù)作為產(chǎn)品運(yùn)營(yíng)則需要建立業(yè)務(wù)結(jié)果導(dǎo)向的穩(wěn)定產(chǎn)品團(tuán)隊(duì)。服務(wù)的設(shè)計(jì)不只聚焦于當(dāng)下需求,更需要考慮價(jià)值定位和產(chǎn)品愿景。工程團(tuán)隊(duì)則需要思考如何用有限成本支撐非線性的業(yè)務(wù)接入增長(zhǎng)。

(圖片來(lái)自:Enterprise Architecture as Strategy, Ross et al, 2006)

如今我們對(duì)服務(wù)的定義已經(jīng)超越了技術(shù)組件,領(lǐng)先的組織已經(jīng)在嘗試將design thinking, business operating model應(yīng)用到微服務(wù)設(shè)計(jì)中。


解耦服務(wù)就足夠了嗎?我們需要去中心化一切!

即使有了設(shè)計(jì)合理的服務(wù)于API,我們?nèi)匀恍枰c之匹配的工程實(shí)踐才能將其順利實(shí)施。

今天仍有很多企業(yè)使用集中式的應(yīng)用服務(wù)器部署應(yīng)用:開(kāi)發(fā)團(tuán)隊(duì)將軟件包構(gòu)建出來(lái),再統(tǒng)一安裝到應(yīng)用服務(wù)器中。對(duì)應(yīng)用團(tuán)隊(duì)來(lái)說(shuō),這往往意味著漫長(zhǎng)的反饋周期和痛苦的自動(dòng)化。我們很早就推薦用Jetty這樣內(nèi)嵌式的應(yīng)用容器部署軟件,啟動(dòng)更快,測(cè)試環(huán)境更接近生產(chǎn)。one Tomcat per VM的部署方式雖然運(yùn)行時(shí)開(kāi)銷(xiāo)較大,卻是前容器時(shí)代隔離性最好的服務(wù)部署模式。Docker將這個(gè)實(shí)踐更進(jìn)一步,除了更輕量級(jí)的隔離,我們第一次可以將軟件和所依賴的環(huán)境本身打包成版本化的artifact,徹底統(tǒng)一開(kāi)發(fā)和生產(chǎn)環(huán)境。容器技術(shù)的成熟讓我們可以將部署去中心化,開(kāi)發(fā)團(tuán)隊(duì)可以獨(dú)立部署一個(gè)服務(wù)。

數(shù)據(jù)庫(kù)耦合是影響服務(wù)獨(dú)立變更的另一重要因素。相比代碼構(gòu)成的應(yīng)用軟件,數(shù)據(jù)庫(kù)schema更加難以變動(dòng)。因?yàn)殡y以測(cè)試、難以兼顧性能優(yōu)化和耦合的發(fā)布周期等因素,服務(wù)間以數(shù)據(jù)庫(kù)集成成為臭名昭著的反模式。服務(wù)間的集成應(yīng)該依賴封裝好的顯示接口,而不是數(shù)據(jù)庫(kù)這種實(shí)現(xiàn)細(xì)節(jié)。我們應(yīng)該在兼顧數(shù)據(jù)一致性的情況下,為每個(gè)微服務(wù)分配獨(dú)立的db schema甚至db instance。如果說(shuō)十年前數(shù)據(jù)幾乎等同于關(guān)系數(shù)據(jù)庫(kù)。如今數(shù) 據(jù)則可能呈現(xiàn)出各種形態(tài):鍵值、文檔、時(shí)間序列、圖...我們完全可以采用更加合適的技術(shù),以去中心化的方式進(jìn)行微服務(wù)的數(shù)據(jù)治理。

即使將這一切都解耦,如果將交給一個(gè)集中的團(tuán)隊(duì)去實(shí)施,很有可能最終還是得到一個(gè)耦合的架構(gòu)。這就是是著名的康威定律??低筛嬖V我們“設(shè)計(jì)系統(tǒng)的架構(gòu)受制于產(chǎn)生這些設(shè)計(jì)的組織的溝通結(jié)構(gòu)”。但同樣我們可以將康威定律反轉(zhuǎn)應(yīng)用:如果你想達(dá)成一個(gè)目標(biāo)架構(gòu),則必須對(duì)團(tuán)隊(duì)結(jié)構(gòu)進(jìn)行調(diào)整,使之和目標(biāo)架構(gòu)對(duì)齊。相比單體系統(tǒng),微服務(wù)在運(yùn)行時(shí)監(jiān)控和運(yùn)維所帶來(lái)的挑戰(zhàn)更大。'you build it, you run it'的DevOps文化成為必須。監(jiān)控運(yùn)維不再是Ops部門(mén)的事情,產(chǎn)品團(tuán)隊(duì)必須對(duì)微服務(wù)的整個(gè)生命周期負(fù)責(zé)。授權(quán)的去中心化自治團(tuán)隊(duì)是實(shí)施微服務(wù)的必要條件。


我們干得還不錯(cuò),但也在持續(xù)搞砸一些事情...

我們?cè)诤芏喾较虻拇_取得了進(jìn)展。但即使在微服務(wù)時(shí)代,很多問(wèn)題仍然在輪回發(fā)生著,似乎我們總是無(wú)法吸取歷史的教訓(xùn)。讓我們看一看那些揮之不去的反模式陰云。

一個(gè)例子是開(kāi)發(fā)者對(duì)強(qiáng)類型RPC代碼生成的依戀。盡管歷史經(jīng)驗(yàn)已經(jīng)證明同步的rpc無(wú)法為分布式通信提供足夠好的封裝,偽裝成本地方法調(diào)用的客戶端往往鼓勵(lì)程序員做出糟糕的接口設(shè)計(jì):細(xì)粒度的頻繁調(diào)用、缺少緩存和容錯(cuò)處理。IDL生成客戶端也會(huì)導(dǎo)致服務(wù)間耦合,每次變更接口都需要升級(jí)數(shù)個(gè)相關(guān)服務(wù)。如果用可演進(jìn)的REST API(如HATEOS)和tolerant reader模式,則可以優(yōu)雅地解決這個(gè)問(wèn)題。然而新一代的開(kāi)發(fā)者們還是經(jīng)?!爸匦隆卑l(fā)現(xiàn)rpc的這些能力并陷入依賴——更快的序列化反序列化、類型安全和來(lái)自IDE的智能提示、通過(guò)spec反向生成代碼...分布式計(jì)算先驅(qū)Vinoski不禁感嘆“開(kāi)發(fā)人員的便利性是否真的勝過(guò)正確性,可擴(kuò)展性,性能,關(guān)注點(diǎn)分離,可擴(kuò)展性和意外復(fù)雜性?”

另一個(gè)揮之不去的陰影是ESB。ESB在將異構(gòu)的應(yīng)用wire在一起有著關(guān)鍵的作用。然而當(dāng)越來(lái)越多的職責(zé)被加入:數(shù)據(jù)報(bào)文的裁剪轉(zhuǎn)換、難以測(cè)試和版本控制的編排(orchection)邏輯、服務(wù)發(fā)現(xiàn)智能路由監(jiān)控治理分布式事務(wù)等All in One的solution將ESB變成了一個(gè)可怕的單點(diǎn)夢(mèng)魘。所以微服務(wù)發(fā)出了“智能終端啞管道”的吶喊:我們只是需要一個(gè)不那么智能的代理處理可靠消息傳輸,將靈活的邏輯交給服務(wù)本身去編配(choreography)吧。

于是在典型的微服務(wù)架構(gòu)里,負(fù)載均衡、服務(wù)注冊(cè)發(fā)現(xiàn)、分布式追蹤等組件以Unix way的方式各司其職。然而在利益誘惑和特性競(jìng)爭(zhēng)壓力之下,很多廠商不斷將更多的功能放進(jìn)他們的中間件,其中為代表的Overambitious API gateways儼然要重新實(shí)現(xiàn)占據(jù)中心的ESB。如果API gateway只是處理鑒權(quán)、限流等橫切層邏輯沒(méi)有問(wèn)題,如果API gateway開(kāi)始處理數(shù)據(jù)轉(zhuǎn)換和業(yè)務(wù)邏輯編排,你應(yīng)該提高警惕!

盡管行業(yè)在不斷發(fā)展,但很多時(shí)候人們?nèi)匀谎赜门f的思維,用新的技術(shù)去一遍遍重新實(shí)現(xiàn)這些舊的反模式。


如何更進(jìn)一步

你總是可以在技術(shù)雷達(dá)里追蹤微服務(wù)的state of art,如今這個(gè)領(lǐng)域的前沿方向是什么,Service Mesh, Chaos Engineering, 還是Observability as Code?然而歷史告訴我們,新的技術(shù)在解決一些問(wèn)題的同時(shí),也可能會(huì)產(chǎn)生新的問(wèn)題。更糟糕的是,我們永遠(yuǎn)無(wú)法記住歷史,用新的工具更高效地重現(xiàn)舊日問(wèn)題。

Technologies come and go, Principles stay forever。好在那些架構(gòu)和實(shí)踐背后的原則是經(jīng)久不變的。從操作系統(tǒng)到移動(dòng)應(yīng)用都會(huì)需要高內(nèi)聚低耦合的架構(gòu),任何軟件開(kāi)發(fā)都需要版本控制、自動(dòng)化構(gòu)建等實(shí)踐。謹(jǐn)記這些核心原則、謹(jǐn)記軟件被創(chuàng)造出來(lái)是為了解決有價(jià)值的問(wèn)題,可以幫我們更好的借鑒歷史的經(jīng)驗(yàn),理解和采納新的技術(shù)。


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多