Java開發微服務入門:微服務認知
翻譯:叩丁狼教育吳嘉俊
1. 介紹
微服務,當今業界最熱門的話題之一,bulingbuling的,每個人,每個公司都想做,但有多少是真正從公司的人和組織結構角度去思考微服務會帶來的變革。
這篇文章中,我們會從核心的原理,到準備實際操作的這個流程來討論微服務架構。但是,這是一個每天都發生著大量創新的領域,所以,在這篇文章中將要討論的所有內容,都是現在發生的實踐,這些實踐,是否在未來還有用,我們需要謹慎的去看待。無論好壞,業界仍在圍繞開發和操作微服務不斷的在實踐中前進。
雖然對於如何正確的實施微服務有非常多的方法方式,但是真相卻是:沒有一條真正統一,有效的路讓你萬無一失。微服務化是持續學習和改進的過程,同時又需要儘可能控制住系統複雜度。不要把本文中所討論的問題和答案看做理所當然,請保持開放的心態,並對新的挑戰做好應對即可。
2. 我們身邊的單塊應用(monolith)
曾幾何時,傳統的單層架構和C/S架構(薄客戶端/富服務端)是搭建所有應用和平臺的首選方案。公平的說,對於大部分的應用,他們確實工作的很好(並且現在仍然工作的很好),但是突然有一天,微服務架構出現了,瞬間給所有的這些架構貼上了可怕的標籤,許多人將他們視為老古董。
圍繞技術的過度宣傳會擾亂基本的常識,微服務就是一個典型的例子。單塊應用並沒有什麼問題,並且目前仍然有不少成功的單塊應用在正常的執行著。然後,確實單塊應用會有一些限制需要我們去改進,我們就從單塊應用的幾個核心問題作為入手點,來看看為什麼會選擇採用微服務架構。
不管你是否認可,在很多公司裡面,單塊應用就是一個龐然大物。維護費用非常高,大量的bug增加了迴歸測試次數,降低產品質量,同時,新需求又需要耗費時間開發,導致整體專案難以按時交付。這就是一個很好的時機,回過頭分析到底什麼地方出了問題,應該怎麼改進。在大多數情況下,把獨立的程式碼庫,直接分解成一組相對獨立的模組或者元件,通過建立適當的API(不必改變模型打包方式),可能是最簡單和最便宜的解決方案。
但是,你經常會遇到可伸縮性問題,包括軟體平臺的伸縮和工程組織的伸縮性,在面對單塊應用架構的時候,非常難以解決。對於這點,經典的康威法則(Conway’s law)總結的非常到位。
“設計系統的組織,其產生的設計等同於組織之內、組織之間的溝通結構” –http://www.melconway.com/Home/Committees_Paper.html
是否微服務就是隧道盡頭的明燈麼?這完全是可能的,但是,你必須做好改變你以前遵循的工程組織和開發實踐。當然,這將是一次顛簸的旅程,但是應該在早期強調,在本文中,我們不會質疑微服務架構(並將您推向微服務),而是假設您已經做了研究,並且強烈相信微服務就是尋找的答案。
3. 擁抱微服務架構
那麼,“微服務”和“微服務架構”到底是什麼意思?您可能會發現有很多不同的存在細微差別的定義,但是最完整、最容易理解的定義還是由Martin Fowlerin在他的關於微服務體系結構的文章中給出的:
簡而言之,微服務架構風格,就像是把一個單獨的應用程式開發為一套小服務,每個小服務執行在自己的程序中,並使用輕量級機制通訊,通常是 HTTP API。這些服務圍繞業務能力來構建,並通過完全自動化部署機制來獨立部署。這些服務使用不同的程式語言書寫,以及不同資料儲存技術,並保持最低限度的集中式管理。– https://www.martinfowler.com/articles/microservices.html
微服務的字首”微“常常會讓人產生迷惑,到底這個”微“應該是多大才合適?當然,這個很難有一個確切的度量。一個比較靠譜的度量方式就是,每一個服務都應該針對一個明確可行的目標。另一種比較有爭議的對”微”的範圍定義是:一個微服務必須足夠的小,讓一個程式設計師(更正式的表述:服務的維護者)能完整的理解。
有兩條基本的路線讓你能夠更快速的擁抱微服務:要麼直接按照微服務架構開始一個新的專案,要麼著手修改一個單塊應用的架構。為了更好的實施微服務,有一些基本的先決條件和原則需要遵守。
首先,微服務必須基於正確的領域模型設計。有兩本這方面的書值得大家閱讀:[The Domain-Driven Design: Tackling Complexity in the Heart of Software]和 [Implementing Domain-Driven Design],這兩本書是關於DDD的最靠譜的兩本書。如果你對你的領域模型瞭解的還不夠深刻,我建議你先不要著急開啟微服務的大門。
良好的領域模型設計,這一點的重要性很快就會變得清晰起來,但是當您從頭開始開發應用程式時,由於未知因素較多,所以在具體實施過程中,還是會遇到很多困難。
3.1 細化架構
總體來看,微服務架構定義瞭如何將你的應用以一組服務的形式組織管理,但是並沒有具體規定服務怎麼實現,以及服務之間應該怎麼通訊等更細節的結構。從某種意義上來說,微服務架構應該被看做一種超級(高層次)架構。
因此,至於單個微服務內部的架構選擇,可以是多種多樣的,比如ports and adapters(https://staging.cockburn.us/hexagonal-architecture/),cleanarchitecture(https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html),onionarchitecture(https://jeffreypalermo.com/2008/07/the-onion-architecture-part-1/),或者老式的分層架構,都是可以使用的。
3.2 有界上下文(Bounded Context)
有界上下文的概念來自於領域模型驅動的概念。當應用到微服務架構時,它概述了每個微服務負責的業務子域的邊界。有界上下文成為微服務的基礎契約,也是微服務對外部系統的邊界。
整個應用的業務領域模型由該系統中所有微服務的領域模型組成,這些領域模型之間由有界的上下文將它們粘在一起。顯然,如果業務領域沒有很好地定義和分解,那麼它們前面的領域模型、有界上下文和微服務也是如此。
3.3 所有權(Ownership)
每一個微服務必須作為它管理的領域模型的唯一來源,包括該領域的資料。特別重要的,在微服務架構中,每個服務必須切斷和其他資料共享的誘惑,比如直接從資料儲存源中讀取其他服務的資料,等繞過微服務契約建立的額外聯絡。
但是,在真實系統中,沒有絕對的獨立應用,所以必須要找到一個處理方法。實際上,資料共享並不是唯一的選擇,你可能立刻會遇到將部分資料冗餘化的需求,接下來,還要找到一個方案提供資料的同步。
你將要做的每個實現都應該被分解為多個部分,並明確地放在正確的微服務(或一組微服務)中。
從組織的角度來看,所有權轉化為為每個微服務(或者一些微服務)提供一個獨立的跨職能團隊。跨職能是實現成熟和最終責任的重要一步:你建立它,你部署它,你執行它,你支援它(或者簡單說:你構建,你運維)。
3.4 獨立部署
每一個微服務必須和其他服務保持獨立:不僅僅是在開發階段,也包括部署階段。部署的分離,並且更重要的,獨立擴充套件的能力,是微服務架構最重要的力量。將微服務視為自治單元,基本上與平臺和基礎設施無關,隨時隨地都可以部署。
3.5 版本控制
獨立的另一方面,意味著每一個微服務應該有自己的生命週期和版本控制。這次,在討論控制權的同時,我們還要考慮合作。在任何一個鬆耦合的分散式系統中,契約是非常容易被打破。契約的修改,必須及時有效的在相關的團隊中進行溝通,以便讓所有人都知道即將到來的改變是什麼,應該怎麼應對。
保持向前和向後相容的能力,是微服務架構中必須處理的事情。這是另一種責任:不僅僅要保證新版本能夠順利的升級和執行,還要保證目前現有的微服務客戶端能完美的繼續執行。
3.6 正確的工具
微服務架構真正的擁抱“選擇正確的工具來工作”的哲學,在選擇開發語言,框架,庫的時候,不再統一固定。不同的微服務面對不同的需求,應該選擇更合適的工具來完成,而不同實現技術棧之間,也能通過微服務間有效的溝通,輕鬆的整合到一起。
4. 單塊應用分散式化的危險
公平的講,微服務架構在提供了很多優秀特性的同時,也引入了很多複雜的問題。毫無疑問,選擇的開發語言或者框架,會更加放大這些複雜性。
當選擇採用微服務之後,很多團隊陷入了仍然採用過去一樣的組織結構和開發過程;到最後,更可能得到的不是一個微服務架構應用,而是一個分散式的單塊應用,這對於開發者和組織者都是一個噩夢。下面我們就這個問題再多談一些。
4.1 每個方法都是遠端呼叫
由於每個微服務都位於一個單獨的程序中,所以每個函式呼叫都可能導致上游微服務間的網路請求風暴。這個問題通過程式碼去檢查比較困難,要處理這個問題,需要從架構的第一天就做好準備。網路呼叫的消耗成本很高,而且所有的網路呼叫都可能出現意想不到的錯誤,讓應用有一萬種失敗的方式。
4.2 通訊量
大多數情況下,一個微服務往往需要和上游的幾個微服務進行溝通,這非常正常,也符合預期。但是,當一個微服務需要呼叫大量的其他微服務,或者一個微服務會發出大量的呼叫請求以完成任務,這就是一個顯然的服務劃分錯誤的標誌。服務間高頻的通訊不僅會受到網路延遲和故障的影響,還會讓出現無效的中介器和代理;
4.3 迴圈依賴
服務間通訊的極端版本,就是兩個微服務間的迴圈通訊,不管是直接的還是間接的。迴圈依賴常常不那麼明顯,但是確實是洪水猛獸。即使您找到了神奇的順序,將這些相互依賴的微服務部署到生產環境中,遲早它們也會使應用程式屈服。
4.4 共享
有太多開發者總結的最佳實踐和模式,又要遵守DRY原則和程式碼重用原則,導致如何抽取和管理微服務之間的共同基礎程式碼是特別困難的事情。
實際上,我們知道的程式碼重複(特別是廣為人知的Ctrl+C/Ctrl+V程式設計大法)必須在開發中儘量避免。然而,在微服務架構的上下文中,不同微服務之間的共享程式碼反而會引入最高級別的程式碼耦合。
但是,在實際開發中,要做到不在微服務間共享程式碼或者庫,特別是當各個微服務使用相同的程式碼或平臺開發的時候,其實是很難的。在這種情況下,如果將共享的程式碼/庫減少到最小甚至是沒有,絕對是一門值得追求的藝術。否則,這種共享將會拖累應用,最後變成分散式的單塊應用。
5. 小結
在這篇文章中,我們非常概要的介紹了微服務架構,它帶來的優勢,它引入的複雜度和對工程組織結構的顯著改變。這種架構帶來了大量的機會,但是另一方面,可能產生錯誤的概率也非常高。
原文:https://www.javacodegeeks.com/2018/07/microservices-for-java-developers-introduction.html