在本指南中,您將了解什麼是 Java 微服務以及如何設計和創建它們。它還涵蓋了有關 Java 微服務庫以及使用微服務的可行性的問題。《Java微服務:實用指南》的翻譯與改編。
Java 微服務:基礎知識
要理解微服務,您必須先定義它們不是什麼。它不是一個「整體」 - Java 整體:它是什麼以及它的優點或缺點是什麼?什麼是 Java 整體架構?
想像一下您在一家銀行或一家金融科技新創公司工作。您為用戶提供一個行動應用程序,他們可以用它來開設新的銀行帳戶。在 Java 程式碼中,這將導致控制器類別的出現。簡化後,它看起來像這樣:@Controller
class BankController {
@PostMapping("/users/register")
public void register(RegistrationForm form) {
validate(form);
riskCheck(form);
openBankAccount(form);
// etc..
}
}
您需要控制器來:
- 確認報名表。
- 檢查用戶地址的風險,以決定是否向其提供銀行帳戶。
- 開設了銀行帳戶。
BankController
將與其餘來源一起打包到bank.jar 或bank.war 檔案中進行部署——這是一個很好的舊整體,包含運行銀行所需的所有程式碼。粗略估計,.jar(或.war)檔案的初始大小範圍為 1 到 100 MB。現在您只需在伺服器上執行 .jar 檔案...這就是部署 Java 應用程式所需要做的全部工作。 圖片,左上角矩形:部署單一(單片)銀行 java -jar Bank.jar(cp .war/.ear 到 appserver)。右側矩形:開啟瀏覽器。
Java 單體應用有什麼問題?
Java 單體並沒有本質上的錯誤。然而,經驗表明,如果在您的專案中:- 有很多程式設計師/團隊/顧問在工作...
- ....在來自需求非常模糊的客戶的壓力下,在同一個整體上...
- 幾年之內...
如何減小 Java 整體的大小?
一個自然的問題出現了:如何讓整體變得更小?現在您的bank.jar 正在一個JVM 上運行,即一台伺服器上的一個進程。不多也不少。現在你可能會想到一個邏輯想法:“但是風險驗證服務可以被我公司的其他部門使用!” 它與我的整體銀行應用程式沒有直接關係!也許它應該從整體中分離出來並作為單獨的產品部署?也就是說,從技術上講,將其作為單獨的 Java 進程運行。”什麼是 Java 微服務?
實際上,這句話意味著現在riskCheck()
不再從 BankController 進行方法呼叫:該方法或 bean 元件及其所有輔助類別將移至其自己的 Maven 或 Gradle 專案。它也將獨立於銀行整體進行部署和置於版本控制之下。但是,整個提取過程不會將新的 RiskCheck 模組本身轉變為微服務,因為微服務的定義可以解釋。這導致團隊和公司內部頻繁討論。
- 一個專案中有 5-7 個類別是微型專案還是什麼?
- 100 或 1000 堂課…還是微課?
- 微服務一般和類別的數量有沒有關係?
- 我們將所有單獨部署的服務稱為微服務,無論其大小或網域邊界為何。
- 我們來思考如何安排服務間的通訊。我們的微服務需要相互溝通的方式。
Java微服務之間如何建立通訊?
一般來說,有兩種選擇——同步和非同步通訊。同步通訊:(HTTP)/REST
通常,微服務之間的同步通訊會透過傳回 XML 或 JSON 的 HTTP 和類似 REST 的服務進行。當然,可能還有其他選擇 - 至少採用Google Protocol Buffers。如果您需要立即回應,最好使用 REST 通訊。在我們的例子中,這正是需要做的,因為在開戶之前需要進行風險驗證。如果沒有風險檢查,就沒有帳戶。我們將在「哪些函式庫最適合同步 Java REST 呼叫」部分中討論下面的工具。訊息傳遞 - 非同步通信
非同步微服務通訊通常透過與 JMS 實作交換訊息和/或使用AMQP等協定來完成。我們在這裡寫「通常」是有原因的:假設電子郵件/SMTP 整合的數量不可低估。當您不需要立即回覆時使用它。例如,使用者點擊「立即購買」按鈕,而您又想要產生發票。這個過程當然不應該發生在使用者的購買請求-回應週期內。以下我們將描述哪些工具最適合異步 Java 訊息傳遞。範例:Java 中的 REST API 呼叫
假設我們選擇同步微服務通訊。在這種情況下,我們的 Java 程式碼(我們上面介紹的程式碼)在低層級上將如下所示。(這裡所說的低階是指對於微服務通信,通常會建立客戶端庫來將您從實際的 HTTP 呼叫中抽象化)。@Controller
class BankController {
@Autowired
private HttpClient httpClient;
@PostMapping("/users/register")
public void register(RegistrationForm form) {
validate(form);
httpClient.send(riskRequest, responseHandler());
setupAccount(form);
// etc..
}
}
根據程式碼,很明顯我們現在需要部署兩個 Java(微)服務:Bank 和 RiskCheck。結果,我們將運行兩個 JVM 進程。 這就是開發 Java 微服務專案所需的全部內容:只需建置和部署較小的區塊(.jar 或 .war 檔案),而不是一個整體的區塊。這個問題的答案尚不清楚:我們應該如何將單體應用切割成微服務?這些碎片應該有多小,如何決定正確的尺寸?讓我們檢查。
Java微服務架構
在實踐中,公司以不同的方式開發微服務項目。此方法取決於您是嘗試將現有的整體專案轉變為微服務專案還是從頭開始專案。從整體架構到微服務
最合乎邏輯的想法之一是從現有的整體中提取微服務。請注意,這裡的前綴“micro”實際上並不意味著提取的服務確實很小;情況不一定如此。我們來看看理論背景。想法:將整體分解為微服務
微服務方法可以應用於遺留項目。這就是為什麼:- 大多數情況下,此類項目很難維護/更改/擴展。
- 從開發人員到管理階層,每個人都希望簡化。
- 您擁有(相對)清晰的領域邊界,這意味著您確切地知道您的軟體應該做什麼。
- 因此,將使用者資料(例如姓名、地址、電話號碼)的處理分開到單獨的微服務「帳戶管理」中是合理的。
- 或前面提到的“風險檢查模組”,它檢查用戶的風險級別,可以被許多其他項目甚至公司的部門使用。
- 或以 PDF 格式或透過郵件發送發票的發票模組。
實施一個想法:讓別人去做
上述方法在紙面和類似 UML 的圖表上看起來很棒。然而,一切並沒有那麼簡單。它的實際實施需要認真的技術準備:我們對從整體中提取什麼內容的理解與提取過程本身之間存在巨大差距。大多數企業專案都會達到這樣一個階段:開發人員不敢將 7 年歷史的 Hibernate 版本升級到較新的版本。庫將隨之更新,但確實存在破壞某些內容的危險。那麼這些開發人員現在必須挖掘資料庫事務邊界不明確的古老遺留程式碼並提取定義明確的微服務嗎?通常,這個問題非常複雜,無法在白板上或架構會議上「解決」。 引用 Twitter 開發人員 @simonbrown 的話: 我會一遍又一遍地說…如果人們無法正確建立單體,微服務將無濟於事。 西蒙布朗基於微服務架構的從頭開始項目
對於新的 Java 項目,前一部分中的三個編號點看起來略有不同:- 您從頭開始,因此無需維護任何「包袱」。
- 開發人員希望將來事情變得簡單。
- 問題:您對領域邊界的了解更加模糊:您不知道您的軟體實際上應該做什麼(提示:敏捷;))
技術微服務架構
第一點對於開發人員來說似乎是最明顯的,但也有人強烈反對。Hadi Hariri 建議在 IntelliJ 中進行「提取微服務」重構。儘管下面的範例非常簡化,但不幸的是,在實際專案中觀察到的實現並沒有離它太遠。 微服務出現前@Service
class UserService {
public void register(User user) {
String email = user.getEmail();
String username = email.substring(0, email.indexOf("@"));
// ...
}
}
帶有子串Java微服務
@Service
class UserService {
@Autowired
private HttpClient client;
public void register(User user) {
String email = user.getEmail();
//теперь вызываем substring microservice via http
String username = httpClient.send(substringRequest(email), responseHandler());
// ...
}
}
因此,您實際上是將 Java 方法呼叫包裝在 HTTP 呼叫中,而這樣做的原因並沒有明顯的原因。然而,原因之一是:缺乏經驗並試圖強制採用 Java 微服務方法。建議:不要這樣做。
面向工作流程的微服務架構
下一個常見的方法是將 Java 微服務劃分為基於工作流程的模組。現實生活中的例子:在德國,當您去看(公立)醫生時,他必須在他的醫療 CRM 系統中記錄您的就診情況。為了從保險中獲得付款,他將透過 XML 向中介發送有關您的治療(以及其他患者的治療)的數據。代理程式將查看此 XML 檔案並(簡化):- 將檢查是否收到正確的 XML 檔案。
- 它將檢查程序的合理性:例如,一個一歲的孩子一天內從婦科醫生處接受了三次牙齒清潔程序,看起來有些可疑。
- 將 XML 與其他一些官僚資料結合。
- 將 XML 檔案轉發給保險公司以發起付款。
- 它將結果發送給醫生,向他提供“成功”或“請在有意義時盡快重新發送此錄音”的訊息。
- 是否需要部署六個應用程式來處理一個 XML 檔案?
- 這些微服務真的彼此獨立嗎?它們可以相互獨立部署嗎?有不同的版本和API方案?
- 如果驗證微服務不起作用,可信度微服務會做什麼?系統還能用嗎?
- 這些微服務是否共享同一個資料庫(它們當然需要資料庫表中的一些公共資料),還是每個微服務都有自己的資料庫?
- … 以及更多。
- 您不僅需要部署一個應用程序,而且至少需要部署六個應用程式。
- 您甚至可能需要部署多個資料庫,這取決於您想要進入微服務架構的程度。
- 您需要確保每個系統都在線上並正常運作。
- 您需要確保微服務之間的呼叫真正具有彈性(請參閱如何讓 Java 微服務具有彈性?)。
- 以及此設定所暗示的所有其他內容 - 從本機開發設定到整合測試。
- 如果你不是 Netflix(很可能你不是 Netflix)...
- 除非你有超強的工作技能,當你打開開發環境時,它會導致一個混亂的猴子,扔掉你的生產資料庫,5秒鐘內輕鬆恢復。
- 或者您感覺像 @monzo 並且願意嘗試 1500 個微服務,只是因為您可以。
GO TO FULL VERSION