DDD、微服務架構 實踐失敗的12個原因

DDD、微服務架構 實踐失敗的12個原因

在過去的幾年中,我已經對處於數字化轉型過程中的多個產品團隊進行了架構審查。大多數團隊都在按照微服務架構構建產品。他們有使用基於微服務的體系結構的所有正確意圖-更快的開發,更好的可伸縮性,更小的獨立團隊,獨立的部署,使用正確的技術來完成工作,等等。但是,我經常發現團隊在微服務方面苦苦掙扎。他們未能充分利用微服務的優勢。在這篇文章中,我將分享我認為團隊在微服務方面苦苦掙扎的原因。 微服務架構風格是一種將單個整體應用程序開發為一組小服務的方法,每個小服務都在自己的進程中運行並與輕量級機制(通常是HTTP資源API)進行通信。這些服務圍繞業務功能構建,並且可以由全自動部署機制獨立部署。這些服務的集中管理幾乎沒有,它可以用不同的編程語言編寫並使用不同的數據存儲技術。


原因1:管理層低估了開發微服務的複雜性

我曾與多個對微服務非常看好的客戶一起工作。對他們來說,微服務是解決所有問題的靈丹妙藥。在討論中,我發現大多數團隊及其管理層低估了微服務開發的複雜性。 要開發微服務,開發人員需要高效的本地環境設置。 隨著系統中服務的增加,越來越難在一臺計算機上運行應用程序的子集。當您使用消耗相對較多內存的語言(例如Java)構建應用程序時,尤其會發生這種情況。 以下是與本地開發設置有關的要點。

  1. 本地開發的第一個重要方面是好的開發機器。我發現大多數組織都很難使用所有最新和最先進的技術,但是他們不想替換性能低下的Windows開發機器。開發人員受其開發機器的限制。我已經看到開發人員使用VDI映像或配置較差的機器來構建基於微服務的系統。這降低了他們的生產力,他們無法完全應用自己。使用性能不佳的開發機器的副作用是開發人員無法獲得快速反饋。如果您知道必須等待幾分鐘才能運行集成測試套件,那麼您寧願不編寫更多內容也不會增加工作量。不良的開發機器會導致不良的開發實踐。
  2. 一旦有了合理的機器開發人員就可以工作。接下來的事情是確保所有服務都使用構建工具。應該能夠在無需太多配置的情況下在一臺新計算機上構建整個應用程序。以我在微服務方面的經驗,使用一個root構建腳本來構建整個應用程序是有幫助的。
  3. 下一個重點是使開發人員能夠輕鬆地在系統上運行應用程序的某些部分。您應該使用多個docker-compose文件在配置了所有端口和卷的情況下啟動不同的服務。
  4. 接下來,如果您使用的是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:將共享服務用於本地開發

由於本地開發環境不佳,大多數團隊開始依靠共享環境提供關鍵服務。開發人員機器中的第一件共享就是數據庫。大多數年輕的開發人員都沒有意識到基於共享數據庫的開發是邪惡的。以下是我在共享數據庫中遇到的主要問題:

  1. 團隊成員必須建立工作的社會契約,以避免最後的寫入勝出問題。開發人員可以清除另一位開發人員為其工作編寫的數據。這種工作方式既痛苦又容易失敗。遲早這會咬傷團隊。
  2. 開發人員擔心實驗會影響他們的其他團隊成員。我們都知道,更好的學習方法是實驗和快速反饋。有了共享數據庫,就可以進行實驗了。我們需要進行實驗以提出數據庫架構並執行性能調整之類的任務。
  3. 另一個副作用是很難單獨測試更改。您的集成測試變得不穩定。從而進一步降低了顯影速度。
  4. 共享數據庫必須像寵物一樣對待,因為您不希望共享數據庫具有不一致且不可預測的狀態。您可能有一個開發人員想要在表為空但其他人需要表具有記錄的情況下測試邊緣情況。
  5. 僅共享數據庫具有系統正常工作所需的所有數據。隨著時間的流逝,團隊成員失去了更改的可追溯性,因此沒人知道他們如何在計算機上覆制相同的設置。唯一的方法是獲取完整的數據庫轉儲並使用它。
  6. 未連接到網絡時很難工作。通勤時間長或乘飛機時,通常會發生這種情況。

數據庫只是共享服務的一個示例,但它也可以是消息傳遞隊列,像Redis這樣的集中式緩存或服務可以改變的任何其他服務。 解決此問題的最佳方法是使開發人員可以輕鬆地在其本地計算機上運行數據庫(作為docker容器),並投資創建SQL腳本來設置架構和初始主數據。這些SQL腳本應保留在版本控制中,並像其他任何代碼一樣進行維護。


原因4:版本控制託管平臺缺乏可見性

一個版本控制系統中具有1000多個存儲庫。他們正在使用Gitlab版本控制平臺。他們有5個產品,每個產品都由多個微服務組成。我問他們的第一個問題是幫助我們瞭解哪些服務及其各自的代碼存儲庫是產品A的一部分。他們的首席架構師不得不花一天的時間弄清楚構成產品A的所有存儲庫。不知道她是否涵蓋了所有服務。 解決此問題的最佳方法是從一開始就以某種方式對微服務進行分組,以使您始終對產品生態系統具有可見性。Gitlab提供了一種創建組,然後在其中創建項目存儲庫的方法。Github沒有組功能,因此您可以使用主題或命名約定來實現它。


原因5:沒有明確的服務定義

大多數團隊都不知道應該將什麼視為服務。關於實際上構成單個微服務的東西有很多困惑和困惑。 讓我們舉一個例子,您的應用程序具有類似於插件的架構,您將在其中與多個第三方服務集成。每個集成都應該是微服務嗎?我已經看到多個團隊正在為每個集成創建一個微服務。隨著集成數量的增加,這很快變得難以管理。這些服務通常太小,以至於它們作為單獨的進程運行會增加更多的開銷。 我認為擁有少量大型服務總比擁有太多小型服務好。我將首先創建一個對業務組織中整個部門建模的服務。這也符合DDD。我將一個域分為子域和有界上下文。有界上下文表示公司內部的部門,例如財務和市場營銷。您可能認為這可能會導致大型微服務,這是正確的。但是,以我的經驗來看,將單體重構為微服務總是比反之容易。隨著您獲得更多的知識,您可以轉向代表較小關注點的細粒度微服務。您可以應用“單一責任原則”來了解您的微服務是否變得太大而做太多的事情。然後,您可以將其分解為較小的獨立服務。任何服務都不應直接與另一個服務的數據庫對話。他們只能通過已發佈的服務合同進行溝通。 我也遵循後端文檔中提到的建議。該建議可以幫助限制服務之間的服務通信,這是基於微服務的系統性能低下的首要原因。 如果兩條信息相互依賴,則它們應屬於一臺服務器。換句話說,服務的自然邊界應該是其數據的自然邊界。


原因6:沒有明確的代碼重用策略

我正在與一個客戶一起工作,該客戶已在其所有基於Java的微服務中複製了四個與特定問題相關的Java文件。因此,如果在該代碼中發現錯誤,則需要將其應用到所有地方。我們都知道,在時間壓力下,我們會錯過將更改應用於一項或多項服務的機會。這將浪費更多時間並增加挫敗感。 不是說開發團隊不知道正確的事情。但是,組織的結構化方式人們總是默認使用簡單且容易出錯的做事方式。 正確的方法是使用工件管理器(如Bintray或Nexus)並在其中發佈依賴項。然後,每個微服務都應依賴該庫。您需要構建工具,以便在發佈新版本的庫時,應更新並重新部署所有微服務。 使用微服務並不意味著您不應使用迄今為止對我們有用的最佳實踐。您需要在工具上進行投資,以使其易於升級微服務。 在沒有適當工具和自動化的情況下使用微服務是災難的根源。


原因7:多種語言編程

我碰到了使用多種編程語言,多個數據庫,多個緩存的團隊,這是工作的最佳工具。所有這些都在項目的初始階段起作用,但是當您的產品投入生產時,這些選擇就開始顯示出它們的真實色彩。諸如我們在構建Java Spring Boot應用程序之類的原因,但我們意識到Java消耗了更多的內存,並且性能很差,因此我們決定切換到Node.js。在上一個任務中,我向團隊解釋說他們的推理能力很弱。

  1. Node.js的性能優於Java。如果您有基於IO的工作負載,則Node.js通常會表現更好。Java 在任何計算密集型工作負載上均勝過 node.js。通過使用響應式範例,Java for IO工作負載可以具有更好的性能。Spring Boot Reactor在IO工作負載方面的性能與Node.js 相當。
  2. Node.js消耗的內存少於Java。這部分是正確的,因為Node.js應用程序通常使用的內存少於Java。Java Spring Boot應用程序並不像大多數人想象的那樣糟糕。我在其中一個Spring Boot Java Microservice上進行了負載測試,並且內存消耗仍然少於1 GB。您可以通過OpenJ9 JVM,限制對類路徑的依賴性以及通過調整默認JVM參數來優化Java內存利用率。另外,Java中的Spring Boot也有其他替代方法,例如Micronaut和Quarkus,它們消耗的內存等於Node.js。
  3. Node.js比Java更高效。這取決於開發人員編寫代碼。帶有靜態類型和靜態分析工具的Java可以幫助在開發生命週期的早期發現問題。

大多數時候,這全都取決於上下文。如果您的開發人員不成熟,則無論使用哪種編程語言,您都將開發出不良的產品。 我建議組織發佈團隊可以使用的語言列表。我認為2–3是個好數字。另外,列出為什麼應使用一種語言代替另一種語言的原因。 選擇語言之前,應考慮以下多種原因:

  1. 輕鬆找到成熟的企業軟件開發人員有多容易?
  2. 重新培訓開發人員使用新技術有多容易?我們發現Java開發人員可以相對輕鬆地學習Golang。
  3. 最初團隊之外的開發人員可以多麼容易地貢獻,傳輸和維護他人編寫的代碼?
  4. 就工具和庫而言,生態系統的成熟程度如何?

這不僅限於編程語言。這也適用於數據庫。如果您的系統中已經有MongoDB,那麼為什麼要在生態系統中使用ArangoDB?它們都主要是文檔數據庫。 始終考慮使用多種技術的維護和操作方面。


原因8:人們依賴性

這並非特定於微服務,但在微服務生態系統中變得更加普遍。原因是大多數團隊專注於他們的特定服務,因此他們不瞭解完整的生態系統。在與不同客戶的合作中,我發現只有一小部分了解整體情況的建築師。但是,這些架構師的問題在於他們在日常活動中不活躍,因此對開發的影響有限。 我認為最好的辦法是確保所有團隊在架構小組中只有一個代表部分,以便他們可以使團隊與整體架構團隊的路線圖和目標保持一致。要成為一個成熟的組織,您需要投資建立輕量級的治理。


原因9:缺少文檔

過去幾年中與我們互動的大多數組織都在文檔方面苦苦掙扎。大多數開發人員和架構師要麼不編寫文檔,要麼他們編寫的文檔沒有用。即使他們想寫,他們也不知道應該如何記錄其體系結構。 至少我們應該記錄以下內容:

  1. 設計文件
  2. C4模型中的上下文和容器圖
  3. 以架構決策記錄的形式跟蹤關鍵架構決策
  4. 開發人員入門指南

我建議所有文檔都保留在版本控制系統中。


原因10:功能超過平臺成熟度

我在其他方面簡要地談到了這個原因,但是我認為值得一提的是頂級原因。微服務比傳統的單片單體應用程序更為複雜,因為您正在構建具有許多活動部件的分佈式系統。大多數開發人員尚未理解系統的不同故障模式。大多數微服務在構建時都考慮了一條愉快的路。因此,如果您的管理層只想早於專注於功能,那麼您將失敗。在弱平臺上構建的功能無法帶來價值。 組織需要進入平臺心態。平臺心態不僅意味著使用容器和Kubernetes。它們是解決方案的一部分,但本身並不是完整的解決方案。您需要考慮分佈式跟蹤,可觀察性,混亂測試,函數調用與網絡調用,服務間通信的安全服務,可調試性等。這需要大量的精力和投資來建立合適的平臺和工具團隊。 如果您是一家資源有限的初創公司,我的建議是重新考慮您的微服務策略。請了解您正在進入什麼。


原因11:缺乏自動化測試

大多數團隊都知道自動化測試對產品的整體質量有多重要,但他們仍然沒有做到。微服務架構為在何處以及如何進行測試提供了更多選擇。如果您不進行全面的自動化測試,那麼您將嚴重失敗。


原因12:您甚至無法構建結構良好的單體架構。

這條就不多說了。


微信掃描下方二維碼(手機端可以長按兩次),添加小助理就能領取(價值2180)Java架構班之BATJ企業面試課。

同時進入架構精進微信群(技術交流,技術課程分享)。


DDD、微服務架構 實踐失敗的12個原因



分享到:


相關文章: