Java程序员须知:分布式微服务为什么很难?
現(xiàn)在,我們不斷地贊美云原生cloud native架構(容器化和微服務),然而現(xiàn)實是大多數(shù)公司仍然運行單體系統(tǒng)。為什么?這不是因為我們非常不時尚,而是因為分布式是非常困難的。盡管如此,它仍然是創(chuàng)建超大規(guī)模的、真正彈性的和快速響應的系統(tǒng)的唯一途徑,因此我們必須圍繞它進行整合。
image
在這篇文章中,我們將介紹分布式系統(tǒng)中一些障礙以及人們應對方法。
忘記康威定律(Conway’s Law),分布式系統(tǒng)遵循的是墨菲定律:“任何可能出錯的地方都會出錯。
在分布式系統(tǒng)的大規(guī)模上看,統(tǒng)計不是你的朋友(事后諸葛亮)。你所擁有的任何服務器實例越多,其中一個或多個當機的可能性就越高。而且極可能在同一時間。
在你收到警報郵件之前,服務器已經(jīng)當機,網(wǎng)絡將會丟失數(shù)據(jù)包,磁盤將失敗,虛擬機將意外終止。
有一些在單體架構中的保證在分布式系統(tǒng)中就不再會得到保障。組件(現(xiàn)在的服務)不再以可預測的順序啟動和停止。服務可能意外重新啟動,更改其數(shù)據(jù)庫狀態(tài)或版本。結果是,沒有服務可以對另一個服務進行假設 - 系統(tǒng)不依賴于1對1的通信。
許多從故障中恢復的傳統(tǒng)機制可能會使分布式環(huán)境惡化。強力重試可能會使您的網(wǎng)絡被洪水般數(shù)據(jù)包淹沒,備份恢復也并不簡單。過去解決所有這些問題的設計模式,都需要重新思考和測試。
如果沒有錯誤,分布式系統(tǒng)會很容易。樂觀主義會造成對安全的錯覺。分布式系統(tǒng)的設計必須具有彈性,能夠容納接受所有可能的發(fā)生錯誤,而不影響日常業(yè)務。
這里通訊會失敗
在不可靠(即分布式)系統(tǒng)中,傳統(tǒng)應用程序消息傳遞有兩種高級方法:
我們在這里討論的可靠和不可靠的應用級通信與網(wǎng)絡可靠性(例如TCP與UDP)是不同。想象一下,兩個通過TCP直接發(fā)送消息(比如RPC通訊)的無狀態(tài)服務。即使TCP是可靠的網(wǎng)絡協(xié)議,這也不是可靠的應用級通信。任何服務都可能會丟失并丟失正在處理的消息,因為無狀態(tài)服務不能安全地保存正在處理的數(shù)據(jù)。(banq注:這是針對同步的RPC框架,比如國內的Dubbo或谷歌的gRPC)
我們可以通過在每個服務之間放置有狀態(tài)的隊列來使此設置應用程序級別可靠,以保存每個消息,直至其完全處理(banq注:引入消息隊列)。這樣做的不足之處在于它會慢一點,但是我們可能很樂意與之相處,因為如果它使生活更簡單,特別是如果我們使用可管理的有狀態(tài)的隊列服務時,那么我們就不必擔心規(guī)模和彈性問題。
可靠的方法是可預測的,但會涉及到延遲(延遲)和復雜性:大量確認消息和彈性保存數(shù)據(jù)(狀態(tài)),直到您已經(jīng)從職責鏈中的下一個服務確認完成了他們已經(jīng)承擔責任。
一個可靠的方法卻不能保證快速的傳遞,但它確保所有的消息將最終至少一次傳遞。在每個消息至關重要且不能容忍丟失(例如信用卡交易)的環(huán)境中,這是一個很好的方法。AWS簡單隊列服務(Amazon的托管隊列服務)是以可靠方式使用狀態(tài)服務的一個例子。(banq注: Apache kafka提供類似正好一次的有效一次傳遞也是適用類似信用卡之類的交易)
第二種情況是,使用不可靠的方法可以實現(xiàn)端對端通訊得更快(比如RPC同步方式),但這意味著服務通常不得不期待重復和無序消息,并且一些消息將丟失。當消息是時間敏感的(即,如果他們不迅速采取行動,就不值得采取行動)或稍后的數(shù)據(jù)只是覆蓋早期的數(shù)據(jù),這種情況下可能會使用不可靠的通信。對于非常大規(guī)模的分布式系統(tǒng),可以使用不可靠的消息傳遞,因為它的開銷小且要快得多。然而,微服務設計卻需要處理應對消息的丟失和重復。
在上述每種情況方法中,存在許多變量(例如,有保證和不保證的順序性),所有這些變量需要在速度、復雜性和故障率方面進行不同的權衡。
一些系統(tǒng)可以同時使用上述多種方法,這取決于正在發(fā)送的消息的類型甚至系統(tǒng)上的當前負載。如果您有很多行為不同的服務,就很難正確恰當使用這些方法。需要在其API中明確定義服務的行為。為您的系統(tǒng)中的服務進行約束或推薦的通信行為的定義通常是有意義的,以獲得一定程度的一致性。
現(xiàn)在時間是幾點?
在分布式系統(tǒng)中沒有這樣的常見的所謂全球時鐘。例如,在團體聊天中,我的評論和我的朋友在澳大利亞、哥倫比亞和日本發(fā)表的評論的出現(xiàn)將不會遵循嚴格順序先后出現(xiàn)。沒有任何保證機制保證我們看到的都是相同的時間表 - 雖然總有一個順序,但是前提是我們有段時間先不說話。
基本上,在分布式系統(tǒng)中,每臺機器都有自己的時鐘,整個系統(tǒng)沒有一個正確的時間。機器時鐘可能會進行同步,但是即使在同步時傳輸時間也會不同,物理時鐘也會以不同的速率運行,所以一切都會立即失去同步。
在單個機器上,一個時鐘可以為所有線程和進程提供通用的時間。在分布式系統(tǒng)中,這在物理上都不可行。
在我們的新世界中,時鐘時代不再提供無可置疑的順序定義。在微服務世界中并不存在“什么時候”的單一概念,所以,我們的設計不應該依賴于服務間消息。
真相就在那里?
在分布式系統(tǒng)中,沒有全局共享內存,因此沒有單一版本的真相。數(shù)據(jù)將分散在不同物理機器上。此外,任何指定的數(shù)據(jù)在機器之間更可能處于相對較慢和無法訪問的傳輸中,而不像在單體架構下的情況。因此,真正運行情況需要基于當前的當?shù)氐男畔ⅰ?/p>
這意味著系統(tǒng)的不同部分的運行情況并不總是一致的。在理論上,它們最終應該在整個系統(tǒng)中傳播消息時變得一致,但是如果數(shù)據(jù)不斷變化,我們可能永遠不會達到完全一致的狀態(tài),除非關閉所有新的輸入和等待。因此,服務必須處理這樣一個事實,即他們相互調用時可能會因為自己的問題而獲得“舊”的或者不一致的信息。
說話快點!
在一個單體的應用程序中,大多數(shù)重要的通信發(fā)生在一個組件和另一個組件之間的單個進程中。流程內部的通信非常快,所以很多內部消息的傳遞不是問題。但是,一旦將單體組件拆分成單獨的服務,通常會在不同的機器上運行,那么事情變得越來越復雜。
假設你知道如下背景知識:
在分布式環(huán)境中的結果卻是:
狀況報告?
如果您的系統(tǒng)可以次秒級(時間上短于1秒)速度更改,這是動態(tài)管理的分布式架構的目標,那么您需要以這種速度了解問題。許多傳統(tǒng)的日志工具并不是為了跟蹤這種情況而設計的。你需要確保能使用它們。
測試破壞
了解您的分布式系統(tǒng)是否正常工作并從不可預測的錯誤中恢復的唯一方法是:持續(xù)攻克這些錯誤并持續(xù)修復系統(tǒng)。Netflix使用Chaos Monkey(混沌猴)隨機造成故意的崩潰測試。您的系統(tǒng)的彈性和完整性是需要測試的,同樣重要的是,測試您的日志記錄,以確保如果發(fā)生錯誤,您可以追溯地診斷和修復它 - 即使您的系統(tǒng)已經(jīng)恢復在線運行。
這聽起來很困難 我一定需要嗎?
創(chuàng)建分布式、可擴展的、有彈性的系統(tǒng)是非常困難的,特別是對于有狀態(tài)的服務(服務需要寫數(shù)據(jù)庫保存變動的數(shù)據(jù))。現(xiàn)在是決定是否需要它的時候了。你的客戶需求是否可以容忍慢一點響應還是小型規(guī)模系統(tǒng)?這樣,您可以先設計一個更小、更慢、更簡單的系統(tǒng),并在構建專業(yè)知識同時逐步增加更多的復雜性。
像AWS,Google和Azure這樣的云計算提供商也正在開發(fā)和推出這些大部分功能,特別是彈性狀態(tài)(托管的消息隊列和數(shù)據(jù)庫)。這些服務似乎是昂貴的,但構建和維護復雜自己的分布式服務也是昂貴的。
任何雖然可能限制您但是會處理這些復雜性的框架(如Linkerd或Istio或Azure的服務架構)是非常值得考慮的。
關鍵的挑戰(zhàn)是不要低估建立正確的彈性和高度可擴展的服務的難度。如果決定你真的需要它,那么全面教育大家,引入有用的約束,逐漸做好一切,并期待挫折和成功。
總結
以上是生活随笔為你收集整理的Java程序员须知:分布式微服务为什么很难?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java-集合的简单介绍
- 下一篇: 编程入门:C语言基础知识全网超全不用到处