微服务开发的 10 个最佳实践
作者 | Md Kamaruzzaman
譯者 | 冬雨
策劃 | 萬佳
隨著軟件系統(tǒng)越來越復(fù)雜,大型的軟件系統(tǒng)變得難于開發(fā)、增強(qiáng)、維護(hù)、現(xiàn)代化和規(guī)模化。為解決這一問題,人們嘗試過模塊化軟件開發(fā)、分層軟件架構(gòu)、SOA。現(xiàn)在,微服務(wù)架構(gòu)成為解決現(xiàn)代軟件應(yīng)用復(fù)雜性的新“利刃”。但正確設(shè)計微服務(wù)架構(gòu)非常具有挑戰(zhàn)性和困難,因此本文作者提出一些最佳實(shí)踐,這些實(shí)踐有助于開發(fā)有效的微服務(wù)應(yīng)用程序。
軟件系統(tǒng)是復(fù)雜的。由于人腦只能處理一定程度內(nèi)的復(fù)雜性,大型軟件系統(tǒng)的高復(fù)雜性導(dǎo)致許多問題。大型復(fù)雜的軟件系統(tǒng)難于開發(fā)、增強(qiáng)、維護(hù)、現(xiàn)代化和規(guī)模化。
多年來,為解決軟件系統(tǒng)的復(fù)雜性做過許多嘗試:
19 世紀(jì) 70 年代,David Parnas 和 Edsger W. Dijkstra 引入模塊化軟件開發(fā),來解決軟件系統(tǒng)的復(fù)雜性;
19 世紀(jì) 90 年代,引入分層軟件架構(gòu)來處理業(yè)務(wù)應(yīng)用程序的復(fù)雜性;
20 世紀(jì)初以來,面向服務(wù)的架構(gòu)(SOA)成為開發(fā)復(fù)雜業(yè)務(wù)應(yīng)用程序的主流。
而微服務(wù)架構(gòu)則是處理現(xiàn)代軟件應(yīng)用復(fù)雜性的最新方法。它將軟件系統(tǒng)分解成可獨(dú)立部署的自治模塊,這些模塊通過輕量級的、語言無關(guān)的方式通信,共同實(shí)現(xiàn)業(yè)務(wù)目標(biāo)。
有人可能會問:為什么我們突然需要一種新的軟件開發(fā)方法?簡單說,與軟件開發(fā)相關(guān)的整個生態(tài)系統(tǒng)在過去十年發(fā)生巨大變化。如今,軟件使用敏捷方法開發(fā),使用 CI/CD 在容器 + 云上部署,在 NoSQL 數(shù)據(jù)庫上持久化,在現(xiàn)代瀏覽器或智能手機(jī)上展現(xiàn),機(jī)器通過高速網(wǎng)絡(luò)連接。這些因素的出現(xiàn)催生出微服務(wù)架構(gòu)。
正確設(shè)計微服務(wù)架構(gòu)非常具有挑戰(zhàn)性和困難。與單體架構(gòu)為所有問題提供一個解決方案相反,微服務(wù)架構(gòu)需要為不同問題提供不同的解決方案。
這里,我提出一些最佳實(shí)踐,這些實(shí)踐將有助于開發(fā)有效的微服務(wù)應(yīng)用程序。在這些應(yīng)用程序中,目標(biāo)項目應(yīng)該存在超過 6 個月的時間,并且團(tuán)隊規(guī)模從中等到大型(6+ 開發(fā)人員)。
?
??
1. 領(lǐng)域驅(qū)動設(shè)計
開發(fā)微服務(wù)的首要挑戰(zhàn)是將大型、復(fù)雜的應(yīng)用程序分割成小型、自主、獨(dú)立的可部署模塊。如果微服務(wù)沒有以正確的方式進(jìn)行分割,將會出現(xiàn)緊耦合的微服務(wù),這些微服務(wù)將具有單體架構(gòu)的所有缺點(diǎn),并具有分布式單體架構(gòu)的所有復(fù)雜性。
幸運(yùn)的是,已經(jīng)有解決方案可以在這方面提供很大幫助。Eric Evans 當(dāng)時是一名軟件工程顧問,他在不同公司的業(yè)務(wù)應(yīng)用程序中遇到了關(guān)于軟件復(fù)雜性的反復(fù)出現(xiàn)的問題,于是在 2004 年出版的《領(lǐng)域驅(qū)動設(shè)計:處理軟件核心的復(fù)雜性》一書中總結(jié)了他的寶貴見解。該書概述了三個核心概念:
軟件開發(fā)團(tuán)隊?wèi)?yīng)該與業(yè)務(wù)部門或領(lǐng)域?qū)<颐芮泻献?#xff1b;
架構(gòu)師 / 開發(fā)人員和領(lǐng)域?qū)<覒?yīng)該首先進(jìn)行戰(zhàn)略設(shè)計:找到有界的上下文和相關(guān)的核心域以及普遍存在的語言、子域、上下文映射;
然后,架構(gòu)師 / 開發(fā)人員應(yīng)該進(jìn)行戰(zhàn)術(shù)設(shè)計,將核心域分解為細(xì)粒度的構(gòu)建塊:實(shí)體、值對象、聚合、聚合根。
領(lǐng)域驅(qū)動設(shè)計的詳細(xì)討論超出了這篇文章的討論范圍,但是你應(yīng)該讀一下起初的 DDD 書籍 Eric Evans 的《領(lǐng)域驅(qū)動設(shè)計:處理復(fù)雜的軟件(藍(lán)皮書)( Domain Driven Design:Tackling Complexity in the Heart of Software ?(Blue Book))》,或者更現(xiàn)代一點(diǎn)兒的 DDD 書籍 ?Vaughn Vernon 的《實(shí)現(xiàn)領(lǐng)域驅(qū)動設(shè)計(紅皮書)( Implementing Domain Driven Design (Red Book))》。
如果將一個大型系統(tǒng)劃分為核心域和子域,然后將核心域和子域映射到一個或多個微服務(wù),那么我們將得到理想的松耦合微服務(wù)。
??
??
2.?每個微服務(wù)一個數(shù)據(jù)庫
在將復(fù)雜的應(yīng)用程序拆分為多個微服務(wù)模塊之后,下一個挑戰(zhàn)出現(xiàn)了,如何處理數(shù)據(jù)庫?我們是否應(yīng)該在微服務(wù)之間共享數(shù)據(jù)庫?這個問題的答案是一把雙刃劍。一方面,在微服務(wù)之間共享數(shù)據(jù)庫將導(dǎo)致微服務(wù)之間的強(qiáng)耦合,這與微服務(wù)架構(gòu)的目標(biāo)正好相反。即使是數(shù)據(jù)庫中的一個小更改也需要團(tuán)隊之間的協(xié)調(diào)同步。
此外,在一個服務(wù)中管理數(shù)據(jù)庫的事務(wù)和鎖就已經(jīng)足夠具有挑戰(zhàn)性了。而在多個分布式微服務(wù)之間管理事務(wù)和鎖更是一項艱巨的任務(wù)。另一方面,如果每個微服務(wù)都有自己的數(shù)據(jù)庫或私有表,那么在微服務(wù)之間交換數(shù)據(jù)就打開了挑戰(zhàn)的潘多拉盒子。因此,許多著名的軟件工程師都提倡在微服務(wù)之間共享數(shù)據(jù)庫,將其作為一種實(shí)用的解決方案。
然而,在我看來,微服務(wù)是關(guān)于可持續(xù)和長期的軟件開發(fā)的。因此,每個微服務(wù)都應(yīng)該有自己的數(shù)據(jù)庫(或者私有表)。
??
??
3. 微前端
不幸的是,大多數(shù)的后端開發(fā)人員對前端開發(fā)有一種過時的看法,認(rèn)為前端開發(fā)很簡單。由于大多數(shù)軟件架構(gòu)師都是后端開發(fā)人員,他們很少關(guān)注前端,而前端在架構(gòu)設(shè)計中往往被忽視。通常在微服務(wù)項目中,后端與它們的數(shù)據(jù)庫被很好地模塊化,但只有一個整體前端。
在最好的情況下,他們考慮用最熱門的單頁面應(yīng)用(React、Angular、Vue)其中之一來開發(fā)獨(dú)體前端。這種方法的主要問題是,前端的單體架構(gòu)和后端單體架構(gòu)一樣糟糕,正如我前一篇文章所述。
另外,當(dāng)前端因?yàn)闉g覽器的變化而需要更新時,它就需要一個大的更新(這就是為什么那么多公司仍然使用過時的 Angular 1 框架的原因)。網(wǎng)絡(luò)是簡單的,但非常強(qiáng)大,并天生提供了穿透力。開發(fā)基于單頁面應(yīng)用的微前端有很多方法:使用 iFrame、Web 組件或借助于(Angular/React)元素。
??
??
4.?持續(xù)交付
微服務(wù)架構(gòu)的關(guān)鍵賣點(diǎn)之一是每個微服務(wù)都可以獨(dú)立部署。如果你有一個系統(tǒng),例如 100 個微服務(wù),并且只需要更改一個微服務(wù),那么你可以只更新一個微服務(wù),而不需要修改其他 99 個微服務(wù)。但是,在沒有自動化的情況下獨(dú)立部署 100 個微服務(wù)(DevOps、CI/CD)是一項艱巨的任務(wù)。
要充分利用微服務(wù)的這一特性,需要 CI/CD 和 DevOps。使用沒有 CI/CD、DevOps 的微服務(wù)架構(gòu),自動化就像購買最新的保時捷,然后用手剎去駕駛它。難怪微服務(wù)專家 Martin Fowler 將 CI/CD 列為使用微服務(wù)架構(gòu)的三個先決條件之一。
?
??
5. 可觀察性
微服務(wù)架構(gòu)的主要缺點(diǎn)之一是,軟件開發(fā)變得簡單,而犧牲了運(yùn)維。使用單體架構(gòu),監(jiān)視應(yīng)用程序要簡單得多。但是許多微服務(wù)在容器上運(yùn)行,整個系統(tǒng)的可觀察性變得非常重要和復(fù)雜。甚至日志記錄也變得很復(fù)雜,要將來自許多容器 / 機(jī)器的日志聚集到一個中心位置。
幸運(yùn)的是,市場上已經(jīng)有很多企業(yè)級的解決方案了。例如,ELK/Splunk 提供微服務(wù)的日志記錄。Prometheus/App Dynamics 提供工業(yè)級監(jiān)控。微服務(wù)世界中另一個非常重要的可觀察性工具是 Tracing。通常,對一個微服務(wù)的一個 API 請求會導(dǎo)致對其他微服務(wù)的幾個級聯(lián)調(diào)用。要分析微服務(wù)系統(tǒng)的延遲,需要測量每個微服務(wù)的延遲。Zipkin/Jaeger 為微服務(wù)提供了出色的跟蹤支持。
?
??
6. 統(tǒng)一技術(shù)棧
微服務(wù)架構(gòu)告訴我們,對于一個微服務(wù),采用最適合該微服務(wù)的編程語言和框架。這種說法不能照字面理解。有時,一個微服務(wù)可能需要一個新的技術(shù)棧,例如 CPU 密集 / 高性能任務(wù),可能會選擇如 c++ /Rust 之類的編程語言。如果微服務(wù)與機(jī)器學(xué)習(xí)一起工作,那么 Python 可能是更好的選擇。
但是在沒有任何理由的情況下使用不同的編程語言 / 框架會導(dǎo)致過多的編程語言和框架而沒有任何實(shí)際的好處。思考這么一個應(yīng)用場景,一個微服務(wù)是使用 Spring Boot + Kotlin+ React + MySQL 開發(fā)的,另一個用的是 JakartaEE + Java + Angular + PostgreSQL,下一個是 Scala + Play Framework + VueJS + Oracle,則需要大量的工作去維持這些不同的編程語言、數(shù)據(jù)庫、框架,而沒有太多的收益。
?
??
7. 異步通信
微服務(wù)架構(gòu)中最具挑戰(zhàn)性的設(shè)計決策之一是服務(wù)之間如何通信和共享數(shù)據(jù)。當(dāng)每個微服務(wù)都有自己的數(shù)據(jù)存儲時,這一點(diǎn)就更為重要了。通常,一個微服務(wù)可以單獨(dú)存在,但是它不能單獨(dú)實(shí)現(xiàn)所有的業(yè)務(wù)目標(biāo)。
所有微服務(wù)為了實(shí)現(xiàn)業(yè)務(wù)目標(biāo)而在一起工作,為了在一起工作,它們需要交換數(shù)據(jù)或觸發(fā)其他微服務(wù)來執(zhí)行任務(wù)。在微服務(wù)之間進(jìn)行通信的最簡單和最常見的方式是通過同步的 REST API,這是一種實(shí)用但臨時的解決方案。如果服務(wù) A 同步調(diào)用服務(wù) B,服務(wù) B 同步調(diào)用服務(wù) C,服務(wù) C 同步調(diào)用服務(wù) D,那么延遲就會增加。
此外,由于微服務(wù)主要是分布式系統(tǒng),它們有可能會失敗。通常,同步微服務(wù)會導(dǎo)致級聯(lián)失敗,即一個服務(wù)的失敗會導(dǎo)致其他服務(wù)的失敗。微服務(wù)之間的同步通信也導(dǎo)致了微服務(wù)之間的緊密耦合。對于長期解決方案,微服務(wù)應(yīng)該異步通信。微服務(wù)之間的異步通信有很多方式:通過消息隊列,例如 Kafka,通過異步的 REST(ATOM)或 CQRS。
?
??
8. 微服務(wù)優(yōu)先
許多專家認(rèn)為,對于新項目,最好從松耦合的單體架構(gòu)開始,因?yàn)槲⒎?wù)架構(gòu)需要大量的初始工作來設(shè)置運(yùn)維。在他們看來,一旦項目變得足夠成熟,“漂亮的”設(shè)計就可以很容易地轉(zhuǎn)化為微服務(wù)。然而,在我看來,這種方法在大多數(shù)情況下都會失敗。
實(shí)際上,實(shí)體內(nèi)部的模塊將是緊耦合的,這將使其很難轉(zhuǎn)換成微服務(wù)。而且,一旦應(yīng)用程序投入生產(chǎn),在不破壞應(yīng)用程序的情況下將其轉(zhuǎn)換為微服務(wù)將變得更加困難。因此,我的建議是,如果最終有使用微服務(wù)架構(gòu)的計劃,那么就從微服務(wù)開始。
?
??
9. 基礎(chǔ)設(shè)施優(yōu)于類庫
在微服務(wù)軟件開發(fā)的早期,Netflix 主要使用 Java 編程來開發(fā)微服務(wù)。他們還開發(fā)了許多類庫(Netflix 的 OSS 棧,包括 Hystrix、Zuul)。許多公司通過 Netflix 跟進(jìn)并開始使用 Netflix OSS。
后來,許多公司(包括 Netflix)發(fā)現(xiàn),Java 實(shí)際上并不是開發(fā)微服務(wù)的語言,因?yàn)樗w積龐大,而且冷啟動問題嚴(yán)重。Netflix 后來轉(zhuǎn)向 Polyglot 微服務(wù)范式,并決定不再進(jìn)一步開發(fā) Netflix OSS,這導(dǎo)致了追隨者公司陷入困境。因此,與其大量投資于特定語言的類庫(如基于 Java 的 Netflix OSS),不如使用框架(如服務(wù)網(wǎng)格、API 網(wǎng)關(guān))。
?
??
10. 組織考慮
大約 50 年前(1967 年),Melvin Conway 觀察到公司的軟件架構(gòu)受到組織結(jié)構(gòu)的限制(Conway 定律)。盡管這一觀察發(fā)現(xiàn)已有 50 年歷史,但麻省理工學(xué)院(MIT)和哈佛商學(xué)院(Harvard Business School)最近發(fā)現(xiàn),這一法則在當(dāng)今仍然有效。如果一個組織計劃開發(fā)微服務(wù)架構(gòu),那么它應(yīng)該使團(tuán)隊規(guī)模更為恰當(dāng)(兩個“美國”比薩團(tuán)隊:7±2 人)。
此外,團(tuán)隊?wèi)?yīng)該是跨職能的,最好有前端 / 后端開發(fā)人員、運(yùn)維工程師和測試人員。微服務(wù)架構(gòu)只有在高層管理者也相應(yīng)地改變他們的觀點(diǎn)和愿景的情況下才能發(fā)揮作用。
有道無術(shù),術(shù)可成;有術(shù)無道,止于術(shù)
歡迎大家關(guān)注Java之道公眾號
好文章,我在看??
總結(jié)
以上是生活随笔為你收集整理的微服务开发的 10 个最佳实践的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: hdu 1087 Super Jum
- 下一篇: hdu 2191 悼念512汶川大地震遇