《微服務(wù)進(jìn)展緩慢的5個難點(diǎn)》中描述了實(shí)施微服務(wù)常見的主要阻礙。本文針對前文提到的5個難點(diǎn)提出了7個步驟。每個步驟分別包含了管理和技術(shù)兩方面的建議。
如果以上5點(diǎn)都讓你膝蓋中箭。那么根據(jù)我個人的經(jīng)驗(yàn),綜合解決微服務(wù)實(shí)施難點(diǎn)的第一步就是:
步驟1:以終為始,先構(gòu)建一個獨(dú)立的敏捷微服務(wù)團(tuán)隊(duì)
我們對微服務(wù)的期待就是:可以獨(dú)立開發(fā)、獨(dú)立部署、獨(dú)立發(fā)布,并且進(jìn)行去中心化的管理。那么,我們就先構(gòu)造一支這樣的團(tuán)隊(duì)。
這個團(tuán)隊(duì)為了達(dá)到上述目標(biāo),會采取各種方法(例如:DevOps、全功能團(tuán)隊(duì))解決阻礙”獨(dú)立開發(fā)、獨(dú)立部署、獨(dú)立發(fā)布和去中心化的問題。而根據(jù)康威定理,系統(tǒng)的架構(gòu)會慢慢向“去中心化”方向發(fā)展。
一定要意識到,這個過程會打破大型系統(tǒng)自上而下的既有流程并采用更有生產(chǎn)力的方式構(gòu)建新的組織結(jié)構(gòu)。你唯一需要做的就是要充分信任團(tuán)隊(duì),把它看做是一個微型的技術(shù)管理創(chuàng)新。不要用老的方式控制團(tuán)隊(duì)的運(yùn)作,這會打擊團(tuán)隊(duì)的士氣。
管理建議:
- 讓微服務(wù)團(tuán)隊(duì)完全脫離之前的工作,專心于微服務(wù)的工作中。如果分心同時(shí)做幾件事,每件事都不會做到最好。
- 給微服務(wù)團(tuán)隊(duì)一些特權(quán),為了滿足“全功能微服務(wù)團(tuán)隊(duì)的”訴求,特事特辦。
- 如果團(tuán)隊(duì)在執(zhí)行的過程出現(xiàn)了依賴,進(jìn)而阻礙了進(jìn)度。則需要把依賴標(biāo)明出來。代碼中的依賴容易看見,但組織中的流程依賴很難發(fā)現(xiàn)。
- 為了避免團(tuán)隊(duì)對外部的“依賴慣性”,讓團(tuán)隊(duì)自己想辦法在內(nèi)部解決依賴。
- 組織流程的改變也是很重要的微服務(wù)架構(gòu)產(chǎn)物,而不僅僅是微服務(wù)代碼或基礎(chǔ)設(shè)施。
技術(shù)建議:
- 為微服務(wù)建立一個全新的代碼庫,而不要從原先的代碼庫上克隆或者復(fù)制,避免和原團(tuán)隊(duì)的開發(fā)依賴。
- 建設(shè)一個獨(dú)立的持續(xù)交付流水線,最好是通過“流水線即代碼技術(shù)”(例如Jenkinsfile)來自動生成流水線。
步驟2:構(gòu)建微服務(wù)的“電梯演講”
成立了微服務(wù)團(tuán)隊(duì)之后,接下來就是要選擇第一個實(shí)現(xiàn)的微服務(wù)。但是“這個微服務(wù)應(yīng)該多大,邊界在哪”是個問題。這不需要進(jìn)行嚴(yán)格的設(shè)計(jì)和反復(fù)的論證,只要發(fā)現(xiàn)當(dāng)前的痛點(diǎn)或者想要完成一個假設(shè)就足夠上路了。讓整個過程變輕,而不是變重。
我的建議是通過“微服務(wù)電梯演講”的方式來定義微服務(wù)。格式可以是:
- (XX微服務(wù))用來
- 在(出現(xiàn)痛點(diǎn)的場景)的情況下
- 解決(解決現(xiàn)有的某個問題)
- 從而(達(dá)到什么樣的效果)
- 提升(微服務(wù)的價(jià)值)
例如:
- (訂單查詢微服務(wù))用來
- 在(訂單查詢數(shù)量快速)的情況下
- 解決(訪問數(shù)量迅速升高導(dǎo)致整體應(yīng)用性能下降的問題)
- 從而(分離了訂單查詢請求)
- 提升(其他功能的性能)
當(dāng)構(gòu)造了微服務(wù)的電梯演講,團(tuán)隊(duì)就可以以此為原則來啟動了。當(dāng)碰到和現(xiàn)有系統(tǒng)沖突的問題,替換幾個詞比較能幫助你做決策。(語言在一定程度上也是具有魔力的)
把“拆分”換成“移除”。例如:“從現(xiàn)有系統(tǒng)中拆分出訂單查詢功能”轉(zhuǎn)變?yōu)?從現(xiàn)有系統(tǒng)中移除訂單查詢功能"。思維方式就從一個團(tuán)隊(duì)負(fù)責(zé)兩個系統(tǒng)變成了兩個團(tuán)隊(duì)負(fù)責(zé)兩個系統(tǒng)。
把“集成”換成“調(diào)用”。例如:“用戶注冊和用戶登錄需要集成”轉(zhuǎn)變?yōu)椤坝脩舻卿浄?wù)需要調(diào)用用戶注冊服務(wù)的信息”。思維方式的轉(zhuǎn)換就把兩個系統(tǒng)的關(guān)系更精確了,從而明確了微服務(wù)之間的關(guān)系和溝通方式。
管理建議:
- 把微服務(wù)的電梯演講打印出來掛到墻上,讓團(tuán)隊(duì)成員銘記于心。這會強(qiáng)化組織對微服務(wù)的邊界認(rèn)識。
- 隨著團(tuán)隊(duì)的反思和學(xué)習(xí),電梯演講有可能會變更,但一定要讓團(tuán)隊(duì)形成共識和一致的意見。
- 不要期望一次就能劃分正確。劃分是一個持續(xù)權(quán)衡取舍的過程。
技術(shù)建議:
- 明確了微服務(wù)的職責(zé)和邊界之后再去看代碼,否則會被代碼的復(fù)雜度影響。
- 領(lǐng)域驅(qū)動設(shè)計(jì)(DDD)可以幫助你更好的劃分微服務(wù)。領(lǐng)域驅(qū)動設(shè)計(jì)很好的遵循了“關(guān)注點(diǎn)分離”(Separation of concerns,SOC)的原則,提出了更成熟、清晰的分層架構(gòu)。
- 不會領(lǐng)域驅(qū)動設(shè)計(jì)(DDD)也沒有關(guān)系。簡單的使用“關(guān)注點(diǎn)分離原則”也可以幫你達(dá)到這一點(diǎn)。例如:從接口中分離出流量較大的接口獨(dú)立部署,把讀數(shù)據(jù)庫和寫數(shù)據(jù)庫的API分開獨(dú)立部署,把靜態(tài)和動態(tài)訪問分離……
步驟3:以最小的代價(jià)發(fā)布出第一個微服務(wù)
要注意兩個關(guān)鍵點(diǎn):一個是“最小的代價(jià)”,另一個是“發(fā)布”(Release)。
正如前文所述,微服務(wù)架構(gòu)本身就決定了微服務(wù)一定是低成本低風(fēng)險(xiǎn)的漸進(jìn)式演進(jìn)。而最大的浪費(fèi)在于:
- 級別/職責(zé)分工明確的組織溝通結(jié)構(gòu)。
- “長時(shí)間,慢反饋”的行動習(xí)慣。
- 先進(jìn)且學(xué)習(xí)成本較高的技術(shù)棧。
因此,“最小的代價(jià)”包含了以下三個方面:
- 最精簡的獨(dú)立敏捷全功能團(tuán)隊(duì)。
- 最快的時(shí)間。
- 代價(jià)最小的技術(shù)棧。
此外,很多微服務(wù)的“愛好者”由于害怕失敗,因此將微服務(wù)技術(shù)始終放在“實(shí)驗(yàn)室”里。要勇于面對失敗,在生產(chǎn)環(huán)境中面對真實(shí)的問題,但要采取一些規(guī)避風(fēng)險(xiǎn)的措施。
管理建議:
- 盡量讓現(xiàn)有微服務(wù)團(tuán)隊(duì)自己學(xué)習(xí)解決問題,成為全功能團(tuán)隊(duì)。如無必要,絕不增添新的人手。
- “扯破嗓子不如甩開膀子”,先動起來,在前進(jìn)中解決問題。
- 先考慮最后如何發(fā)布,根據(jù)發(fā)布流程倒推。
技術(shù)建議:
- 根據(jù)當(dāng)前技術(shù)采用的情況選擇代價(jià)較小的技術(shù)棧。
- 采用動態(tài)特性開關(guān)(Feature Toggle),在發(fā)布后可以在生產(chǎn)環(huán)境動態(tài)的控制微服務(wù)的啟用,降低失敗風(fēng)險(xiǎn)。
- 如果采用了特性開關(guān),一定要設(shè)立刪除特性開關(guān)和對應(yīng)舊代碼的時(shí)間,一般不超過兩個月。否則后面大量的特性開關(guān)會帶來管理成本的提升和代碼的凌亂。
- 由于團(tuán)隊(duì)比較小,功能比較單一,不建議采用分支來構(gòu)建微服務(wù),而應(yīng)該采用單主干方式開發(fā)。
步驟4:取得快速勝利(Quick wins),演示(Showcase)驅(qū)動開發(fā)
剛開始進(jìn)行微服務(wù)改造的時(shí)候一定會是一個試錯的過程。如果目標(biāo)定得太大,會讓團(tuán)隊(duì)倍感壓力,從而士氣低落。而制定每日的短期目標(biāo),贏得快速勝利則會不斷激勵團(tuán)隊(duì)的士氣。通過“設(shè)定當(dāng)天結(jié)束的產(chǎn)出來確定今天需要做什么”是一個非常有效的辦法。
每日演示(Daily Showcase)就是一種推進(jìn)產(chǎn)出的做法。每天向團(tuán)隊(duì)分享今天的工作內(nèi)容,使小組能夠共同學(xué)習(xí)。并且以當(dāng)天或者明天的showcase作為目標(biāo)。每個人showcase的內(nèi)容一般不超過20分鐘,一天的showcase時(shí)間不超過一小時(shí)。可以早上showcase,也可以下班后showcase。
常見的快速勝利目標(biāo)如下:
- 構(gòu)造第一條微服務(wù)流水線。
- 上線第一個微服務(wù)HelloWorld
- 構(gòu)造出第一個微服務(wù)自動化測試。
而以下的目標(biāo)不適合作為快速勝利的目標(biāo):
- 構(gòu)造出微服務(wù)DevOps平臺。
- 完成整個產(chǎn)品的微服務(wù)架構(gòu)拆分。
- 構(gòu)造微服務(wù)自動化運(yùn)維體系。
管理建議:
- 要防止團(tuán)隊(duì)畫大餅,完成好每日和每周的工作目標(biāo)即可。微服務(wù)開發(fā)本身就沒有很長周期。
- 強(qiáng)迫團(tuán)隊(duì)有所產(chǎn)出,這樣才能用關(guān)鍵產(chǎn)出驅(qū)動開發(fā)。產(chǎn)出不一定是代碼或者基礎(chǔ)設(shè)施,一篇總結(jié),或者學(xué)習(xí)的文章分享,甚至是踩過的坑和遇到的問題都可以展示,目的是要打造自治學(xué)習(xí)的團(tuán)隊(duì)。
- 貴在堅(jiān)持,不要計(jì)劃太遠(yuǎn)。超過一個月,就要對目標(biāo)是不是范圍過大進(jìn)行反思。
- 以天為單位拆分任務(wù),超過一天的必須要拆分。無法在一天完成的工作需要拆分出階段性產(chǎn)出。
- 如果能結(jié)對,并且能夠每天交換結(jié)對,showcase不必要。
- 可視化所有任務(wù),用敏捷看板來管理任務(wù)是了解現(xiàn)狀的最好方式。
技術(shù)建議:
- 想辦法讓第一個微服務(wù)盡快發(fā)布到生產(chǎn)環(huán)境,生產(chǎn)是最重要的。
- 完成了HelloWord的發(fā)布,就要考慮如何對發(fā)布流程進(jìn)行改進(jìn)。而不是著急準(zhǔn)備下一個業(yè)務(wù)上線。
步驟5:代碼未動,DevOps先行
微服務(wù)解耦的本質(zhì)是把代碼內(nèi)部的復(fù)雜性通過一些工具轉(zhuǎn)化外部復(fù)雜性。把代碼內(nèi)部的復(fù)雜性分散到各個微服務(wù)中以降低整體復(fù)雜性和架構(gòu)風(fēng)險(xiǎn)。在這個過程中會大量采用DevOps技術(shù)和工具。也可以說,微服務(wù)是DevOps文化和技術(shù)在走到極致的必然結(jié)果。
以J2EE的應(yīng)用為例,以前Web Server + App Server + MiddleWare + Database的傳統(tǒng)架構(gòu)被更多的基礎(chǔ)設(shè)施工具所取代,所需要的編程工作量更小。因?yàn)榛A(chǔ)設(shè)施相對于應(yīng)用代碼來說更加穩(wěn)定,更加利于擴(kuò)展。
我把微服務(wù)的技術(shù)架構(gòu)問題比作“搭臺唱戲”:首先需要建立好微服務(wù)交付和運(yùn)行的平臺,然后讓微服務(wù)上臺“唱戲”。
這個平臺一開始不需要很完善,只需要滿足生產(chǎn)上線的必要要求即可。而在很多企業(yè)里,這個部分是由Ops團(tuán)隊(duì)在交付流程的末尾把關(guān)的。因此,把最后一道關(guān)卡的確認(rèn)工作放到最前面考慮可以減少后期的返工以及不必要的浪費(fèi)。
以前,軟件的開發(fā)和測試過程是分開的。然而,隨著DevOps運(yùn)動和各種自動化運(yùn)維工具的興起,這之間的必要性有所降低,只要有足夠的自動化測試做質(zhì)量保證,就可以很快的將微服務(wù)快速部署和發(fā)布到生產(chǎn)環(huán)境上。
最開始的時(shí)候,哪怕是發(fā)布一個Hello World程序,都表明微服務(wù)的持續(xù)交付和運(yùn)行的平臺已經(jīng)搭建好,微服務(wù)交付流程已經(jīng)打通,這一點(diǎn)是重中之重。
從技術(shù)交付產(chǎn)物來說,DevOps主要交付兩點(diǎn):
- 持續(xù)交付流水線。
- 微服務(wù)運(yùn)行平臺。
為了保證微服務(wù)交付的高效,需要把這二者通過自動化的方式有機(jī)的結(jié)合起來,而不是各為其主。讓開發(fā)和運(yùn)維的矛盾變成“自動化的開發(fā)運(yùn)維矛盾”
此外,DevOps指的不光是一系列技術(shù),更是一種工作方式。從團(tuán)隊(duì)工作方式來說,DevOps要做到:
- 要讓Dev和Ops共同參與決策、設(shè)計(jì)、實(shí)現(xiàn)和維護(hù)。
- 團(tuán)隊(duì)完全獨(dú)立自主,打破對現(xiàn)有流程的依賴。
- 不斷的追求改進(jìn),讓團(tuán)隊(duì)形成改進(jìn)的團(tuán)隊(duì)文化。
管理建議:
- “新程序快速投入生產(chǎn)”能給團(tuán)隊(duì)繼續(xù)前進(jìn)最大的動力。
- 如果你的組織是Dev和Ops分離的組織,先咨詢一下Ops工程師的意見。最好是能夠給微服務(wù)團(tuán)隊(duì)里面配備一名Ops工程師。
- 如果不具備實(shí)施DevOps的條件,微服務(wù)架構(gòu)就要從運(yùn)維側(cè),而不是開發(fā)側(cè)開始進(jìn)行。
技術(shù)建議:
- 微服務(wù)的平臺一開始可以很簡單,以后慢慢增強(qiáng)和擴(kuò)展。但是一定要部署到生產(chǎn)環(huán)境里使用。
- 如果想使用現(xiàn)成的微服務(wù)平臺,可以參考Spring Cloud。
- 微服務(wù)運(yùn)行平臺可以通過灰度發(fā)布技術(shù)在生產(chǎn)環(huán)境并行運(yùn)行。
- 采用灰度發(fā)布技術(shù)在生產(chǎn)環(huán)境中逐步提升微服務(wù)的使用占比。
- 基礎(chǔ)設(shè)施即代碼是DevOps核心實(shí)踐,可以幫助開發(fā)人員迅速在本機(jī)構(gòu)建生產(chǎn)環(huán)境相似的開發(fā)環(huán)境,減少環(huán)境的不一致性。可以采用Docker,Ansible,Vagrant等工具來完成。
- 基礎(chǔ)設(shè)施對微服務(wù)應(yīng)該是透明的。微服務(wù)不應(yīng)該也沒必要知道運(yùn)行環(huán)境的細(xì)節(jié)。只要能夠正常啟動并執(zhí)行業(yè)務(wù)就完成了它的任務(wù)。因此,基礎(chǔ)設(shè)施代碼要和微服務(wù)業(yè)務(wù)代碼分開,且微服務(wù)不應(yīng)該告訴平臺自己如何部署。
- 服務(wù)注冊和發(fā)現(xiàn)是微服務(wù)架構(gòu)的核心部分。consul和Eureka是這方面的佼佼者。
- 部署(Deploy)和發(fā)布(Release)要分開。
步驟6:除了提交代碼和發(fā)布,微服務(wù)平臺一切都應(yīng)當(dāng)自動化
在完成了微服務(wù)的基礎(chǔ)設(shè)施和交付流程之后,就可以開始實(shí)現(xiàn)微服務(wù)的業(yè)務(wù)了。這時(shí)候需要依據(jù)電梯演講劃分出來的微服務(wù)進(jìn)行業(yè)務(wù)邏輯的開發(fā)。在以DevOps的方式工作一段時(shí)間之后,團(tuán)隊(duì)?wèi)?yīng)該養(yǎng)成了一些自動化的習(xí)慣,如果沒有,就應(yīng)該檢查一下自己的自動化程度。最佳的自動化理想的狀態(tài)就是除了代碼提交和發(fā)布,在這之間的每一個流程和環(huán)節(jié)都應(yīng)當(dāng)由自動化的手段來完成。
當(dāng)然,也有不能自動化的部分。根據(jù)我的經(jīng)驗(yàn),不能自動化的原因主要來自于流程管理的制度要求,而非技術(shù)困難。這往往是組織沒有依據(jù)微服務(wù)進(jìn)行流程變革導(dǎo)致的。這時(shí)候需要檢討不能自動化的部分是不是有存在的必要。
另一方面,雖然自動化可以大量縮短微服務(wù)交付時(shí)間,提升微服務(wù)交付效率。但是自動化的同時(shí)需要考慮到安全因素和風(fēng)險(xiǎn),不能顧此失彼。對于生產(chǎn)來說,可用性和安全性是最重要的部分。 關(guān)鍵的自動化:
- 自動化功能性測試(UI/集成/單元/回歸)
- 自動化構(gòu)建
- 自動化部署
- 自動化性能測試
- 自動化安全掃描
管理建議:
- 團(tuán)隊(duì)成員自發(fā)的進(jìn)行自動化的改進(jìn),這會給未來微服務(wù)批量開發(fā)帶來很多益處。
- 不要一開始就追求全面的自動化,自動化需要花費(fèi)一定時(shí)間。根據(jù)團(tuán)隊(duì)的進(jìn)度視情況適度進(jìn)行。
技術(shù)建議:
- 采用TDD的方式開發(fā)不光可以提升質(zhì)量,也完成了測試的自動化。
- 契約測試可以解?耦微服務(wù)提供者和消費(fèi)者的開發(fā)。但是要注意始終保持契約的有效性,一定要先改契約后開發(fā)。
- 注意自動化的安全隱患。機(jī)密信息需要獨(dú)立管理,例如可以采用 Hashicorp Vault 這樣的服務(wù)。
- 關(guān)鍵步驟需要準(zhǔn)備自動、手動兩種方式,必要時(shí)可以干預(yù)自動過程。
- 采用git的hook技術(shù),在代碼push之前就可以完成測試和靜態(tài)檢查,提升CI的成功率。
步驟7:總結(jié)并復(fù)制成功經(jīng)驗(yàn),建立起微服務(wù)交付的節(jié)奏
當(dāng)完成了第一個微服務(wù),不要著急開始進(jìn)行下一個微服務(wù)的開發(fā)。而是需要進(jìn)行一次關(guān)于可復(fù)制經(jīng)驗(yàn)的總結(jié),識別微服務(wù)開發(fā)中的經(jīng)驗(yàn)教訓(xùn)并總結(jié)成可復(fù)制的經(jīng)驗(yàn)和產(chǎn)出。
以下是一些需要總結(jié)出來的關(guān)鍵產(chǎn)出:
- 微服務(wù)開發(fā)到發(fā)布的端到端流程規(guī)范。
- 微服務(wù)開發(fā)的技術(shù)質(zhì)量規(guī)范。
- 團(tuán)隊(duì)合作中堅(jiān)持的最佳實(shí)踐。
- 常見技術(shù)問題總結(jié)。
有了以上的關(guān)鍵產(chǎn)出,就可以對微服務(wù)開發(fā)團(tuán)隊(duì)進(jìn)行擴(kuò)張。這時(shí)候有了微服務(wù)開發(fā)的老司機(jī),帶著剛加入的同事一起開發(fā),風(fēng)險(xiǎn)會相對低很多。
管理建議:
- 剛開始的時(shí)候可以每周舉行一個回顧會議,團(tuán)隊(duì)需要快速的反饋和調(diào)整。
- 不要急于擴(kuò)張團(tuán)隊(duì),要在成功經(jīng)驗(yàn)穩(wěn)定并形成模式之后再快速擴(kuò)充。
- 避免微服務(wù)良好的開發(fā)氛圍被稀釋,剛開始的時(shí)候擴(kuò)充團(tuán)隊(duì)可以慢一點(diǎn)。新老成員的配比不要超過1:1。
- 雖然微服務(wù)平臺趨于穩(wěn)定,但在微服務(wù)沒有上規(guī)模之前,不要讓團(tuán)隊(duì)里缺少Ops成員。
- 注意知識的傳遞和人員的培養(yǎng)。
技術(shù)建議:
- 不要急于在微服務(wù)應(yīng)用規(guī)模不大的時(shí)候形成微服務(wù)模板,這會限制未來微服務(wù)的開發(fā)和擴(kuò)展。
- 在微服務(wù)不成規(guī)模的時(shí)候不要放松對微服務(wù)平臺和交付流程的改進(jìn)。要做到最快的時(shí)間交付和發(fā)布微服務(wù)。
參考書目
- 《微服務(wù)設(shè)計(jì)》是一本有關(guān)微服務(wù)各個方面技術(shù)的綜合參考材料。如果你在實(shí)施微服務(wù)的過程中碰到了問題,它就是一個解決方案的分類匯總。
- 《持續(xù)交付》匯集了很多交付最佳實(shí)踐,當(dāng)你的微服務(wù)實(shí)施碰到阻礙時(shí),里面的建議或許能夠讓你解決當(dāng)前的困境。
- 《領(lǐng)域驅(qū)動設(shè)計(jì)》和《實(shí)現(xiàn)領(lǐng)域驅(qū)動設(shè)計(jì)》為拆分微服務(wù)提供了方法論,當(dāng)團(tuán)隊(duì)之間對于微服務(wù)的拆分有困難的時(shí)候,采用領(lǐng)域驅(qū)動的方法往往會得到更好的效果。·
- 《微服務(wù)那些事兒》是一本快速啟動微服務(wù)的工具和實(shí)踐的總結(jié),能夠幫助微服務(wù)入門者快速跨越門檻。
本文首發(fā)于GitChat,經(jīng)作者(顧宇)同意授權(quán)轉(zhuǎn)發(fā)。轉(zhuǎn)載請聯(lián)系作者或GitChat。