作者 | 曉土 阿里巴巴高階工程師
姊妹篇閱讀推薦:《雲原生時代,分散式系統設計必備知識圖譜(內含22個知識點)》
導讀:本文力求從分散式基礎理論、架構設計模式、工程應用、部署運維、業界方案這幾大方面,介紹基於 MSA(微服務架構)的分散式知識體系大綱,從而對 SOA 到 MSA 進化有著立體的認識;從概念上和工具應用上更近一步瞭解微服務分散式的本質,身臨其境的感受如何搭建全套微服務架構的過程。
關注“阿里巴巴雲原生”公眾號,回覆“分佈”,即可下載分散式系統及其知識體系清晰大圖!
隨著移動網際網路的發展和智慧終端的普及,計算機系統早就從單機獨立工作過渡到多機器協作,叢集按照分散式理論構建出龐大複雜的應用服務,在分散式的基礎上正進行一場雲原生的技術革命,徹底打破傳統的開發方式,解放了新一代的生產力。
分散式系統知識體系大圖
關注“阿里巴巴雲原生”公眾號,回覆“分佈”,即可下載分散式系統及其知識體系清晰大圖!
基礎理論
SOA 到 MSA 的進化
SOA 面向服務架構
由於業務發展到一定程度後,需要對服務進行解耦,進而把一個單一的大系統按邏輯拆分成不同的子系統,通過服務介面來通訊。面向服務的設計模式,最終需要匯流排整合服務,而且大部分時候還共享資料庫,出現單點故障時會導致匯流排層面的故障,更進一步可能會把資料庫拖垮,所以才有了更加獨立的設計方案的出現。
MSA 微服務架構
微服務是真正意義上的獨立服務,從服務入口到資料持久層,邏輯上都是獨立隔離的,無需服務匯流排來接入,但同時也增加了整個分散式系統的搭建和管理難度,需要對服務進行編排和管理,所以伴隨著微服務的興起,微服務生態的整套技術棧也需要無縫接入,才能支撐起微服務的治理理念。
節點與網路
節點
傳統的節點也就是一臺單體的物理機,所有的服務都揉進去包括服務和資料庫;隨著虛擬化的發展,單臺物理機往往可以分成多臺虛擬機器,實現資源利用的最大化,節點的概念也變成單臺虛擬機器上面服務;近幾年容器技術逐漸成熟後,服務已經徹底容器化,也就是節點只是輕量級的容器服務。總體來說,節點就是能提供單位服務的邏輯計算資源的集合。
網路
分散式架構的根基就是網路,不管是區域網還是公網,沒有網路就無法把計算機聯合在一起工作,但是網路也帶來了一系列的問題。網路訊息的傳播有先後,訊息丟失和延遲是經常發生的事情,我們定義了三種網路工作模式:
- 同步網路
- 節點同步執行
- 訊息延遲有限
- 高效全域性鎖
- 半同步網路
- 鎖範圍放寬
- 非同步網路
- 節點獨立執行
- 訊息延遲無上限
- 無全域性鎖
- 部分演算法不可行
常用網路傳輸層有兩大協議的特點簡介:
- TCP 協議
- 首先 tcp 協議傳輸可靠,儘管其他的協議可以更快傳輸
- tcp 解決重複和亂序問題
- UDP 協議
- 常量資料流
- 丟包不致命
時間與順序
時間
慢速物理時空中,時間獨自在流淌著,對於序列的事務來說,很簡單的就是跟著時間的腳步走就可以,先來後到的發生。而後我們發明了時鐘來刻畫以往發生的時間點,時鐘讓這個世界井然有序。但是對於分散式世界來說,跟時間打交道著實是一件痛苦的事情。
分散式世界裡面,我們要協調不同節點之間的先來後到關係,不同節點本身承認的時間又各執己見,於是我們創造了網路時間協議(NTP)試圖來解決不同節點之間的標準時間,但是 NTP 本身表現並不盡如人意,所以我們又構造出了邏輯時鐘,最後改進為向量時鐘:
- NTP 的一些缺點,無法完全滿足分散式下併發任務的協調問題
- 節點間時間不同步
- 硬體時鐘漂移
- 執行緒可能休眠
- 作業系統休眠
- 硬體休眠
- 邏輯時鐘
- 定義事件先來後到
- t' = max(t, t_msg + 1)
- 向量時鐘
- t_i' = max(t_i, t_msg_i)
- 原子鐘
順序
有了衡量時間的工具,解決順序問題自然就是水到渠成了。因為整個分散式的理論基礎就是如何協商不同節點的一致性問題,而順序則是一致性理論的基本概念,所以前文我們才需要花時間介紹衡量時間的刻度和工具。
一致性理論
說到一致性理論,我們必須看一張關於一致性強弱對系統建設影響的對比圖:
該圖對比了不同一致性演算法下的事務、效能、錯誤、延遲的平衡。
強一致性 ACID
單機環境下我們對傳統關係型資料庫有苛刻的要求,由於存在網路的延遲和訊息丟失,ACID 便是保證事務的原則,這四大原則甚至我們都不需要解釋出來就耳熟能詳了:
- Atomicity:原子性,一個事務中的所有操作,要麼全部完成,要麼全部不完成,不會結束在中間某個環節;
- Consistency:一致性,在事務開始之前和事務結束以後,資料庫的完整性沒有被破壞;
- Isolation:隔離性,資料庫允許多個併發事務同時對其資料進行讀寫和修改的能力,隔離性可以防止多個事務併發執行時,由於交叉執行而導致資料的不一致;
- Durabilit:事務處理結束後,對資料的修改就是永久的,即便系統故障也不會丟失。
分散式一致性 CAP
分散式環境下,我們無法保證網路的正常連線和資訊的傳送,於是發展出了 CAP/FLP/DLS 這三個重要的理論:
- CAP:分散式計算系統不可能同時確保一致性(Consistency)、可用性(Availablity)和分割槽容忍性(Partition);
- FLP:在非同步環境中,如果節點間的網路延遲沒有上限,只要有一個惡意的節點存在,就沒有演算法能在有限的時間內達成共識;
- DLS:
- 在一個部分同步網路的模型(也就是說:網路延時有界限但是我們並不知道在哪裡)下執行的協議可以容忍 1/3 任意(換句話說,拜占庭)錯誤;
- 在一個非同步模型中的確定性的協議(沒有網路延時上限)不能容錯(不過這個論文沒有提起隨機化演算法可以容忍 1/3 的錯誤);
- 同步模型中的協議(網路延時可以保證小於已知 d 時間),可以令人吃驚的達到 100% 容錯,雖然對 1/2 的節點出錯可以發生的情況有所限制。
弱一致性 BASE
多數情況下,其實我們也並非一定要求強一致性,部分業務可以容忍一定程度的延遲一致,所以為了兼顧效率,發展出來了最終一致性理論 BASE。BASE 是指基本可用(Basically Available)、軟狀態( Soft State)、最終一致性( Eventual Consistency):
- 基本可用(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
- 基於狀態(state-based):即將各個節點之間的 CRDT 資料直接進行合併,所有節點都能最終合併到同一個狀態,資料合併的順序不會影響到最終的結果;
- 基於操作(operation-based):將每一次對資料的操作通知給其他節點。只要節點知道了對資料的所有操作(收到操作的順序可以是任意的),就能合併到同一個狀態。
瞭解資料結構後,我們需要來關注一下分散式系統的一些重要的***協議***HATs(Highly Available Transactions),ZAB(Zookeeper Atomic Broadcast): 參考《高可用事務》,《ZAB 協議分析》
最後要學習的是業界主流的一致性演算法 : 說實話具體的演算法我也還沒完全搞懂,一致性演算法是分散式系統最核心本質的內容,這部分的發展也會影響架構的革新,不同場景的應用也催生不同的演算法。
- Paxos:《優雅的Paxos演算法》
- Raft :《Raft 一致性演算法》
- Gossip:《Gossip Visualization》
這一節我們說完分散式系統裡面核心理論基礎,如何達成不同節點之間的資料一致性,下面我們將會講到目前都有哪些主流的分散式系統。
場景分類
檔案系統
單臺計算機的儲存始終有上限,隨著網路的出現,多臺計算機協作儲存檔案的方案也相繼被提出來。最早的分散式檔案系統其實也稱為網路檔案系統,第一個檔案伺服器在 1970 年代被髮展出來。在 1976 年迪吉多公司設計出 File Access Listener(FAL),而現代分散式檔案系統則出自赫赫有名的 Google 的論文,《The Google File System》奠定了分散式檔案系統的基礎。現代主流分散式檔案系統參考《分散式檔案系統對比》,下面列舉幾個常用的檔案系統:
- HDFS
- FastDFS
- Ceph
- mooseFS
資料庫
資料庫當然也屬於檔案系統,主資料增加了事務、檢索、擦除等高階特性,所以複雜度又增加了,既要考慮資料一致性也得保證足夠的效能。傳統關係型資料庫為了兼顧事務和效能的特性,在分散式方面的發展有限,非關係型資料庫擺脫了事務的強一致性束縛,達到了最終一致性的效果,從而有了飛躍的發展,NoSql(Not Only Sql) 也產生了多個架構的資料庫型別,包括 KV、列式儲存、文件型別等。
- 列式儲存:Hbase
- 文件儲存:Elasticsearch,MongoDB
- KV 型別:Redis
- 關係型:Spanner
計算
分散式計算系統構建在分散式儲存的基礎上,充分發揮分散式系統的資料冗餘災備,多副本高效獲取資料的特性,進而平行計算,把原本需要長時間計算的任務拆分成多個任務並行處理,從而提高了計算效率。分散式計算系統在場景上分為離線計算、實時計算和流式計算。
- 離線:Hadoop
- 實時:Spark
- 流式:Storm,Flink/Blink
快取
快取作為提升效能的利器無處不在,小到 CPU 快取架構,大到分散式應用儲存。分散式快取系統提供了熱點資料的隨機訪問機制,大大了提升了訪問時間,但是帶來的問題是如何保證資料的一致性,引入分散式鎖來解決這個問題,主流的分散式儲存系統基本就是 Redis 了。
- 持久化:Redis
- 非持久化:Memcache
訊息
分散式訊息佇列系統是消除非同步帶來的一系列複雜步驟的一大利器,在多執行緒高併發場景下,我們常常需要謹慎設計業務程式碼,來保證多執行緒併發情況下不出現資源競爭導致的死鎖問題。而訊息佇列以一種延遲消費的模式將非同步任務都存到佇列,然後再逐個消化。
- Kafka
- RabbitMQ
- RocketMQ
- ActiveMQ
監控
分散式系統從單機到叢集的形態發展,複雜度也大大提高,所以對整個系統的監控也是必不可少。
- Zookeeper
應用
分散式系統的核心模組就是在應用如何處理業務邏輯,應用直接的呼叫依賴於特定的協議來通訊,有基於 RPC 協議的,也有基於通用的 HTTP 協議。
- HSF
- Dubbo
日誌
錯誤對應分散式系統是家常便飯,而且我們設計系統的時候,本身就需要把容錯作為普遍存在的現象來考慮。那麼當出現故障的時候,快速恢復和排查故障就顯得非常重要了。分散式日誌採集儲存和檢索則可以給我們提供有力的工具來定位請求鏈路中出現問題的環節。
- 日誌採集:flume
- 日誌儲存:ElasticSearch/Solr,SLS
- 日誌定位:Zipkin
賬本
前文我們提到所謂分散式系統,是迫於單機的效能有限,而堆硬體卻又無法無休止的增加,單機堆硬體最終也會遇到效能增長曲線的瓶頸。於是我們才採用了多臺計算機來幹同樣的活,但是這樣的分散式系統始終需要中心化的節點來監控或者排程系統的資源,即使該中心節點也可能是多節點組成。區塊鏈則是真正的區中心化分散式系統,系統裡面只有 P2P 網路協議各自通訊,沒有真正意義的中心節點,彼此按照區塊鏈節點的算力、權益等機制來協調新區塊的產生。
- 比特幣
- 以太坊
設計模式
上節我們列舉了不同場景下不同分散式系統架構扮演的角色和實現的功能,本節我們更進一步歸納分散式系統設計的時候是如何考慮架構設計的、不同設計方案直接的區別和側重點、不同場景需要選擇合作設計模式,來減少試錯的成本,設計分散式系統需要考慮以下的問題。
可用性
可用性是系統執行和工作的時間比例,通常以正常執行時間的百分比來衡量。它可能受系統錯誤、基礎架構問題、惡意攻擊和系統負載的影響。分散式系統通常為使用者提供服務級別協議(SLA),因此應用程式必須設計為最大化可用性。
- 健康檢查:系統實現全鏈路功能檢查,外部工具定期通過公開端點訪問系統
- 負載均衡:使用佇列起到削峰作用,作為請求和服務之間的緩衝區,以平滑間歇性的重負載
- 節流:限制應用級別、租戶或整個服務所消耗資源的範圍
資料管理
資料管理是分散式系統的關鍵要素,並影響大多數質量的屬性。由於效能,可擴充套件性或可用性等原因,資料通常託管在不同位置和多個伺服器上,這可能帶來一系列挑戰。例如,必須維護資料一致性,並且通常需要跨不同位置同步資料。
- 快取:根據需要將資料從資料儲存層載入到快取
- CQRS(Command Query Responsibility Segregation): 命令查詢職責分離
- 事件溯源:僅使用追加方式記錄域中完整的系列事件
- 索引表:在經常查詢引用的欄位上建立索引
- 物化檢視:生成一個或多個資料預填充檢視
- 拆分:將資料拆分為水平的分割槽或分片
設計與實現
良好的設計包括諸如元件設計和部署的一致性、簡化管理和開發的可維護性、以及允許元件和子系統用於其他應用程式和其他方案的可重用性等因素。在設計和實施階段做出的決策對分散式系統和服務質量和總體擁有成本產生巨大影響。
- 代理:反向代理
- 介面卡: 在現代應用程式和遺留系統之間實現介面卡層
- 前後端分離: 後端服務提供介面供前端應用程式呼叫
- 計算資源整合:將多個相關任務或操作合併到一個計算單元中
- 配置分離:將配置資訊從應用程式部署包中移出到配置中心
- 閘道器聚合:使用閘道器將多個單獨的請求聚合到一個請求中
- 閘道器解除安裝:將共享或專用服務功能解除安裝到閘道器代理
- 閘道器路由:使用單個端點將請求路由到多個服務
- 領導人選舉:通過選擇一個例項作為負責管理其他例項管理員,協調分散式系統的雲
- 管道和過濾器:將複雜的任務分解為一系列可以重複使用的單獨元件
- 邊車:將應用的監控元件部署到單獨的程式或容器中,以提供隔離和封裝
- 靜態內容託管:將靜態內容部署到 CDN,加速訪問效率
訊息
分散式系統需要一個連線元件和服務的訊息傳遞中介軟體,理想情況是以鬆散耦合的方式,以便最大限度地提高可伸縮性。非同步訊息傳遞被廣泛使用,並提供許多好處,但也帶來了諸如訊息排序,冪等性等挑戰
- 競爭消費者:多執行緒併發消費
- 優先順序佇列: 訊息佇列分優先順序,優先順序高的先被消費
管理與監控
分散式系統在遠端資料中心執行,無法完全控制基礎結構,這使管理和監視比單機部署更困難。應用必須公開執行時資訊,管理員可以使用這些資訊來管理和監視系統,以及支援不斷變化的業務需求和自定義,而無需停止或重新部署應用。
效能與擴充套件
效能表示系統在給定時間間隔內執行任何操作的響應性,而可伸縮性是系統處理負載增加而不影響效能或容易增加可用資源的能力。分散式系統通常會遇到變化的負載和活動高峰,特別是在多租戶場景中,幾乎是不可能預測的。相反,應用應該能夠在限制範圍內擴充套件以滿足需求高峰,並在需求減少時進行擴充套件。可伸縮性不僅涉及計算例項,還涉及其他元素,如資料儲存、訊息佇列等。
彈性
彈性是指系統能夠優雅地處理故障並從故障中恢復。分散式系統通常是多租戶,使用共享平臺服務、競爭資源和頻寬,通過 Internet 進行通訊,以及在商用硬體上執行,意味著出現瞬態和更永久性故障的可能性增加。為了保持彈性,必須快速有效地檢測故障並進行恢復。
- 隔離:將應用程式的元素隔離到池中,以便在其中一個失敗時,其他元素將繼續執行
- 斷路器:處理連線到遠端服務或資源時可能需要不同時間修復的故障
- 補償交易:撤消一系列步驟執行的工作,這些步驟共同定義最終一致的操作
- 健康檢查:系統實現全鏈路功能檢查,外部工具定期通過公開端點訪問系統
- 重試:通過透明地重試先前失敗的操作,使應用程式在嘗試連線到服務或網路資源時處理預期的臨時故障
安全
安全性是系統能夠防止在設計使用之外的惡意或意外行為,並防止洩露或丟失資訊。分散式系統在受信任的本地邊界之外的 Internet 上執行,通常向公眾開放,並且可以為不受信任的使用者提供服務。必須以保護應用程式免受惡意攻擊,限制僅允許對已批准使用者的訪問,並保護敏感資料。
- 聯合身份:將身份驗證委派給外部身份提供商
- 看門人: 通過使用專用主機例項來保護應用程式和服務,該例項充當客戶端與應用程式或服務之間的代理,驗證和清理請求,並在它們之間傳遞請求和資料
- 代客鑰匙:使用為客戶端提供對特定資源或服務的受限直接訪問的令牌或金鑰
工程應用
前文我們介紹了分散式系統的核心理論,面臨的一些難題和解決問題的折中思路,羅列了現有主流分散式系統的分類,而且歸納了建設分散式系統的一些方法論,那麼接下來我們將從工程角度來介紹真刀真槍搭建分散式系統包含的內容和步驟。
資源排程
巧婦難為無米之炊,我們一切的軟體系統都是構建在硬體伺服器的基礎上。從最開始的物理機直接部署軟體系統,到虛擬機器的應用,最後到了資源上雲容器化,硬體資源的使用也開始了集約化的管理。本節對比的是傳統運維角色對應的職責範圍,在 devops 環境下,開發運維一體化,我們要實現的也是資源的靈活高效使用。
彈性伸縮
過去軟體系統隨著使用者量增加需要增加機器資源的話,傳統的方式就是找運維申請機器,然後部署好軟體服務接入叢集,整個過程依賴的是運維人員的人肉經驗,效率低下而且容易出錯。微服務分散式則無需人肉增加物理機器,在容器化技術的支撐下,我們只需要申請雲資源,然後執行容器指令碼即可。
- 應用擴容:使用者激增需要對服務進行擴充套件,包括自動化擴容,峰值過後的自動縮容
- 機器下線:對於過時應用,進行應用下線,雲平臺收回容器宿主資源
- 機器置換:對於故障機器,可供置換容器宿主資源,服務自動啟動,無縫切換
網路管理
有了計算資源後,另外最重要的就是網路資源了。在現有的雲化背景下,我們幾乎不會直接接觸到物理的頻寬資源,而是直接由雲平臺統一管理頻寬資源。我們需要的是對網路資源的最大化應用和有效的管理。
- 域名申請:應用申請配套域名資源的申請,多套域名對映規則的規範
- 域名變更:域名變更統一平臺管理
- 負載管理:多機應用的訪問策略設定
- 安全外聯:基礎訪問鑑權,攔截非法請求
- 統一接入:提供統一接入的許可權申請平臺,提供統一的登入管理
故障快照
在系統故障的時候我們第一要務是系統恢復,同時保留案發現場也是非常重要的,資源排程平臺則需要有統一的機制儲存好故障現場。
- 現場保留:記憶體分佈,執行緒數等資源現象的儲存,如 JavaDump 鉤子接入
- 除錯接入:採用位元組碼技術無需入侵業務程式碼,可以供生產環境現場日誌打點除錯
流量排程
在我們建設好分散式系統後,最先受到考驗的關口就是閘道器了,進而我們需要關注系統流量的情況,也就是如何對流量的管理,我們追求的是在系統可容納的流量上限內,把資源留給最優質的流量使用、把非法惡意的流量擋在門外,這樣節省成本的同時確保系統不會被衝擊崩潰。
負載均衡
負載均衡是我們對服務如何消化流量的通用設計,通常分為物理層的底層協議分流的硬負載均衡和軟體層的軟負載。負載均衡解決方案已經是業界成熟的方案,我們通常會針對特定業務在不同環境進行優化,常用有如下的負載均衡解決方案
- 交換機
- F5
- LVS/ALI-LVS
- Nginx/Tengine
- VIPServer/ConfigServer
閘道器設計
負載均衡首當其衝的就是閘道器,因為中心化叢集流量最先打到的地方就是閘道器了,如果閘道器扛不住壓力的話,那麼整個系統將不可用。
- 高效能:閘道器設計第一需要考慮的是高效能的流量轉發,閘道器單節點通常能達到上百萬的併發流量
- 分散式:出於流量壓力分擔和災備考慮,閘道器設計同樣需要分散式
- 業務篩選:閘道器同設計簡單的規則,排除掉大部分的惡意流量
流量管理
- 請求校驗:請求鑑權可以把多少非法請求攔截,清洗
- 資料快取:多數無狀態的請求存在資料熱點,所以採用 CDN 可以把相當大一部分的流量消費掉
流控控制
剩下的真實流量我們採用不同的演算法來分流請求。
-
流量分配
- 計數器
- 佇列
- 漏斗
- 令牌桶
- 動態流控
-
流量限制在流量激增的時候,通常我們需要有限流措施來防止系統出現雪崩,那麼就需要預估系統的流量上限,然後設定好上限數,但流量增加到一定閾值後,多出來的流量則不會進入系統,通過犧牲部分流量來保全系統的可用性。
- 限流策略
- QPS 粒度
- 執行緒數粒度
- RT 閾值
- 限流工具 - Sentinel
服務排程
所謂打鐵還需自身硬,流量做好了排程管理後,剩下的就是服務自身的健壯性了。分散式系統服務出現故障是常有的事情,甚至我們需要把故障本身當做是分散式服務的一部分。
註冊中心
我們網路管理一節中介紹了閘道器,閘道器是流量的集散地,而註冊中心則是服務的根據地。
- 狀態型別:第一好應用服務的狀態,通過註冊中心就可以檢測服務是否可用
- 生命週期:應用服務不同的狀態組成了應用的生命週期
版本管理
- 叢集版本:叢集不用應用有自身對應的版本號,由不同服務組成的叢集也需要定義大的版本號
- 版本回滾:在部署異常的時候可以根據大的叢集版本進行回滾管理
服務編排
服務編排的定義是:通過訊息的互動序列來控制各個部分資源的互動。參與互動的資源都是對等的,沒有集中的控制。微服務環境下服務眾多我們需要有一個總的協調器來協議服務之間的依賴,呼叫關係,K8s 則是我們的不二選擇。
- K8s
- Spring Cloud
- HSF
- ZK+Dubbo
服務控制
前面我們解決了網路的健壯性和效率問題,這節介紹的是如何使我們的服務更加健壯。
-
發現資源管理那節我們介紹了從雲平臺申請了容器宿主資源後,通過自動化指令碼就可以啟動應用服務,啟動後服務則需要發現註冊中心,並且把自身的服務資訊註冊到服務閘道器,即是閘道器接入。註冊中心則會監控服務的不同狀態,做健康檢查,把不可用的服務歸類標記。
- 閘道器接入
- 健康檢查
-
降級:當使用者激增的時候,我們首先是在流量端做手腳,也就是限流。當我們發現限流後系統響應變慢了,有可能導致更多的問題時,我們也需要對服務本身做一些操作。服務降級就是把當前不是很核心的功能關閉掉,或者不是很要緊的準確性放寬範圍,事後再做一些人工補救。
- 降低一致性約束
- 關閉非核心服務
- 簡化功能
-
熔斷:當我們都做了以上的操作後,還是覺得不放心,那麼就需要再進一步操心。熔斷是對過載的一種自身保護,猶如我們開關跳閘一樣。比如當我們服務不斷對資料庫進行查詢的時候,如果業務問題造成查詢問題,這是資料庫本身需要熔斷來保證不會被應用拖垮,並且訪問友好的資訊,告訴服務不要再盲目呼叫了。
- 閉合狀態
- 半開狀態
- 斷開狀態
- 熔斷工具- Hystrix
-
冪等:我們知道,一個冪等操作的特點是其任意多次執行所產生的影響均與一次執行的影響相同。那麼就需要對單次操作賦予一個全域性的 id 來做標識,這樣多次請求後我們可以判斷來源於同個客戶端,避免出現髒資料。
- 全域性一致性 ID
- Snowflake
資料排程
資料儲存最大的挑戰就是資料冗餘的管理,冗餘多了效率變低而且佔用資源,副本少了起不到災備的作用,我們通常的做法是把有轉態的請求,通過轉態分離,轉化為無狀態請求。
狀態轉移
分離狀態至全域性儲存,請求轉換為無狀態流量,比如我們通常會將登陸資訊快取至全域性 redis 中介軟體,而不需要在多個應用中去冗餘使用者的登陸資料。
分庫分表
資料橫向擴充套件。
分片分割槽
多副本冗餘。
自動化運維
我們從資源申請管理的時候就介紹到 devops 的趨勢,真正做到開發運維一體化則需要不同的中介軟體來配合完成。
配置中心
全域性配置中心按環境來區分,統一管理,減少了多處配置的混亂局面。
- switch
- diamend
部署策略
微服務分散式部署是家常便飯,如何讓我們的服務更好地支撐業務發展,穩健的部署策略是我們首先需要考慮的,如下的部署策略適合不同業務和不同的階段。
- 停機部署
- 滾動部署
- 藍綠部署
- 灰度部署
- A/B 測試
作業排程
任務排程是系統必不可少的一個環節,傳統的方式是在 Linux 機器上配置 crond 定時任務或者直接在業務程式碼裡面完成排程業務,現在則是成熟的中介軟體來代替。
- SchedulerX
- Spring 定時任務
應用管理
運維工作中很大一部分時間需要對應用進行重啟,上下線操作,還有日誌清理。
- 應用重啟
- 應用下線
- 日誌清理
容錯處理
既然我們知道分散式系統故障是家常便飯,那麼應對故障的方案也是不可或缺的環節。通常我們有主動和被動的方式來處理:
- 主動是在錯誤出現的時候,我們試圖再試試幾次,說不定就成功了,成功的話就可以避免了該次錯誤
- 被動方式是錯誤的事情已經發生了,為了挽回,我們只是做時候處理,把負面影響降到最小
重試設計
重試設計的關鍵在於設計好重試的時間和次數,如果超過重試次數,或是一段時間,那麼重試就沒有意義了。開源的專案 spring-retry 可以很好地實現我們重試的計劃。
事務補償
事務補償符合我們最終一致性的理念。補償事務不一定會將系統中的資料返回到原始操作開始時其所處的狀態。 相反,它補償操作失敗前由已成功完成的步驟所執行的工作。補償事務中步驟的順序不一定與原始操作中步驟的順序完全相反。 例如,一個資料儲存可能比另一個資料儲存對不一致性更加敏感,因而補償事務中撤銷對此儲存的更改的步驟應該會首先發生。對完成操作所需的每個資源採用短期的基於超時的鎖並預先獲取這些資源,這樣有助於增加總體活動成功的可能性。 僅在獲取所有資源後才應執行工作。 鎖過期之前必須完成所有操作。
全棧監控
由於分散式系統是由眾多機器共同協作的系統,而且網路也無法保證完全可用,所以我們需要建設一套對各個環節都能監控的系統,這樣我們才能從底層到業務各個層面進行監控,出現意外的時候可以及時修復故障,避免更多的問題出現。
基礎層
基礎層面是對容器資源的監測,包含各個硬體指標的負載情況
- CPU、IO、記憶體、執行緒、吞吐
中介軟體
分散式系統接入了大量的中介軟體平臺,中介軟體本身的健康情況也需要監控。
應用層
- 效能監控:應用層面的需要對每個應用服務的實時指標(qps,rt),上下游依賴等進行監控
- 業務監控:除了應用本身的監控程度,業務監控也是保證系統正常的一個環節,通過設計合理的業務規則,對異常的情況做報警設定
監控鏈路
- zipkin/eagleeye
- sls
- goc
- Alimonitor
故障恢復
當故障已經發生後,我們第一個要做的就是馬上消除故障,確保系統服務正常可用,這個時候通常做回滾操作。
應用回滾
應用回滾之前需要儲存好故障現場,以便排查原因。
基線回退
應用服務回滾後,程式碼基線也需要 revert 到前一版本。
版本回滾
整體回滾需要服務編排,通過大版本號對叢集進行回滾。
效能調優
效能優化是分散式系統的大專題,涉及的面非常廣,這塊簡直可以單獨拿出來做一個系列來講,本節就先不展開。本身我們做服務治理的過程也是在效能的優化過程。
參考《高併發程式設計知識體系》
分散式鎖
快取是解決效能問題的一大利器,理想情況下,每個請求不需要額外計算就立刻能獲取到結果時最快。小到 CPU 的三級快取,大到分散式快取,快取無處不在,分散式快取需要解決的就是資料的一致性,這個時候我們引入了分散式鎖的概念,如何處理分散式鎖的問題將決定我們獲取快取資料的效率。
高併發
多執行緒程式設計模式提升了系統的吞吐量,但也同時帶來了業務的複雜度。
非同步
事件驅動的非同步程式設計是一種新的程式設計模式,摒棄了多執行緒的複雜業務處理問題,同時能夠提升系統的響應效率。
總結
最後總結一下,如果有可能的話,請嘗試使用單節點方式而不是分散式系統。分散式系統伴隨著一些失敗的操作,為了處理災難性故障,我們使用備份;為了提高可靠性,我們引入了冗餘。
分散式系統本質就是一堆機器的協同,而我們要做的就是搞出各種手段來然機器的執行達到預期。這麼複雜的系統,需要了解各個環節、各個中介軟體的接入,是一個非常大的工程。慶幸的是,在微服務背景下,多數基礎性的工作已經有人幫我們實現了。前文所描述的分散式架構,在工程實現了是需要用到分散式三件套 (Docker+K8S+Srping Cloud) 基本就可以構建出來了。
分散式架構核心技術分佈圖如下:
分散式技術棧使用中介軟體:
“ 阿里巴巴雲原生微信公眾號(ID:Alicloudnative)關注微服務、Serverless、容器、Service Mesh等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,做最懂雲原生開發者的技術公眾號。”