O'Reilly 主題演講:淺談“完美無瑕”的分散式系統

2019-09-06 03:14:35

作者 | Lena Hall
譯者 | 劉志勇
本文最初發佈於 Lena Hall 個人部落格,經原作者 Lena Hall 授權,由 InfoQ 中文站翻譯並分享。

本文基於 Lena Hall 的 O'Reilly Velocity 2019 主題演講進行了解讀。分散式系統是建立在網路之上的軟體系統。正是因為軟體的特性,所以分散式系統具有高度的內聚性和透明性。因此,網路和分散式系統之間的區別更多的在於高層軟體(特別是作業系統),而不是硬體。

內聚性是指每一個數據庫分佈節點高度自治,有本地的資料庫管理系統。

透明性是指每一個數據庫分佈節點對使用者的應用來說都是透明的,看不出是本地還是遠端。

在分散式資料庫系統中,使用者感覺不到資料是分佈的,即使用者不須知道關係是否分割、有無副本、資料存於哪個站點以及事務在哪個站點上執行等。

說了這麼多,但實際上,分散式系統一點都不復雜,簡單的說就是:將整個個軟體視為一個系統(不管它有多複雜),然後將整個系統分割為一系列的程序,每個程序完成一定的功能。再將這些程序分散到不同的機器上,分散後,選擇若干種通訊協議將它們連線起來。這就完成了分散式系統的構建。人們常常把分散式系統自然而然的和平行計算聯絡起來。然而這並不正確。實際上,分散式系統並不一定是並行的。Lena Hall 給我們詳細闡述了“完美無瑕”的分散式系統應該是什麼樣的,以及我們應該如何朝著這一目標做哪些工作。

本文闡述了我們所做工作帶來的影響,我們所面臨的複雜性和障礙,以及對於構建更好的分散式系統的重要因素,尤其是當其他關鍵領域依賴並建立我們所創造的基礎之上時。

目前可用的系統已經提供了許多解決方案,封裝了許多分散式演算法,實現了自動化並抽象出一些複雜性。使用這些系統的工程師並不一定非要擁有開發它們所需的大量知識不可。儘管對於工程師新手來說,瞭解這些系統所依賴的基礎知識越來越沒有什麼必要了,但在某些情況下,瞭解幕後工作對於做出正確的決策並解決出現的困難問題還是必不可少的。

基礎知識仍然很重要嗎?  

為什麼說重視基礎知識很重要?今天,我們正處於這樣的一個階段,分散式系統在醫療系統、自主裝置、傳輸自動化和其他生命攸關係統中的應用越來越廣泛,在這些場景中,錯誤的代價越來越高,而正確性變得日益重要起來。

錯誤的代價並不是指你的系統今天不可用的時間長短。它是關於你的系統發生宕機或故障時,給使用者或他們的使用者帶來的代價。我們應該負起責任,並永遠記住我們為什麼這樣做,我們真正要解決的問題是什麼。

每個行業都希望通過結合他們和我們的研究和解決方案來取得更大的進步。而我們的工作能夠幫助其他領域更好地實現他們的目標。對我們來說,瞭解如何放寬某些限制或者微調某些權衡也是非常有用的。

瞭解核心的內容,是一個強大的工具,可以讓我們從容駕馭不斷變化的選項和工具的複雜性,並幫助我們構建正確的解決方案,以改進我們現有的選項。

但事實證明,要做到這一點並不是那麼容易。在我們前進的道路上,荊棘載途,艱難險阻。

理論和實踐存在巨大的差距  

理解“正確”對我們的系統意味著什麼,對我們來說,不啻為一個挑戰。大多數理論材料都很不“接地氣”,眾所周知,它們很難被理解並掌握。不止如此,它往往還不包括那些將這一理論付諸實踐所需的資訊。要想應用到生產系統中,就必須修改理論演算法,並對它們進行調整以適應實際環境。其中許多並沒有透露對實際解決方案很重要的具體細節。甚至對協議細節稍有誤解,也會破壞協議的正確性。因此,我們需要做更多的額外工作,以保證實踐時,協議仍然是正確的。

正確性難以驗證和維持  

在實際環境中驗證並維持分散式系統的正確性,是一項具有挑戰性的工作。它可能聽上去很完美,但在實踐中,卻可能是低效的、或者難以實現的。這在理論上聽起來不切實際,但在實踐中卻是完全可以接受的。須知在演算法邏輯及其實現中,很多地方都有可能出錯,而且還難以檢測。

正確性並不總是優先考慮的事  

另一方面,正確性並不總是優先考慮的事。還有截止期限、競爭和客戶都需要更快的解決方案。終端系統還可能會出現倉促而不能正確修復的情況。這意味著團隊可能沒有足夠的時間來做這件事:正確地討論並系統地解決罕見的“間歇性”錯誤背後的真正原因,這些錯誤在未來還會再次發生,導致出現更多的錯誤。

我們該如何改進?  

我們可以從多個方面改進。其中之一就是:強調並集中精力提高正確性,以確保我們能夠構建並維護系統,使其始終按照我們所希望的那樣執行。

另一個就是,提高對它們如何工作的理解,因為這有助於我們減少複雜性和可能出現的錯誤,並使我們更有準備迎接即將到來的挑戰。

當我們不直接實現分散式演算法和概念時,我們肯定會依賴基於那些構建的系統。在我們構建的內容與其他領域相互交叉時,理解基本概念和權衡就變得極為重要了。

如果向你承諾了一些效能和一致性,那麼你該如何確保這些承諾就是在你需要的確切水平上提供的呢?

簡單問題複雜化  

當幾臺計算機相互通訊時,瑣碎的問題就變成了棘手的問題,而且它們還會累積起來。分散式系統難以理解,也難以實現,而且在實踐中很難保持它們的正確性。

我認為有很多方法可以說明其原因。最近,我有機會為生物資訊學領域的人解釋,他們想知道為什麼需要在分散式環境中的重要屬性之間進行權衡。

   排序     

我想到的第一件事就是對事件進行排序。在一臺機器上進行排序很容易,但當訊息通過網路傳送時,就變得很難了!我們不能依賴物理時間戳,因為不同機器上的物理時鐘往往有所偏移。對於分散式系統中的排序,我們經常應用邏輯時鐘,或者簡單地說,在節點之間傳遞的計數器。

由於分散式系統的非同步特性,我們並不能很容易地為所有事件建立競爭順序,因為其中一些事件是併發的!我們所能做的就是找出哪些事件是併發的,哪些事件在彼此之前發生。即使是這樣一個簡單的任務,我們也需要做出一些決定。

例如,如果系統告訴我們事件是有序的,但實際上它們是併發的,那麼,這種情況我們是否可以接受呢?

或者,我們是否需要確切地知道,當我們可以對事件進行排序時,事件真的不是同時發生的嗎?

   協議     

我們不能簡單地對併發事件進行排序,有時候,我們仍然需要決定操作的順序、值、值序列或其他任何東西。

事實證明,讓幾臺機器選擇相同的東西是另一種情況。在這種情況下,我們必須要問自己的問題,並決定什麼對我們是合適的。

例如,二階段提交(Two Phase Commit)的是一種解決方案,在這種解決方案中,我們的節點可以就某些方面達成一致。

譯註:在計算機網路以及資料庫領域內,二階段提交(Two-phase Commit)是指,為了使基於分散式系統架構下的所有節點在進行事務提交時保持一致性而設計的一種演算法。通常,二階段提交也被稱為是一種協議。在分散式系統中,每個節點雖然可以知曉自己的操作時成功或者失敗,卻無法知道其他節點的操作的成功或失敗。當一個事務跨越多個節點時,為了保持事務的 ACID 特性,需要引入一個作為協調者的元件來統一掌控所有節點(稱作參與者) 的操作結果並最終指示這些節點是否要把操作結果進行真正的提交(比如將更新後的資料寫入磁碟等等)。因此,二階段提交的演算法思路可以概括為:參與者將操作成敗通知協調者,再由協調者根據所有參與者的反饋情報決定各參與者是否要提交操作還是中止操作。

只要我們的節點不出故障,它就可以進行工作。

如果一些節點發生崩潰,為了防止出現數據不一致的可能性,系統就會阻塞,直到崩潰的節點返回,這種情況也有可能永遠不會發生;或者需要非常、非常長的時間。

所以,這個演算法是安全的,但它不是實時的。

如果這還不是我們所能接受的,那麼我們是不是真的需要一個系統來回應呢?

在這種情況下,我們可能有另一種潛在的解決方案:三階段提交(Three Phase Commit),當節點出現故障時,它就不會發生阻塞。

譯註: 三階段提交(Three-phase commit),是在計算機網路及資料庫的範疇下,使得一個分散式系統內的所有節點能夠執行事務的提交的一種分散式演算法。三階段提交是為解決兩階段提交協議的缺點而設計的。與二階段提交不同的是,三階段提交是 “非阻塞” 協議。三階段提交在二階段提交的第一階段與第二階段之間插入了一個準備階段,使得原先在二階段提交中,參與者在投票之後,由於協調者發生崩潰或錯誤,而導致參與者處於無法知曉是否提交或者中止的 “不確定狀態” 所產生的可能相當長的延時的問題得以解決。

但是,當有網路分割槽時,情況又會怎麼樣呢?

網路的兩個相互隔離的分割槽在超時後可能會做出兩個不同的決定,系統最終將會處於不一致的狀態。

所以,這時候我們得到的是相反的結果:系統是實時響應的,但並不安全,因為不同的節點可以決定不同的值。

如果我們對這兩個選項中的任何一個都能接受,那就太好了!

如果我們希望資料始終保持一致性,並且系統還要能夠響應,那麼我們應該做什麼呢?

不可能結果  

不可能結果證明,實際上,在完全非同步的環境中,總是終止並最終作出決定的確定性演算法是不存在的,甚至可能出現一次故障。

譯註: 不可能結果(Impossibility result)是分散式領域的專業術語,在一個完全非同步的訊息傳遞分散式系統中,如果一個程序有故障,那麼一致性問題是無法得到解決的。簡單來說,就是在一定的限制條件下問題能否被解決,那麼任務的不可能結果就只有兩種情況:能和不能。

從這個結果中,我們可以學到的主要內容是:如果我們想在實踐中解決協議,我們就必須重新考慮我們的假設,以反映更為現實的期望!例如,我們可以設定最大訊息延遲的上限,並確定系統可接受的失敗次數。

如果我們改變假設,那麼我們就可以用多種方式來解決分散式協議!

Paxos 演算法  

最著名的解決方案是 Paxos 演算法,眾所周知,這個演算法晦澀難懂,而且難以正確實施。

它實際上是可行的,但只有在大多數節點都必須啟動,且最大訊息延遲是有限的情況下才可行。

在 Paxos 中,任何節點都可以提出一個值,在經過“準備”和“建議”階段後,所有節點都應該就相同的值達成一致。

大多數節點都需要啟動,因為如果在每個階段中 Quorums 相交,總有有至少一個節點記得最近的建議是什麼,這就阻止了對舊值達成一致。

為了提高演算法的效率,在實際應用中,對初始演算法進行了許多優化。基於它們所選擇的權衡,共識演算法也有許多可能的變體。

例如,Leader 完成了多少工作。擁有一個強大的 Leader 可能是好事,但也有可能是壞事。這要取決於失敗的頻率和重新選舉的難度。另一種權衡是,我們可以容忍多少節點出故障,以及 Quorum 數量應該有多少。

有些被低估的標準是演算法在實踐中的可理解性和可實施性。Raft 之所以廣受歡迎,是因為它更容易理解,現在已經應用於許多廣泛使用的專案中。

譯註: Paxos 演算法是 Leslie Lamport(就是 LaTeX 中的 "La",此人現在在微軟研究院)於 1990 年提出的一種基於訊息傳遞的一致性演算法。這個演算法被認為是類似演算法中最有效的。Paxos 演算法解決的問題是一個分散式系統如何就某個值(決議)達成一致。一個典型的場景是,在一個分散式資料庫系統中,如果各節點的初始狀態一致,每個節點執行相同的操作序列,那麼他們最後能得到一個一致的狀態。為保證每個節點執行相同的命令序列,需要在每一條指令上執行一個 “一致性演算法” 以保證每個節點看到的指令一致。

新的權衡仍在不斷髮現  

但更有趣的是,儘管共識和協議的話題並不新鮮,但我們仍然發現了許多新的優化和權衡。

在經典的 Paxos 演算法中,大多數節點都需要啟動以確保所有的 Quorum 相交。但事實證明,我們可以重新考慮並簡化大多數 Quorum 要求。事實證明,只有準備階段和建議階段的 Quorum 相交就足矣,這為我們提供了更多的靈活性來對每個階段的 Quorum 大小和效能進行實驗!

重點是,揭示迄今為止的新效能和可用性權衡,有助於我們在實踐中擴大選擇範圍。共識只是一個構件塊,但它可以用來解決許多常見問題,如原子廣播(atomic broadcast)、分散式鎖(distributed locks)、強一致性複製等等。

請檢視 Heidi Howard 博士的論文"Distributed Consensus Revised",該篇論文是這方面最好的論文之一。

一致性複製?  

複製(Replication)是當今任何分散式系統的重要組成部分。

我們實際上可以用共識來實現強一致性複製,但它的缺點之一就是效能。另一方面當然是一致性複製,這種複製速度非常快,但在客戶端卻可以看到不一致的資料。在實踐中,我們通常會希望獲得更好的效能,同時還要保持更強的一致性,這可能有些棘手。

因此,在某些情況下,我們可以提出比共識更快的解決方案,而且比最終的一致性更加一致。

其中一個有趣的例子是 Aurora,它避免了對 I/O 和其他一些操作達成共識。它們使用 Quorum 進行寫入,但不用它們來閱讀。實際上,副本可能會儲存不同的值,但當客戶端執行讀取操作時,由於資料庫維護一致性點,因此它可以直接檢視已知資料一致的節點,並將正確的資料返回給客戶端。

無衝突可複製資料型別  

另一個有趣的例子是無衝突可複製資料型別(Conflict Free Replicated Data Type,CRDT)。它們可以提供強大的最終一致性:快速讀寫操作,甚至在網路分割槽期間仍然保持可用,而無需使用共識或同步。然而,只有在我們能夠有解決任何併發衝突的規則時才有可能。

換句話說,如果可以使用某些函式合併併發更新,這些可以按任意順序應用它們,並且還可以按照我們想要的任意次數應用它們,而不會破壞結果,那麼我們就只能使用這種技術。

這是一個完全可以接受的示例,其中所有更新都是附加的,因此它們完全滿足這一要求。

另一方面,這一點並不明顯,因為我們沒有明確的規則來解決這種同時更新的衝突。

Azure Cosmos DB 使用 CRDT 在併發多主多區域寫入的後臺來解決衝突。Redis 和 Riak 也使用 CRDT。

故障檢測  

如果我們在分散式系統中進入另一個主題,我們總會發現需要進行更多的權衡。

故障檢測器是分散式系統中發現節點崩潰的關鍵技術之一。它們可以應用於協議問題、Leader 選舉、組員協議和其他領域。

我們可以通過故障檢測器的“完備性”、“正確度”來衡量它們的效率。

完備性 顯示了系統中的一些或所有節點是否發現所有故障。正確度 度量故障檢測器在懷疑另一個節點故障可能出現的錯誤級別。

事實證明,即使是不可靠的故障檢測器在實際系統中也是非常有用的,因為我們可以通過新增一種故障知識傳播到所有節點的“八卦”機制,來提高它們的完備性。

為什麼所有這一切都很重要?  

權衡可能是多種多樣的,如果我們知道如何使用它們,知道在哪裡尋找它們,那麼我們就可以變得非常靈活。

許多產品都是圍繞演算法和權衡而構建的。這些產品為我們做出了某些選擇,我們通過使用某些產品來做出選擇。未受教育的選擇可能會導致延遲和資料丟失。對於某些系統來說,這點可能會導致客戶流失和鉅額資金。對於其他系統來說,它可能導致反應緩慢,或者操作順序錯誤,從而構成了實際的生命威脅。理解你的權衡對於做出正確的選擇、瞭解正確的含義以及在現實中驗證系統的正確性非常重要。

驗證與維護現實中的正確性  

在我們明確了抉擇和權衡之後,我們該如何在實際系統中維護正確性呢?

系統模型檢查是驗證分散式邏輯的安全性和活性(尤其是安全性)的常用選項之一。模型檢查很有用,因為它探索了系統最終可能出現的所有狀態。現在有相當多的工具,如 TLA+ 就非常有名,除此之外還有更多的新興技術,如語義感知模型檢查。

為了驗證分散式系統的實際執行實現的正確性,僅靠模型檢查是不夠的。

很少有專案會發布關於如何維護其系統的正確性並對其進行驗證的相關資訊。但其中一些專案做到了。

例如,Kafka 的各種系統測試每天都在執行,世界上的任何人都可以檢查並檢視哪些工作符合預期,哪些工作不正常。

Cassandra 對他們的綜合測試方法寫了一篇很棒的文章。

我真的希望,會有更多的產品、專案和系統能夠對他們投入測試和正確性驗證方面的工作更加開放。

如果我們看一下準備執行生產機分散式系統需要做些什麼,就會發現有很多事情需要去做。

當然,對於小範圍場景並確保多個服務協同工作良好,單元測試和整合測試是必不可少的。但這些還不夠!我們可以使用更多的技術。模糊測試和基於屬性的測試為你的系統提供了隨機生成的輸入,以確保基本屬性基於其規範是正確的。實際上,我在 Microsoft 從事過一個關於模糊測試的專案,總體來說,這是一個非常吸引人的話題。效能測試對收集各種元件的延遲和吞吐量的資料非常有用。故障注入有助於檢查系統在故障情況下是否可用,以及預期的系統屬性是否仍然保持正確。

綜上所述,導致最嚴重錯誤的背後的大量原因,仍然是異常處理邏輯。

有些事情,我們無法完全解決。我們需要接受這樣一個事實:在我們編寫完所有的測試和檢查之後,無論如何,錯誤都會存在。我們是人類,再加上上下文切換,因此我們不可能知曉每一件事,有太多的活動部分了。我們永遠沒有探索過新的領域,如果我們害怕離開所熟悉的領域,那麼我們就永遠不會取得進展。但是,我們絕對可以為處理意外錯誤做出更好的準備,找到模式,並試圖解決導致錯誤的原因。這就是為什麼檢測程式碼很重要,可觀察性也很重要。當我們意識到這種可能性併為解決生產錯誤奠定基礎時,就不那麼可怕了。

題外話  

產品變化很快,描述它們的一致性、彈性和效能的術語極其繁多。基本概念和權衡仍然存在,並不斷積累。它們在孤立的情況下並沒有什麼用處,但是瞭解它們,對於做出正確的選擇和在實踐中保持正確性是必不可少的。當我們的系統在特定級別的響應性和安全性有強烈要求的場景中受到信任時,正確性尤為重要。

如果你正在構建某些內容時,請捫心自問:這會被誤解嗎?複雜性就像專案周圍的一堵防彈牆一樣,它使解釋、構建、使用和改進變得困難。試著讓你構建的系統能夠被其他人理解,因為理解有助於正確性的提高。

正確性並不容易,也不是免費的。你必須致力於此,並將其作為優先事項。不僅僅是一個願意這樣做的工程師的水平上,而是整個組織的水平。不要相信你的系統知識工作:測試它,驗證它,並在事情失敗時做好準備,向你的使用者和客戶展示你在演示系統方面投入了哪些技術和努力。

想想那些與你工作相關但沒有得到足夠重視的重要領域吧,如果你有機會和其他領域工作的其他人聊天,那就去做,瞭解他們在工作中所面臨的挑戰,以及他們正在做出的權衡。虛心求教,與他們分享你的工作。這會幫助你成長為一個更優秀的工程師。

作者介紹

Lena Hall,Microsoft 高階軟體工程師,從事大資料和分散式系統方向。曾在 Microsoft 研究院工作。同時也是一名技術演講者、機器學習 ML4ALL 的組織者、Kafka 峰會的董事。

原文連結:

https://lenadroid.github.io/posts/OReillyVelocity/keynote.html


活動推薦

微服務落地涉及到以運維為首,包含IT架構、應用架構、組織架構等多個方面,這是一個循序漸進的階段性過程,而在每一個階段都會遇到運維、部署、安全等問題,包括組織協作上的問題。運維團隊如何在微服務架構採取有效的實施過程,請【掃碼】或點選【閱讀原文】瞭解詳細資訊。ArchSummit全球架構師峰會,7折限時直降2640元!瞭解詳情請聯絡票務經理灰灰:15600537884 ,微信同號。

已同步到看一看



熱點新聞