在我們的軟件開發(fā)流程中,經(jīng)常需要面臨改動,有來自用戶需求的改動,來自市場的,以及為了一些潛在機會而產(chǎn)生的改動等。當這些改動來臨的時候,我們需要能夠快速做出調(diào)整。但不幸的是,事情并不總是如我們所愿。
那么我們之前是怎么做的呢?
對于資歷較老的程序員來說,應(yīng)該都還記得有一種基于可重用組件的設(shè)計方法。在這種方法中,專門有一個架構(gòu)團隊,他們來識別出整個組織中? 各個部門應(yīng)該怎么使用某一組件。某些時候架構(gòu)團隊的業(yè)績甚至還會與其所設(shè)計的組件被使用的次數(shù)進行掛鉤。但是不幸的是,由于架構(gòu)團隊和組件使用團隊缺少連接,因此架構(gòu)團隊很難設(shè)計出一個有口皆碑,受使用者歡迎的組件。
還記得另外一種通過數(shù)據(jù)庫做集成的架構(gòu)么?是的,我們之前都是這么做的,在這種架構(gòu)模式中,我們有一個巨型數(shù)據(jù)庫,所有的數(shù)據(jù)都囊括其中。圍繞著這個數(shù)據(jù)庫的周圍,有一圈各種各樣的應(yīng)用,它們支配著這些數(shù)據(jù)。
此外還有一種曾經(jīng)頗為流行的面向服務(wù)的架構(gòu),這種架構(gòu)理念聲稱它們可以達到我們想達到的目標。這種架構(gòu)確實有其做的不錯的一些地方,首當其沖的是它讓組織者知道并不是所有的東西都必須是模塊化的。與此同時,它也激發(fā)了大家開始思考,將多種功能更好的集成到一起,而不是緊耦合到一塊,比如你可以想想使用中間件,消息隊列或者其他一些更松耦合的方法。
SOA(面向服務(wù)型架構(gòu))讓最終一致性得到更加廣泛的認同。一直以來,傳統(tǒng)的(DBA)數(shù)據(jù)庫管理員這個角色起著至關(guān)重要的作用,因為最有價值的數(shù)據(jù)資源均由他們保護。在訪問數(shù)據(jù)庫的時候,一切都是關(guān)系型的,都是事務(wù)處理。因此每當你說我需要做持久化的時候,就會有人告訴你,放在一個關(guān)系型數(shù)據(jù)庫里就好了,大家對此都達成默契了,沒有任何問題。然后所有的操作都是完整的事務(wù)處理,我們可以使用關(guān)系型數(shù)據(jù)庫所能提供的所有功能。以前大家都是這么干的。而SOA的出現(xiàn)最少啟發(fā)了大家開始討論我們是不是可以用另外的方式來取代之前的老路子,從這個方面來講,SOA確實有其正面意義。
但不幸的是,SOA也犯了一些錯誤。最主要的一個問題是其龐大的服務(wù)。如果你看一看使用SOA模型做出來的這些服務(wù),這些海量服務(wù)作為一個全局組件,還是太大了,太難做出改動,也太難部署了。其次,SOA傾向于提供方驅(qū)動的服務(wù),我指的意思是,當你開始想我要寫一個用戶服務(wù),我要給用戶提供這些信息,因為我是這些信息的提供方。我假設(shè)我知道用戶將會如何使用這些信息。這種思路其實和設(shè)計可重用組件的架構(gòu)師差不多,我們統(tǒng)稱為信息提供方驅(qū)動。一般而言是由組織中的IT部門做完之后移交給業(yè)務(wù)部門使用,這種設(shè)計中的想法大部分是從系統(tǒng)的角度在想問題,而不是從應(yīng)用的角度。
SOA的另外一個問題是其充斥著大量的編配(orchestration),注意這里我們說的是編配而不是編排(choreography)。在管弦樂(也是orchestration這個詞)中,有一個統(tǒng)一的指揮,由他來指揮整個樂團,他來設(shè)置節(jié)奏,音量等各種信息。整個樂團里的個體都無一例外的聽命于這個指揮。我們設(shè)想一下,如果某個時候同時發(fā)生兩件事,那么可能就需要兩個指揮??偠灾谶@種模型里面,有一個類似指揮的角色來對整個系統(tǒng)全盤負責(zé)。而編排卻不是這樣,在編排的時候,每個個體只需要關(guān)注自己周圍的其他成員就行,而并沒有一個統(tǒng)一的總指揮。當出現(xiàn)問題的時候,每個個體只要知道自己應(yīng)該怎么調(diào)整就行,同樣也不需要一個所謂的總指揮來指揮它進行調(diào)整。SOA這種類似管弦樂團的組織方式,過分集中化了,從而導(dǎo)致其本身通常難以測試。
SOA還有一個問題是工藝受阻。SOA需要我們有這樣的供應(yīng)商,能滿足業(yè)務(wù)部門的所有想法,然后業(yè)務(wù)部門只需要坐在自己的辦公室里面做一些自定義的配置就可以了。因此最后的工具通常是我們將一些之前有人用過的系統(tǒng)稍作修改來供應(yīng)另外一群用戶。
事實上,SOA搞出來的東西甚至比沒有他們之前還要更難以修改。諷刺的是SOA恰恰是為了讓改動變得容易而誕生的。與此同時,SOA不可避免的也很難進行測試。
好,現(xiàn)在我們來聊聊微服務(wù)(micro-services)
簡單來講,你可以將微服務(wù)理解成正確的SOA模式。我們的關(guān)注點還是服務(wù),在微服務(wù)的架構(gòu)里面,服務(wù)是作為一個基礎(chǔ)單元存在的。SOA本身即是面向服務(wù)的架構(gòu),所以我們這個其實也可以叫SOA2,但是我們還是用了微服務(wù)這個名字,目的就是提醒大家不要搞海量服務(wù)。這是一段James Lewis和Martin Fowler的文章中摘抄的一段關(guān)于微服務(wù)的定義:
一種將一組小型服務(wù)做成一個單獨應(yīng)用的開發(fā)方式,每一個小型服務(wù)在其獨自的進程中運行,使用諸如HTTP資源API等其他輕量級方式進行通信。重點是要輕量級。
微服務(wù)有些什么特點呢?
第一個顯而易見的特點是,微服務(wù)中每個個體服務(wù)單元很小。這里所謂的小其實并不是絕對的,其思想的要點是,與其搞一個大而全的服務(wù)體,我們更傾向于小一些的單一服務(wù)。微服務(wù)的另外一個特點是,這些服務(wù)是按照業(yè)務(wù)能力構(gòu)建的。之前我們經(jīng)常掉入一個陷阱,就是從系統(tǒng)的角度思考問題,而不是從業(yè)務(wù)角度。現(xiàn)在我們不僅要思考系統(tǒng)能力,更要思考業(yè)務(wù)能力。并且我們需要按照業(yè)務(wù)能力來組織工作。對于業(yè)務(wù)部門而言,如何實現(xiàn)的并不重要,他們所關(guān)心的是系統(tǒng)長什么樣子,怎么樣能方便用戶使用。業(yè)務(wù)部門是這么思考的,我們也對應(yīng)的需要圍繞業(yè)務(wù)能力進行設(shè)計。
微服務(wù)中的服務(wù)個體都是可以單獨部署的。也就是說,只要沒有動接口協(xié)議,在修改某一個服務(wù)個體的時候,完全不用理會其他服務(wù)個體。在微服務(wù)中,只有很少一部分的集中管理,而由于各個服務(wù)個體之間是相對獨立的,因此我們甚至可以在不同的服務(wù)單元采用不同的技術(shù)棧。比如某一部分的計算邏輯比較復(fù)雜,我們選用clojure,另外一部分則對應(yīng)著很強的對象模型,我們可以用一些面向?qū)ο蟮木幊陶Z言等等。
在微服務(wù)中,我們主張“智能端點”和“傻瓜管道”。基本上如果管道兩邊都按照一定的假設(shè)強制執(zhí)行的話,需要重新配置時就會簡單許多,而并不需要時刻監(jiān)控管道中的各種中間狀態(tài)。當我們嘗試把現(xiàn)在的這種模塊拆分的時候,需要考慮的另一個問題是,數(shù)據(jù)庫的結(jié)構(gòu)應(yīng)該是什么樣的?具體的問題還包括數(shù)據(jù)如何進行維護,其他單元如何緩存等等。毫無疑問在微服務(wù)中,數(shù)據(jù)結(jié)構(gòu)的形態(tài)會有很大不同。
使用微服務(wù)意味著什么呢?
首先粒度的問題是至關(guān)重要的,當你在思考微服務(wù)的邊界問題時,這應(yīng)該是使用微服務(wù)架構(gòu)需要做出的一個最重要的決定。在這個過程中需要平衡好內(nèi)聚和耦合的關(guān)系,一方面為了加強內(nèi)聚你可能需要將某一些服務(wù)合并到一起,另外一方面為了解耦,需要對某些服務(wù)進行拆分。事實上在使用微服務(wù)架構(gòu)的整個過程中都充斥著來回往復(fù)的拆分和合并,直到你真的理解了服務(wù)的邊界應(yīng)該是什么為止。我們后面會繼續(xù)回到這個問題上。
微服務(wù)中的各個服務(wù)個體是可以獨立擴展的,也就是說如果某個服務(wù)上的需求量猛增,我們只需要擴展該服務(wù)即可,于其他服務(wù)無關(guān)。相應(yīng)的,對于各個服務(wù)的狀態(tài)監(jiān)控也非常重要。如果你手頭是一個單塊,從定義來看,理論上你需要監(jiān)控的只有一個東西。而到了微服務(wù)里面,因為我們有大量的小型服務(wù),因此需要對所有這些服務(wù)進行監(jiān)控才行,你需要清除的知道每一個服務(wù)是不是在工作,是不是在正常工作,為此光監(jiān)控就會需要更多的機器。
在微服務(wù)中,我們還需要考慮服務(wù)掛掉的情況,而這些情況在傳統(tǒng)單塊架構(gòu)里面一般不用怎么考慮。比如我們有一塊業(yè)務(wù)需要依賴數(shù)個獨立的微服務(wù),那么我們需要考慮的失敗場景就相當多了,基本上是把所有這些可能的失敗進行排列組合,而不得不說的一點是,在傳統(tǒng)單塊架構(gòu)里面這些可能根本就不成之為一個問題。
在微服務(wù)架構(gòu)中,因為我們有很多獨立的單元,它們需要獨自進行部署,因此我們真心離不開基礎(chǔ)設(shè)施的自動構(gòu)建,自動化部署和持續(xù)交付這些基礎(chǔ)。在微服務(wù)中,雖然我們講在不同的服務(wù)中可以使用不同的技術(shù)棧,但是這種靈活性如果任其發(fā)展最終也會完全不可控,因此我們需要管理好這種靈活性。我之前呆過的一個項目里面,光是XML解析就有11種不同的方法,是的你沒聽錯,11種之多。一般來講我覺得兩種XML解析器我尚能接受,但是11種實在是難以理解。因此在微服務(wù)架構(gòu)中,我們必須要避免引入所有類型的編程語言,引入所有不同種類的數(shù)據(jù)庫,沒什么原因,明眼人都知道,我們不能這么做。在系統(tǒng)的技術(shù)棧方面,我們必須在某個層面進行控制,否則一發(fā)不可收拾了。
當然最終一致性也必須管理好。一旦我們開始將數(shù)據(jù)分散到各個不同的服務(wù)單元里面去,我們必須考慮到這對于信息傳播會有什么影響。其中的一個結(jié)果就是,我們需要給業(yè)務(wù)人員講清楚,什么是最終一致性。一般而言我覺得業(yè)務(wù)人員會理解成“可能會一致”,而不是最終會達到一致。我們必須時刻想到由于最終一致性的存在所可能產(chǎn)生的各種后果。同樣,如果我們用的是一個大而全的關(guān)系型數(shù)據(jù)庫的話,壓根就不會存在這個問題。
好了,大家看看我們列出來的這些個問題,他們一個比一個復(fù)雜,而在傳統(tǒng)的單塊模型中,這些問題我們根本不用想。當我們回顧這些問題的時候,不由得會想到我們的初衷,如果我們的初衷能夠得以實現(xiàn),最少能彌補解決這些問題時所帶來的痛處。我們的初衷是什么呢?讓系統(tǒng)能盡可能快的響應(yīng)變化!另外一個方面,這些問題也在一定程度上警醒著你,微服務(wù)這個東西不是你想象的那么簡單,不是照著教程做一遍就可以大功告成,然后出門跟人炫耀:哥在搞微服務(wù)哦,牛逼吧!
最后有一點差點忘了說了,接口的改動也必須有個限度。在定義清楚服務(wù)邊界的時候,你少不了要修改一些接口協(xié)議,在修改的時候務(wù)必想清楚這個修改意味著什么。這個也深受團隊成員結(jié)構(gòu)的影響,比如如果寫另外一個服務(wù)的人就在你旁邊,改起來三兩句話就搞定了,但是如果團隊成員咫尺天涯或者天各一方,這個溝通過程本身就是一個巨大的成本。
好了,以上這些就是我認為的在準備使用微服務(wù)的時候,需要想清楚的一些問題。
好了,我們現(xiàn)在有兩個選項。第一個是一片綠地,就好比我們拿到一個空白的項目,沒有任何的遺留代碼。這種情況也有,但是很少。另外還有一點,在馬丁即將發(fā)表的一篇文章里提到,我們并不建議在一個嶄新的項目中一開始就使用微服務(wù)進行開發(fā)。因為你很可能并不真的理解業(yè)務(wù)領(lǐng)域,從而也很難理解各個服務(wù)的邊界。因此在這種項目中,可以先做成單塊的,進行適當?shù)哪K化,加深理解之后再考慮演進成微服務(wù)??偠灾?,你遲早會走到這個點,就是我們怎么將一個單塊系統(tǒng)拆解成微服務(wù)架構(gòu)的。
首先,想清楚邊界上下文。這其實是從領(lǐng)域驅(qū)動設(shè)計一書中拿過來的概念。所謂的邊界,指的是你可以將某些部分用一個圈圈起來,圈里的內(nèi)容代表了一定的業(yè)務(wù)面。這個所謂的邊界其實就是我們設(shè)計服務(wù)邊界時的一個重要指示。再回到我之前說的那個問題,你需要對你的系統(tǒng)有一個全面透徹的認知之后,才能做出這些決定。作為劃分服務(wù)邊界的第一個提示便是:嘗試按照領(lǐng)域驅(qū)動設(shè)計的方式來思考服務(wù)的邊界應(yīng)該在哪里。
其次還是這一點:從業(yè)務(wù)能力的角度來思考服務(wù)的邊界。想想系統(tǒng)所提供的產(chǎn)品、服務(wù)是什么,從這個角度想想怎么樣才算一個合理的服務(wù)邊界。
想想調(diào)用者需要什么。與提供方驅(qū)動的方式不同的是,你需要想想這個服務(wù)的使用者會需要些什么信息。也就是說需要從真實的需求開始想問題,而不是一些作為提供方揣測出來的需求。
想想服務(wù)之間的通信模式。想想哪些服務(wù),哪些系統(tǒng)可能會用到同一組數(shù)據(jù),不同的服務(wù)之間怎么合作來實現(xiàn)一個特殊的業(yè)務(wù)產(chǎn)出。特別是當我們在猶豫是要將兩個服務(wù)分開還是合并到一塊的時候,想想拆開之后可能產(chǎn)生的各種通信,以及通信失敗的情形等等。
想想數(shù)據(jù)結(jié)構(gòu)。一般而言,大家不愿意花太多精力想怎么保護數(shù)據(jù)的問題,也不會糾結(jié)太多最終一致性產(chǎn)生的影響。你怎么設(shè)計數(shù)據(jù),合適的數(shù)據(jù)結(jié)構(gòu)應(yīng)該是什么樣的也可以作為一個指示你如何設(shè)計服務(wù)邊界的提示。因為服務(wù)是持有數(shù)據(jù)的。我們不再想的是一個數(shù)據(jù)庫周圍圍繞著一堆服務(wù),而是每一個服務(wù)有一個自己的持久化存儲。
想想聯(lián)動變化模式。比如有兩個業(yè)務(wù)部分需要一起改,其實某種程度上在提示你,是不是把這兩塊放到一個服務(wù)里面更加合適。因此多想想未來可能產(chǎn)生的各種改動,對你做出決定也會有所幫助。
做好出錯的準備,你可能經(jīng)常需要將一些服務(wù)進行合并,而后搞不好又要重新再拆開。由于服務(wù)還牽扯到數(shù)據(jù),如果兩個服務(wù)的關(guān)系是一個服務(wù)主要負責(zé)一部分數(shù)據(jù),而另外一個服務(wù)中對這部分數(shù)據(jù)只是進行緩存的話,你或許還要考慮一些需要數(shù)據(jù)遷移的情況。一般而言你不會想經(jīng)常修改服務(wù)的邊界,因為這會帶來一系列的應(yīng)用程序,數(shù)據(jù)的改動。但是還是那句話,做最壞的打算。
最后的一點是:做一名有耐心的讀者。這其實扯到演進架構(gòu)的內(nèi)容了。首先是我們不能把build搞掛了。我們能做的是只有在沒有別的選擇的時候,我們才開始改。而做耐心的讀者就是為了確保他們改的確實是你所需要的。也就是說在正式確定修改我們實現(xiàn)之前,需求本身可能改的還要多一些。
OK,那么微服務(wù)與演進式架構(gòu)還有什么聯(lián)系呢?其實當我們談?wù)撗葸M式架構(gòu)的時候,其實是有很多不同的原則的。這些原則都很嚴格,而微服務(wù)某種程度上展現(xiàn)出了一些演進式架構(gòu)的原則。我們在談微服務(wù)的時候,主要是想用它來快速應(yīng)對頻繁的需求變更,因此微服務(wù)所承載的期望便是讓我們能盡可能快的適應(yīng)變化。而演進式架構(gòu)中所倡導(dǎo)的進化性與此不謀而合??蛇M化型并不同于可維護性,但也不是說要怎么預(yù)測未來,而是一種隨時準備響應(yīng)變化的狀態(tài),而不管你是否提前就設(shè)想好了這些變化。以前關(guān)于可進化性的一個理解誤區(qū)是,我要非常聰明的想到所有可能出現(xiàn)的變化,并且為所有的這些可能的變化寫好代碼,哪怕到頭來根本就沒變。因此微服務(wù)將可進化性作為其首要目標。
耐心的讀者,是的前面已經(jīng)提到過一遍了。我們可以做出任何改變,但這種改變必須是我們經(jīng)過大量的溝通討論之后得出的統(tǒng)一結(jié)論。
遵從康威法則。我們需要關(guān)注怎么組織團隊結(jié)構(gòu),以及不同的團隊結(jié)構(gòu)可能影響到最終的系統(tǒng)形態(tài)。只有團隊對服務(wù)有很好的所有權(quán)意識,團隊做出來的微服務(wù)才是這種松耦合的獨立服務(wù)。某些采用了微服務(wù)的組織中,但是并沒有一個專門的支持維護團隊,因此每個團隊成員會不自覺地將他的那部分代碼寫好,因為誰也不想大周末的還要跑到公司來修BUG。
適當耦合。我們在談演進式架構(gòu)的時候,其實總是在平衡耦合與性能、復(fù)雜度等其他因素之間的關(guān)系。
協(xié)議。在微服務(wù)架構(gòu)中,各個服務(wù)可以獨立演進。那么必不可少的一環(huán)就是相互之間的接口協(xié)議。通常而言我們可以借助于一些協(xié)議測試工具或者文檔來確保相互之間正常工作。作為服務(wù)提供方同時還應(yīng)該提供對應(yīng)的接口測試給調(diào)用方,而一旦調(diào)用方發(fā)現(xiàn)這個測試失敗了,馬上需要找到提供方確認問題。測試的另外一重含義是,只要這個全面的接口測試是正常通過的,那么無論提供方把代碼改成什么樣了,調(diào)用一方都不用關(guān)心,因為大家都是獨立的,鏈接這彼此的就是這些接口協(xié)議,這也是為什么微服務(wù)中的接口協(xié)議顯得如此重要的一個重要原因。
最后,作為一名來自ThoughtWorks的員工,我不得不談?wù)劀y試相關(guān)的事情。我們發(fā)現(xiàn)如果你始終沿著方面測試的方向設(shè)計架構(gòu),最后的架構(gòu)會更加簡潔。而且易于測試的系統(tǒng)一定是有一個清楚的定義的,你甚至不需要顆粒度太細的測試,哪怕只有一個非常頂層的端到端測試,但是只要這個測試能簡單明了的描述了其行為就已足夠。當你的架構(gòu)設(shè)計的很好,邊界劃分的很清楚的時候,系統(tǒng)本身就應(yīng)該是很好測試的。我們發(fā)現(xiàn),一般而言,不管是從代碼層面還是系統(tǒng)層面,關(guān)注測試始終會讓你的架構(gòu)更加完善。而且一般而言,基于測試定義的邊界,也讓整個架構(gòu)更容易做出改變。
持續(xù)交付在這里扮演什么角色呢?
微服務(wù)相比于傳統(tǒng)架構(gòu),增加了大量的運維負擔(dān)。有更多的東西需要部署,有更多的地方需要監(jiān)控,出錯的地方自然也成倍增加,有更多的數(shù)據(jù)庫,對應(yīng)的需要更多的備份。在微服務(wù)架構(gòu)中,出現(xiàn)問題時如何快速恢復(fù)也是件很復(fù)雜的事,因為服務(wù)數(shù)量眾多,對應(yīng)的排列組合情況更是數(shù)不勝數(shù)。
第二點是微服務(wù)需要很強的運維文化,這里我用了“不明智”這個詞,主要是強調(diào)運維文化對于微服務(wù)架構(gòu)的重要性。如果你的開發(fā)團隊和運維團隊之間有堵高墻,那么用微服務(wù)實施下去必然是個災(zāi)難。這里面有大量的瑣事需要做好做對,需要理解清楚。如果沒有一種強運維環(huán)境,你那個單獨的運維團隊一定會被你搞瘋掉的。
如果不能嚴格執(zhí)行持續(xù)交付,而選擇了微服務(wù)也不是一種明智之舉。在程序出錯的時候,我們需要趕緊進行調(diào)試,但是如果你連現(xiàn)在的代碼是哪個版本都沒法準確知道,你告訴我怎么他喵的調(diào)試?所以嚴格執(zhí)行持續(xù)交付是微服務(wù)架構(gòu)賴以成功之根本。關(guān)于持續(xù)交付的內(nèi)容,比如基礎(chǔ)設(shè)置自動化,自動化部署,自動化測試等等都缺一不可。拿自動化測試舉例,與傳統(tǒng)架構(gòu)相比,你的測試場景會更加復(fù)雜,甚至就連程序主路徑這一個方面都要比原來負責(zé)很多,因此測試就顯得至關(guān)重要了。
我應(yīng)該從哪兒開始呢?
跟前面講的一樣,我們始終建議在完全透徹的理解業(yè)務(wù)背景的前提下再嘗試使用微服務(wù)。在一個嶄新的項目上,始終建議從一個單塊架構(gòu)開始,因為你不可避免的會犯一些邊界劃分的錯誤,除非你真的是對于這個領(lǐng)域爛熟于胸,倒背如流。在開始的單塊架構(gòu)中,你依然可以讓代碼保持整潔清晰,有完整的測試覆蓋。實施微服務(wù)的時候所面臨的一個最大問題是,大家容易把它用錯了,導(dǎo)致大量沒有必要的反復(fù)更改,從這個意義上來講,從一個單件開始不失為一種較為安全的選擇。
微服務(wù)是一把尚方寶劍嗎?
我們說它并不是。我們確實見證了不少使用微服務(wù)架構(gòu)的成功案例,但是就微服務(wù)本身還是有很多問題需要考慮。比如我之前提到的最終一致性的問題,錯誤的排列組合問題等。這些問題也并不是我們就完全不知道怎么解決,我們知道怎么管理開發(fā)流程,我們知道該怎么溝通,只是在微服務(wù)中要稍微復(fù)雜一些而已。但是面對這些問題的時候,不要害怕做出修改。你完全可以重新設(shè)計某些部分。我們有嚴格的接口協(xié)議,全面的接口測試覆蓋,來保證你在修改業(yè)務(wù)流程、引入新功能、新的校驗方式時更加從容。事實上這些東西也確實容易朝秦暮楚,現(xiàn)在只要誰在社交媒體上秀了個新功能,馬上大家一窩蜂的都想要這個新功能了。用戶的期待就是改變的這么快,業(yè)務(wù)生命周期也越來越短,安全相關(guān)的問題也是日新月異,所有這些變更都驅(qū)使著我們必須快速的適應(yīng)變化,而微服務(wù)便是在這樣的大環(huán)境下應(yīng)運而生的,但是微服務(wù)并不是免費的蛋糕,也有其自身的成本消耗。
最后給大家推薦一本關(guān)于微服務(wù)的書,是的你沒看錯,就是這本《持續(xù)集成》。你可以將微服務(wù)看成我們開將持續(xù)交付的里面引入軟件開發(fā)行業(yè)之后的第一個主要架構(gòu)。在這本書里面你會看到,如果沒有持續(xù)交付,微服務(wù)中所提到的很多東西你根本就不會朝這個方向想,也更不會想這么做。持續(xù)交付和微服務(wù)只有組合在一起才能展現(xiàn)出相互的價值,就像我前面所說的,我們需要喊上運維的同事一起來做這個事情,因為在微服務(wù)中他們的部署方式,監(jiān)控方式都會與之前大不相同。
謝謝各位 ?Rebecca