作者 | 曉土??阿里巴巴高級工程師
姊妹篇閱讀推薦:《[云原生時代,分布式系統設計必備知識圖譜(內含22個知識點)](http://mp.weixin.qq.com/s?__biz=MzUzNzYxNjAzMg==&mid=2247486600&idx=1&sn=0ad92a1fe535f141fe2e8c87ffbd1229&chksm=fae50747cd928e51c05c41d2cc206069babbe9dfdba5957c52ac6e77cb754192169bb6b3e898&scene=21#wechat_redirect)》
導讀:本文力求從分布式基礎理論、架構設計模式、工程應用、部署運維、業界方案這幾大方面,介紹基于 MSA(微服務架構)的分布式知識體系大綱,從而對 SOA 到 MSA 進化有著立體的認識;從概念上和工具應用上更近一步了解微服務分布式的本質,身臨其境的感受如何搭建全套微服務架構的過程。
關注“阿里巴巴云原生”公眾號,回復“分布”,即可下載分布式系統及其知識體系清晰大圖!
隨著移動互聯網的發展和智能終端的普及,計算機系統早就從單機獨立工作過渡到多機器協作,集群按照分布式理論構建出龐大復雜的應用服務,在分布式的基礎上正進行一場云原生的技術革命,徹底打破傳統的開發方式,解放了新一代的生產力。
cdn.com/d16a1bbbb104cad78fe989c3f11828614c75e946.png">
關注“阿里巴巴云原生”公眾號,回復“**分布**”,即可下載分布式系統及其知識體系清晰大圖!
由于業務發展到一定程度后,需要對服務進行解耦,進而把一個單一的大系統按邏輯拆分成不同的子系統,通過服務接口來通訊。面向服務的設計模式,最終需要總線集成服務,而且大部分時候還共享數據庫,出現單點故障時會導致總線層面的故障,更進一步可能會把數據庫拖垮,所以才有了更加獨立的設計方案的出現。
微服務是真正意義上的獨立服務,從服務入口到數據持久層,邏輯上都是獨立隔離的,無需服務總線來接入,但同時也增加了整個分布式系統的搭建和管理難度,需要對服務進行編排和管理,所以伴隨著微服務的興起,微服務生態的整套技術棧也需要無縫接入,才能支撐起微服務的治理理念。
傳統的節點也就是一臺單體的物理機,所有的服務都揉進去包括服務和數據庫;隨著虛擬化的發展,單臺物理機往往可以分成多臺虛擬機,實現資源利用的最大化,節點的概念也變成單臺虛擬機上面服務;近幾年容器技術逐漸成熟后,服務已經徹底容器化,也就是節點只是輕量級的容器服務??傮w來說,節點就是能提供單位服務的邏輯計算資源的集合。
分布式架構的根基就是網絡,不管是局域網還是公網,沒有網絡就無法把計算機聯合在一起工作,但是網絡也帶來了一系列的問題。網絡消息的傳播有先后,消息丟失和延遲是經常發生的事情,我們定義了三種網絡工作模式:
常用網絡傳輸層有兩大協議的特點簡介:
慢速物理時空中,時間獨自在流淌著,對于串行的事務來說,很簡單的就是跟著時間的腳步走就可以,先來后到的發生。而后我們發明了時鐘來刻畫以往發生的時間點,時鐘讓這個世界井然有序。但是對于分布式世界來說,跟時間打交道著實是一件痛苦的事情。
分布式世界里面,我們要協調不同節點之間的先來后到關系,不同節點本身承認的時間又各執己見,于是我們創造了網絡時間協議(NTP)試圖來解決不同節點之間的標準時間,但是 NTP 本身表現并不盡如人意,所以我們又構造出了邏輯時鐘,最后改進為向量時鐘:
有了衡量時間的工具,解決順序問題自然就是水到渠成了。因為整個分布式的理論基礎就是如何協商不同節點的一致性問題,而順序則是一致性理論的基本概念,所以前文我們才需要花時間介紹衡量時間的刻度和工具。
說到一致性理論,我們必須看一張關于一致性強弱對系統建設影響的對比圖:
該圖對比了不同一致性算法下的事務、性能、錯誤、延遲的平衡。
單機環境下我們對傳統關系型數據庫有苛刻的要求,由于存在網絡的延遲和消息丟失,ACID 便是保證事務的原則,這四大原則甚至我們都不需要解釋出來就耳熟能詳了:
分布式環境下,我們無法保證網絡的正常連接和信息的傳送,于是發展出了 CAP/FLP/DLS 這三個重要的理論:
多數情況下,其實我們也并非一定要求強一致性,部分業務可以容忍一定程度的延遲一致,所以為了兼顧效率,發展出來了最終一致性理論 BASE。BASE 是指基本可用(Basically Available)、軟狀態( Soft State)、最終一致性( Eventual Consistency):
分布式架構的核心就在于一致性的實現和妥協,那么如何設計一套算法來保證不同節點之間的通信和數據達到無限趨向一致性,就非常重要了。保證不同節點在充滿不確定性網絡環境下能達成相同副本的一致性是非常困難的,業界對該課題也做了大量的研究。
首先我們要了解一致性的大前提原則?(CALM):
CALM 原則的全稱是 Consistency and Logical Monotonicity ,主要描述的是分布式系統中單調邏輯與一致性的關系,它的內容如下,參考?consistency as logical monotonicity。
然后再關注分布式系統的數據結構?CRDT(Conflict-Free Replicated Data Types):
我們了解到分布式一些規律原則之后,就要著手考慮如何來實現解決方案,一致性算法的前提是數據結構,或者說一切算法的根基都是數據結構,設計良好的數據結構加上精妙的算法可以高效的解決現實的問題。經過前人不斷的探索,我們得知分布式系統被廣泛采用的數據結構 CRDT。
參考《談談 CRDT》,A comprehensive study of Convergent and Commutative Replicated Data Types
了解數據結構后,我們需要來關注一下分布式系統的一些重要的協議HATs(Highly Available Transactions),ZAB(Zookeeper Atomic Broadcast):
參考《高可用事務》,《ZAB 協議分析》
最后要學習的是業界主流的一致性算法?:
說實話具體的算法我也還沒完全搞懂,一致性算法是分布式系統最核心本質的內容,這部分的發展也會影響架構的革新,不同場景的應用也催生不同的算法。
這一節我們說完分布式系統里面核心理論基礎,如何達成不同節點之間的數據一致性,下面我們將會講到目前都有哪些主流的分布式系統。
單臺計算機的存儲始終有上限,隨著網絡的出現,多臺計算機協作存儲文件的方案也相繼被提出來。最早的分布式文件系統其實也稱為網絡文件系統,第一個文件服務器在 1970 年代被發展出來。在 1976 年迪吉多公司設計出 File Access Listener(FAL),而現代分布式文件系統則出自赫赫有名的 Google 的論文,《The Google File System》奠定了分布式文件系統的基礎?,F代主流分布式文件系統參考《分布式文件系統對比》,下面列舉幾個常用的文件系統:
數據庫當然也屬于文件系統,主數據增加了事務、檢索、擦除等高級特性,所以復雜度又增加了,既要考慮數據一致性也得保證足夠的性能。傳統關系型數據庫為了兼顧事務和性能的特性,在分布式方面的發展有限,非關系型數據庫擺脫了事務的強一致性束縛,達到了最終一致性的效果,從而有了飛躍的發展,NoSql(Not Only Sql) 也產生了多個架構的數據庫類型,包括 KV、列式存儲、文檔類型等。
分布式計算系統構建在分布式存儲的基礎上,充分發揮分布式系統的數據冗余災備,多副本高效獲取數據的特性,進而并行計算,把原本需要長時間計算的任務拆分成多個任務并行處理,從而提高了計算效率。分布式計算系統在場景上分為離線計算、實時計算和流式計算。
緩存作為提升性能的利器無處不在,小到 CPU 緩存架構,大到分布式應用存儲。分布式緩存系統提供了熱點數據的隨機訪問機制,大大了提升了訪問時間,但是帶來的問題是如何保證數據的一致性,引入分布式鎖來解決這個問題,主流的分布式存儲系統基本就是 Redis 了。
分布式消息隊列系統是消除異步帶來的一系列復雜步驟的一大利器,在多線程高并發場景下,我們常常需要謹慎設計業務代碼,來保證多線程并發情況下不出現資源競爭導致的死鎖問題。而消息隊列以一種延遲消費的模式將異步任務都存到隊列,然后再逐個消化。
分布式系統從單機到集群的形態發展,復雜度也大大提高,所以對整個系統的監控也是必不可少。
分布式系統的核心模塊就是在應用如何處理業務邏輯,應用直接的調用依賴于特定的協議來通信,有基于 RPC 協議的,也有基于通用的 HTTP 協議。
錯誤對應分布式系統是家常便飯,而且我們設計系統的時候,本身就需要把容錯作為普遍存在的現象來考慮。那么當出現故障的時候,快速恢復和排查故障就顯得非常重要了。分布式日志采集存儲和檢索則可以給我們提供有力的工具來定位請求鏈路中出現問題的環節。
前文我們提到所謂分布式系統,是迫于單機的性能有限,而堆硬件卻又無法無休止的增加,單機堆硬件最終也會遇到性能增長曲線的瓶頸。于是我們才采用了多臺計算機來干同樣的活,但是這樣的分布式系統始終需要中心化的節點來監控或者調度系統的資源,即使該中心節點也可能是多節點組成。區塊鏈則是真正的區中心化分布式系統,系統里面只有 P2P 網絡協議各自通信,沒有真正意義的中心節點,彼此按照區塊鏈節點的算力、權益等機制來協調新區塊的產生。
上節我們列舉了不同場景下不同分布式系統架構扮演的角色和實現的功能,本節我們更進一步歸納分布式系統設計的時候是如何考慮架構設計的、不同設計方案直接的區別和側重點、不同場景需要選擇合作設計模式,來減少試錯的成本,設計分布式系統需要考慮以下的問題。
可用性是系統運行和工作的時間比例,通常以正常運行時間的百分比來衡量。它可能受系統錯誤、基礎架構問題、惡意attack和系統負載的影響。分布式系統通常為用戶提供服務級別協議(SLA),因此應用程序必須設計為最大化可用性。
數據管理是分布式系統的關鍵要素,并影響大多數質量的屬性。由于性能,可擴展性或可用性等原因,數據通常托管在不同位置和多個服務器上,這可能帶來一系列挑戰。例如,必須維護數據一致性,并且通常需要跨不同位置同步數據。
良好的設計包括諸如組件設計和部署的一致性、簡化管理和開發的可維護性、以及允許組件和子系統用于其他應用程序和其他方案的可重用性等因素。在設計和實施階段做出的決策對分布式系統和服務質量和總體擁有成本產生巨大影響。
分布式系統需要一個連接組件和服務的消息傳遞中間件,理想情況是以松散耦合的方式,以便最大限度地提高可伸縮性。異步消息傳遞被廣泛使用,并提供許多好處,但也帶來了諸如消息排序,冪等性等挑戰
分布式系統在遠程數據中心運行,無法完全控制基礎結構,這使管理和監視比單機部署更困難。應用必須公開運行時信息,管理員可以使用這些信息來管理和監視系統,以及支持不斷變化的業務需求和自定義,而無需停止或重新部署應用。
性能表示系統在給定時間間隔內執行任何操作的響應性,而可伸縮性是系統處理負載增加而不影響性能或容易增加可用資源的能力。分布式系統通常會遇到變化的負載和活動高峰,特別是在多租戶場景中,幾乎是不可能預測的。相反,應用應該能夠在限制范圍內擴展以滿足需求高峰,并在需求減少時進行擴展??缮炜s性不僅涉及計算實例,還涉及其他元素,如數據存儲、消息隊列等。
彈性是指系統能夠優雅地處理故障并從故障中恢復。分布式系統通常是多租戶,使用共享平臺服務、競爭資源和帶寬,通過 Internet 進行通信,以及在商用硬件上運行,意味著出現瞬態和更永久性故障的可能性增加。為了保持彈性,必須快速有效地檢測故障并進行恢復。
安全性是系統能夠防止在設計使用之外的惡意或意外行為,并防止泄露或丟失信息。分布式系統在受信任的本地邊界之外的 Internet 上運行,通常向公眾開放,并且可以為不受信任的用戶提供服務。必須以保護應用程序免受惡意attack,限制僅允許對已批準用戶的訪問,并保護敏感數據。
前文我們介紹了分布式系統的核心理論,面臨的一些難題和解決問題的折中思路,羅列了現有主流分布式系統的分類,而且歸納了建設分布式系統的一些方法論,那么接下來我們將從工程角度來介紹搭建分布式系統包含的內容和步驟。
巧婦難為無米之炊,我們一切的軟件系統都是構建在硬件服務器的基礎上。從最開始的物理機直接部署軟件系統,到虛擬機的應用,最后到了資源上云容器化,硬件資源的使用也開始了集約化的管理。本節對比的是傳統運維角色對應的職責范圍,在 devops 環境下,開發運維一體化,我們要實現的也是資源的靈活高效使用。
過去軟件系統隨著用戶量增加需要增加機器資源的話,傳統的方式就是找運維申請機器,然后部署好軟件服務接入集群,整個過程依賴的是運維人員的人肉經驗,效率低下而且容易出錯。微服務分布式則無需人肉增加物理機器,在容器化技術的支撐下,我們只需要申請云資源,然后執行容器腳本即可。
有了計算資源后,另外最重要的就是網絡資源了。在現有的云化背景下,我們幾乎不會直接接觸到物理的帶寬資源,而是直接由云平臺統一管理帶寬資源。我們需要的是對網絡資源的最大化應用和有效的管理。
在系統故障的時候我們第一要務是系統恢復,同時保留案發現場也是非常重要的,資源調度平臺則需要有統一的機制保存好故障現場。
在我們建設好分布式系統后,最先受到考驗的關口就是網關了,進而我們需要關注系統流量的情況,也就是如何對流量的管理,我們追求的是在系統可容納的流量上限內,把資源留給最優質的流量使用、把非法惡意的流量擋在門外,這樣節省成本的同時確保系統不會被沖擊崩潰。
負載均衡是我們對服務如何消化流量的通用設計,通常分為物理層的底層協議分流的硬負載均衡和軟件層的軟負載。負載均衡解決方案已經是業界成熟的方案,我們通常會針對特定業務在不同環境進行優化,常用有如下的負載均衡解決方案
負載均衡首當其沖的就是網關,因為中心化集群流量最先打到的地方就是網關了,如果網關扛不住壓力的話,那么整個系統將不可用。
剩下的真實流量我們采用不同的算法來分流請求。
流量分配
所謂打鐵還需自身硬,流量做好了調度管理后,剩下的就是服務自身的健壯性了。分布式系統服務出現故障是常有的事情,甚至我們需要把故障本身當做是分布式服務的一部分。
我們網絡管理一節中介紹了網關,網關是流量的集散地,而注冊中心則是服務的根據地。
服務編排的定義是:通過消息的交互序列來控制各個部分資源的交互。參與交互的資源都是對等的,沒有集中的控制。微服務環境下服務眾多我們需要有一個總的協調器來協議服務之間的依賴,調用關系,K8s 則是我們的不二選擇。
前面我們解決了網絡的健壯性和效率問題,這節介紹的是如何使我們的服務更加健壯。
發現資源管理那節我們介紹了從云平臺申請了容器宿主資源后,通過自動化腳本就可以啟動應用服務,啟動后服務則需要發現注冊中心,并且把自身的服務信息注冊到服務網關,即是網關接入。注冊中心則會監控服務的不同狀態,做健康檢查,把不可用的服務歸類標記。
降級:當用戶激增的時候,我們首先是在流量端做手腳,也就是限流。當我們發現限流后系統響應變慢了,有可能導致更多的問題時,我們也需要對服務本身做一些操作。服務降級就是把當前不是很核心的功能關閉掉,或者不是很要緊的準確性放寬范圍,事后再做一些人工補救。
熔斷:當我們都做了以上的操作后,還是覺得不放心,那么就需要再進一步操心。熔斷是對過載的一種自身保護,猶如我們開關跳閘一樣。比如當我們服務不斷對數據庫進行查詢的時候,如果業務問題造成查詢問題,這是數據庫本身需要熔斷來保證不會被應用拖垮,并且訪問友好的信息,告訴服務不要再盲目調用了。
數據存儲最大的挑戰就是數據冗余的管理,冗余多了效率變低而且占用資源,副本少了起不到災備的作用,我們通常的做法是把有轉態的請求,通過轉態分離,轉化為無狀態請求。
分離狀態至全局存儲,請求轉換為無狀態流量,比如我們通常會將登陸信息緩存至全局 redis 中間件,而不需要在多個應用中去冗余用戶的登陸數據。
數據橫向擴展。
多副本冗余。
我們從資源申請管理的時候就介紹到 devops 的趨勢,真正做到開發運維一體化則需要不同的中間件來配合完成。
全局配置中心按環境來區分,統一管理,減少了多處配置的混亂局面。
微服務分布式部署是家常便飯,如何讓我們的服務更好地支撐業務發展,穩健的部署策略是我們首先需要考慮的,如下的部署策略適合不同業務和不同的階段。
任務調度是系統必不可少的一個環節,傳統的方式是在 Linux 機器上配置 crond 定時任務或者直接在業務代碼里面完成調度業務,現在則是成熟的中間件來代替。
運維工作中很大一部分時間需要對應用進行重啟,上下線操作,還有日志清理。
既然我們知道分布式系統故障是家常便飯,那么應對故障的方案也是不可或缺的環節。通常我們有主動和被動的方式來處理:
重試設計的關鍵在于設計好重試的時間和次數,如果超過重試次數,或是一段時間,那么重試就沒有意義了。開源的項目 spring-retry 可以很好地實現我們重試的計劃。
事務補償符合我們最終一致性的理念。補償事務不一定會將系統中的數據返回到原始操作開始時其所處的狀態。 相反,它補償操作失敗前由已成功完成的步驟所執行的工作。補償事務中步驟的順序不一定與原始操作中步驟的順序完全相反。 例如,一個數據存儲可能比另一個數據存儲對不一致性更加敏感,因而補償事務中撤銷對此存儲的更改的步驟應該會首先發生。對完成操作所需的每個資源采用短期的基于超時的鎖并預先獲取這些資源,這樣有助于增加總體活動成功的可能性。 僅在獲取所有資源后才應執行工作。 鎖過期之前必須完成所有操作。
由于分布式系統是由眾多機器共同協作的系統,而且網絡也無法保證完全可用,所以我們需要建設一套對各個環節都能監控的系統,這樣我們才能從底層到業務各個層面進行監控,出現意外的時候可以及時修復故障,避免更多的問題出現。
基礎層面是對容器資源的監測,包含各個硬件指標的負載情況
分布式系統接入了大量的中間件平臺,中間件本身的健康情況也需要監控。
當故障已經發生后,我們第一個要做的就是馬上消除故障,確保系統服務正??捎?,這個時候通常做回滾操作。
應用回滾之前需要保存好故障現場,以便排查原因。
應用服務回滾后,代碼基線也需要 revert 到前一版本。
整體回滾需要服務編排,通過大版本號對集群進行回滾。
性能優化是分布式系統的大專題,涉及的面非常廣,這塊簡直可以單獨拿出來做一個系列來講,本節就先不展開。本身我們做服務治理的過程也是在性能的優化過程。<br />參考《高并發編程知識體系》
緩存是解決性能問題的一大利器,理想情況下,每個請求不需要額外計算就立刻能獲取到結果時最快。小到 CPU 的三級緩存,大到分布式緩存,緩存無處不在,分布式緩存需要解決的就是數據的一致性,這個時候我們引入了分布式鎖的概念,如何處理分布式鎖的問題將決定我們獲取緩存數據的效率。
多線程編程模式提升了系統的吞吐量,但也同時帶來了業務的復雜度。
事件驅動的異步編程是一種新的編程模式,摒棄了多線程的復雜業務處理問題,同時能夠提升系統的響應效率。
最后總結一下,如果有可能的話,請嘗試使用單節點方式而不是分布式系統。分布式系統伴隨著一些失敗的操作,為了處理災難性故障,我們使用備份;為了提高可靠性,我們引入了冗余。
分布式系統本質就是一堆機器的協同,而我們要做的就是搞出各種手段來然機器的運行達到預期。這么復雜的系統,需要了解各個環節、各個中間件的接入,是一個非常大的工程。慶幸的是,在微服務背景下,多數基礎性的工作已經有人幫我們實現了。前文所描述的分布式架構,在工程實現了是需要用到分布式三件套 (Docker+K8S+Srping Cloud) 基本就可以構建出來了。
分布式架構核心技術分布圖如下:
原圖來源:https://dzone.com/articles/deploying-microservices-spring-cloud-vs-kubernetes
分布式技術棧使用中間件:
原圖來源:https://dzone.com/articles/deploying-microservices-spring-cloud-vs-kubernetes
“ 阿里巴巴云原生微信公眾號(ID:Alicloudnative)關注微服務、Serverless、容器、Service Mesh等技術領域、聚焦云原生流行技術趨勢、云原生大規模的落地實踐,做最懂云原生開發者的技術公眾號?!?/p>
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。