在過去的幾年中,我已經完成了對處于數字化轉型過程中的多個產品團隊的架構審查。 大多數團隊都在按照微服務架構構建產品。 他們有使用基于微服務的體系結構的所有正確意圖-更快的開發,更好的可伸縮性,更小的獨立團隊,獨立的部署,使用正確的技術來完成工作,等等。但是,我經常發現團隊在微服務方面苦苦掙扎。 他們未能充分利用微服務的優勢。 在這篇文章中,我將分享我認為團隊在微服務方面苦苦掙扎的原因。
對于微服務新手,我建議閱讀Martin Fowler的微服務文章。 我喜歡本文中提到的微服務架構定義。
微服務架構風格是一種將單個應用程序開發為一組小型服務的方法,每個小型服務都在自己的進程中運行并與輕量級機制(通常是HTTP資源API)進行通信。 這些服務圍繞業務功能構建,并且可以由全自動部署機制獨立部署。 這些服務的集中管理幾乎沒有,可以用不同的編程語言編寫并使用不同的數據存儲技術。
原因1:管理層低估了開發微服務的復雜性
我曾與多個對微服務非常看好的客戶一起工作。 對他們來說,微服務是解決所有問題的靈丹妙藥。 在討論中,我發現大多數團隊及其管理層低估了微服務開發的復雜性。
要開發微服務,開發人員需要高效的本地環境設置。
隨著系統中服務的增加,變得越來越難在一臺計算機上運行應用程序的子集。 當您使用消耗相對較多內存的語言(例如Java)構建應用程序時,尤其會發生這種情況。
以下是與本地開發設置有關的要點。
· 本地開發的第一個重要方面是好的開發機器。 我發現大多數組織都很難使用所有最新和最先進的技術,但是他們不想替換性能低下的Windows開發機器。 開發人員受其開發機器的限制。 我已經看到開發人員使用VDI映像或配置較差的機器來構建基于微服務的系統。 這降低了他們的生產力,他們無法完全應用自己。 使用劣質的開發機器的副作用是,開發人員無法獲得快速反饋。 如果您知道必須等待幾分鐘才能運行集成測試套件,那么您寧愿不用編寫更多內容也不會增加工作量。 不良的開發機器會導致不良的開發實踐。
· 一旦有了您的開發人員,合理的機器就可以工作。 接下來的事情是確保所有服務都使用構建工具。 您應該能夠在無需太多配置的情況下在一臺新計算機上構建整個應用程序。 以我在微服務方面的經驗,即使使用根構建腳本也可以構建整個應用程序,這很有幫助。
· 下一個重點是使開發人員能夠輕松地在系統上運行應用程序的某些部分。 您應該使用多個docker-compose文件來啟動配置了所有端口和卷的不同服務。
· 接下來,如果您使用的是Kubernetes之類的容器編排工具,則應該投資于Telepresence之類的工具,該工具可以輕松調試Kubernetes集群中的應用程序。
如果組織不了解微服務的開發復雜性,那么團隊速度會隨著時間的推移而下降。
原因2:沒有將庫和工具更新到最新版本的過程
在我的評論中,我發現新平臺已經成為歷史。 團隊無法確保依賴關系保持最新狀態,或者數據庫等工具是否為最新版本。 因此,兩年前開始的現代化工作如今已經有數月的技術債務。
幾年前,許多團隊開始將Spring Cloud Netflix OSS項目用于微服務。 他們使用的是Kubernetes之類的容器編排工具,但由于它們是從Netflix OSS開始的,因此并未使用Kubernetes提供的所有功能。 當Kubernetes內置服務發現時,他們仍將Eureka用作服務發現。 此外,借助Istio這樣的服務網格,您可以擺脫Netflix OSS提供的大多數功能。 這有助于降低復雜性,并將很多交叉問題轉移到平臺上。
要記住的另一點是,要使所有服務的依賴項版本保持同步。 我最近在幫助一個使用Spring Boot構建微服務的客戶。 在過去的兩年中,他們已經構建了20多個Spring Boot服務。 在他們的環境中,他們使用的Spring Boot版本范圍從1.5到2.1。 這意味著當有人設置他們的機器時,他們必須下載多個版本的Spring Boot。 此外,他們缺少自1.5以來在Spring Boot中所做的許多改進。
我們的建議是組織應在積壓的訂單中為這些升級創建技術債務項目。 這些技術債務項目應在架構委員會會議上進行討論并定期解決。 在我的上一個項目中,我們每三個月設置一個星期的沖刺,以將所有依賴項更新到最新版本。
此外,團隊應該花時間在升級工具上,例如數據庫,消息隊列和緩存,以升級到最新版本。
原因3:將共享服務用于本地開發
由于本地開發不佳,大多數團隊開始依靠共享環境提供關鍵服務。 開發人員機器中的第一件事就是數據庫。 大多數年輕的開發人員都沒有意識到基于共享數據庫的開發是邪惡的。 以下是我在共享數據庫中遇到的主要問題:
· 團隊成員必須建立工作的社會契約,以避免最后的作家勝出問題。 開發人員可以清除另一位開發人員為其工作編寫的數據。 這種工作方式既痛苦又容易失敗。 遲早這會咬傷團隊。
· 開發人員擔心實驗會影響他們的其他團隊成員。 我們都知道,更好的學習方法是實驗和快速反饋。 有了共享數據庫,就可以進行實驗了。 我們需要進行實驗以提出數據庫架構并執行性能調整之類的任務。
· 另一個副作用是很難單獨測試更改。 您的集成測試變得不穩定。 從而進一步降低了顯影速度。
· 共享數據庫必須像寵物一樣對待,因為您不希望共享數據庫的狀態不一致且不可預測。 您可能有一個開發人員想要在表為空但其他人需要表具有記錄的情況下測試邊緣情況。
· 僅共享數據庫具有系統正常工作所需的所有數據。 隨著時間的流逝,團隊成員失去了更改的可追溯性,因此沒人知道他們如何復制他們計算機上相同的設置。 唯一的方法是獲取完整的數據庫轉儲并使用它。
· 未連接到網絡時很難工作。 通勤時間長或乘飛機時,通常會發生這種情況。
數據庫只是共享服務的一個示例,但它也可以是消息傳遞隊列,像Redis這樣的集中式緩存或服務可以改變的任何其他服務。
解決此問題的最佳方法是使開發人員可以輕松地在其計算機上運行數據庫(作為docker容器),并投資創建SQL腳本來設置架構和初始主數據。 這些SQL腳本應保留在版本控制中,并像其他任何代碼一樣進行維護。
原因4:版本控制托管平臺缺乏可見性
我正在與一個在其版本控制系統中具有1000多個存儲庫的客戶端一起工作。 他們正在使用Gitlab版本控制平臺。 他們有5個產品,每個產品都由多個微服務組成。 我問他們的第一個問題是幫助我們了解哪些服務及其各自的代碼存儲庫是產品A的一部分。他們的首席架構師不得不花一天的時間弄清楚構成產品A的所有存儲庫。 不知道她是否涵蓋了所有服務。
解決此問題的最佳方法是從一開始就以某種方式對微服務進行分組,以使您始終對產品生態系統具有可見性。 Gitlab提供了一種創建組,然后在其中創建項目存儲庫的方法。 Github沒有組功能,因此您可以使用主題或命名約定來實現它。
我個人更喜歡mono repos,因為我發現它們真的很方便。 我遇到的大多數開發人員都將其視為反模式。 我同意Dan Lua的帖子,他在文章中提到了mono repo的以下好處
*簡化的組織
*簡化的依賴關系
*工具
*跨項目變更
原因5:沒有明確的服務定義
大多數團隊都不知道應該將什么視為服務。 關于實際上構成單個微服務的東西有很多困惑和困惑。 讓我們舉一個例子,您的應用程序具有類似插件的架構,您將在其中與多個第三方服務集成。 每個集成都應該是微服務嗎? 我已經看到多個團隊正在為每個集成創建一個微服務。 隨著集成數量的增加,這很快變得難以管理。 這些服務通常太小,以至于它們作為單獨的進程運行會增加更多的開銷。
我認為擁有少量大型服務總比擁有太多小型服務好。我將首先創建一個對業務組織中整個部門建模的服務。這也符合DDD。我將一個域分為子域和有界上下文。有界上下文表示公司內部的部門,例如財務和市場營銷。您可能認為這可能會導致大型微服務,這是正確的。但是,以我的經驗來看,將單片重構為微服務總是比反之容易。隨著您獲得更多的知識,您可以轉向代表較小關注點的細粒度微服務。您可以應用"單一責任原則"來了解您的微服務是否變得太大而做太多的事情。然后,您可以將其分解為較小的獨立服務。任何服務都不應直接與另一個服務的數據庫對話。他們只能通過已發布的合同進行溝通。您可以閱讀Microservices.io網站上提到的有關按子域模式分解的更多信息。
我也遵循后端文檔中提到的建議。 該建議可以幫助限制服務之間的通信,這是基于微服務的系統性能低下的首要原因。
如果兩條信息相互依賴,則它們應屬于一臺服務器。 換句話說,服務的自然邊界應該是其數據的自然邊界。
原因6:沒有明確的代碼重用策略
我正在與一個客戶一起工作,該客戶已在其所有基于Java的微服務中復制了四個與特定問題相關的Java文件。 因此,如果在該代碼中發現錯誤,則需要將其應用到所有地方。 我們都知道,在時間壓力下,我們會錯過將更改應用于一項或多項服務的機會。 這將浪費更多時間并增加挫敗感。
開發團隊并不了解正確的事情。 但是,組織的結構化方式人們總是默認使用簡單且容易出錯的做事方式。
正確的方法是使用工件管理器(如Bintray或Nexus)并在其中發布依賴項。 然后,每個微服務都應依賴該庫。 您需要構建工具,以便在發布新版本的庫時,應更新并重新部署所有微服務。
使用微服務并不意味著您不應使用迄今為止對我們有用的最佳實踐。 您需要在工具上進行投資,以使其易于升級微服務,從而使人類不必這樣做。
在沒有適當工具和自動化的情況下使用微服務是災難的根源。
原因7:多種語言編程
我找到了使用多種編程語言,多個數據庫,多個緩存的團隊,這是工作的最佳工具。 所有這些都在項目的初始階段起作用,但是當您的產品投入生產時,這些選擇就開始顯示出它們的真實色彩。 諸如我們在構建Java Spring Boot應用程序之類的原因,但我們意識到Java占用了更多內存,并且性能很差,因此我們決定切換到Node.js。 在上一個任務中,我向團隊解釋說他們的推理能力很弱。
· Node.js的性能優于Java。 如果您有基于IO的工作負載,則Node.js通常會表現更好。 Java在任何計算密集型工作負載上均勝過node.js。 通過使用響應式范例,Java for IO工作負載可以具有更好的性能。 Spring Boot Reactor在IO工作負載方面的性能與Node.js相當。
· Node.js消耗的內存少于Java。 這部分是正確的,因為Node.js應用程序通常使用的內存少于Java。 Java Spring Boot應用程序并不像大多數人想象的那樣糟糕。 我在其中一個Spring Boot Java Microservice上進行了負載測試,并且內存消耗仍然少于1 GB。 您可以通過OpenJVM,限制對類路徑的依賴性以及通過調整默認JVM參數來優化Java內存利用率。 另外,Java中的Spring Boot替代品還有Micronaut和Quarkus等,它們消耗的內存等于Node.js。
· Node.js比Java更高效。 這取決于開發人員編寫代碼。 帶有靜態類型和靜態分析工具的Java可以幫助在開發生命周期的早期發現問題。
大多數時候,這全都取決于上下文。 如果您的開發人員不成熟,則無論使用哪種編程語言,您都將開發出不良的產品。
我建議組織發布團隊可以使用的語言列表。 我認為2–3是個好數字。 另外,列出為什么應使用一種語言代替另一種語言的原因。
選擇語言之前,應考慮以下多種原因:
· 輕松找到成熟的企業軟件開發人員有多容易?
· 重新培訓開發人員使用新技術有多容易? 我們發現Java開發人員可以相對輕松地學習Golang。
· 最初團隊之外的開發人員可以多么容易地貢獻,傳輸和維護他人編寫的代碼?
· 就工具和庫而言,生態系統的成熟程度如何?
這不僅限于編程語言。 這也適用于數據庫。 如果您的系統中已經有MongoDB,那么為什么要在生態系統中使用ArangoDB? 它們都主要是文檔數據庫。
始終考慮使用多種技術的維護和操作方面。
原因8:人們依賴性
這并非特定于微服務,但在微服務生態系統中變得更加普遍。 原因是大多數團隊專注于他們的特定服務,因此他們不了解完整的生態系統。 在與不同客戶的合作中,我發現只有一小部分了解整體情況的建筑師。 但是,這些架構師的問題在于他們在日常活動中不活躍,因此對開發的影響有限。
我認為最好的辦法是確保所有團隊在架構小組中只有一個代表性的部分,以便他們可以使團隊與整體架構團隊的路線圖和目標保持一致。 要成為一個成熟的組織,您需要投資建立輕量級的治理。
原因9:缺少文檔
過去幾年中與我們互動的大多數組織都在文檔方面苦苦掙扎。 大多數開發人員和架構師要么不編寫文檔,要么他們編寫的文檔沒有用。 即使他們想寫,他們也不知道應該如何記錄其體系結構。
至少我們應該記錄以下內容:
· 設計文件
· C4模型中的上下文和容器圖
· 以架構決策記錄的形式跟蹤關鍵架構決策
· 開發人員入門指南
我建議所有文檔都保留在版本控制系統中。
原因10:功能超過平臺成熟度
我在其他方面簡要地談到了這個原因,但是我認為值得一提的是它的首要原因。 微服務比傳統的單片應用程序更為復雜,因為您正在構建具有許多活動部件的分布式系統。 大多數開發人員尚未理解系統的不同故障模式。 大多數微服務在構建時都考慮了一條愉快的路。 因此,如果您的管理層只想早于專注于功能,那么您將失敗。 在弱平臺上構建的功能無法帶來價值。
組織需要進入平臺心態。 平臺心態不僅意味著使用容器和Kubernetes。 它們是解決方案的一部分,但本身并不是完整的解決方案。 您需要考慮分布式跟蹤,可觀察性,混亂測試,函數調用與網絡調用,服務到服務通信的安全服務,可調試性等。這需要大量的精力和投資來建立合適的平臺和工具團隊。
如果您是一家資源有限的初創公司,我的建議是重新考慮您的微服務策略。 請了解您正在進入什么。
原因11:缺乏自動化測試
大多數團隊都知道自動化測試對產品的整體質量有多重要,但他們仍然沒有做到。 微服務架構為在何處以及如何進行測試提供了更多選擇。 如果您不進行全面的自動化測試,那么您將嚴重失敗。
關于這一點,我不會寫太多,因為網絡上許多其他人已經討論過這一點。 我從Martin Fowler網站上發布的Microservices測試文章中獲取的下圖討論了基于Microservices的系統的測試金字塔。
Microservices Test Pyramid
-
API
+關注
關注
2文章
1487瀏覽量
61827 -
微服務
+關注
關注
0文章
134瀏覽量
7328
發布評論請先 登錄
相關推薦
評論