Amazon Dynamo系統架構


Amazon Dynamo系統架構

0x00 摘要

本文參考了網上眾多文章,把 Amazon Dynamo 架構匯總成文,為后續源碼分析奠定基礎。

特此感謝各位作者。

0x01 Amazon Dynamo

亞馬遜在業務發展期間面臨一些問題,主要受限於關系型數據庫的可擴展性和高可用性,因此研發了一套新的、基於 KV 存儲模型的數據庫,將之命名為 Dynamo

相較於傳統的關系型數據庫 MySQLDynamo 的功能目標與之有一些細小的差別,例如: Amazon 的業務場景多數情況並不需要支持復雜查詢,卻要求必要的單節點故障容錯性、數據最終一致性(即犧牲數據強一致優先保障可用性)、較強的可擴展性等。

1.1 概況

在上述功能目標的驅使下,Dynamo 需要解決以下幾個關鍵問題:

  • 它要在 CAP 中做出取舍,Dynamo 選擇犧牲特定情況下的強一致性(這也是大多數新興數據庫的權衡)優先保障可用性;
  • 它需要引入多節點,通過異步數據流復制完成數據備份和冗余,從而支持單節點故障切換、維持集群高可用;
  • 它需要引入某種 “再平衡(rebalance)” 算法來完成集群的自適應管理和擴展操作,Dynamo 選擇了一致性哈希算法;

為了保證其穩定性,Amazon的系統采用完全的分布式、去中心化的架構:

  • 作為底層存儲架構的Dynamo也同樣采用了無中心的模式;
  • Dynamo只支持簡單的鍵/值(key/value)方式的數據存儲,不支持復雜的查詢;
  • Dynamo中存儲的是數據值的原始形式,即按位存儲,並不解析數據的具體內容;

因此,Dynamo 敘述的是一種 NoSQL 數據庫的設計思想和實現方案,它是一個由多節點實例組成的集群,其中一個節點稱之為 Instance(或者 Node 其實無所謂),這個節點由三個模塊組成,分別是請求協調器、Gossip 協議檢測、本地持久化引擎,其中最后一個持久化引擎被設計為可插拔的形式,可以支持不同的存儲介質,例如 BDBMySQL 等。

1.2 主要問題及解決方案

Dynamo在設計時被定位為一個基於分布式存儲架構的,高可靠、高可用且具有良好容錯性的系統。下面列舉了Dynamo設計時面臨的主要問題及所采取的解決方案。

問題 采取的相關技術
數據均衡分布 改進的一致性哈希算法
數據備份 參數可調的弱quorum機制
數據沖突處理 向量時鍾(Vector Clock)
成員資格及錯誤檢測 基於Gossip協議的成員資格和錯誤檢測
臨時故障處理 Hinted handoff(數據回傳機制)
永久故障處理 Merkle哈希樹

1.3 數據均衡分布

數據分片實在是太常見了,因為海量數據無法僅存儲在單一節點上,必須要按照某種規則進行划分之后分開存儲,在 MySQL 中也有分庫分表方案,它本質上就是一種數據分片。

數據分片的邏輯既可以實現在客戶端,也可以實現在 Proxy 層,取決於你的架構如何設計,傳統的數據庫中間件大多將分片邏輯實現在客戶端,通過改寫物理 SQL 訪問不同的 MySQL 庫;而 NewSQL 數據庫倡導的計算存儲分離架構中呢,通常將分片邏輯實現在計算層,即 Proxy 層,通過無狀態的計算節點轉發用戶請求到正確的存儲節點。

1.3.1 Redis 集群的數據分片

Redis 集群也是 NoSQL 數據庫,它是怎么解決哈希映射問題的呢?它啟動時就划分好了 16384 個桶,然后再將這些桶分配給節點占有,數據是固定地往這 16384 個桶里放,至於節點的增減操作,那就是某些桶的重新分配,縮小了數據流動的范圍。

1.3.2 Dynamo 的數據分片

Dynamo 設計之初就考慮到要支持增量擴展,因為節點的增減必須具備很好的可擴展性,盡可能降低期間的數據流動,從而減輕集群的性能抖動。Dynamo 選擇采用一致性哈希算法來處理節點的增刪。

我們想象一下傳統哈希算法的局限是什么,一旦我給定了節點總數 h,那數據划分到哪個節點就固定了(x mod h),此時我一旦增減 h 的大小,那么全部數據的映射關系都要發生改變,解決辦法只能是進行數據遷移,但是一致性哈希可以在一個圓環上優先划分好每個節點負責的數據區域。這樣每次增刪節點,影響的范圍就被局限在一小部分數據。

一致性哈希是存在缺點的,如果僅僅是直接將每個節點映射到一個圓環上,可能造成節點間復雜的范圍有大有小,造成數據分布和機器負載不均衡。因此一致性哈希有個優化舉措,就是引入虛擬節點,其實就是再引入一個中間層解耦,虛擬節點平均落在圓環上,然后實際節點的映射跟某幾個虛擬節點掛鈎,表示我這台物理節點實際負責這些虛擬節點的數據范圍,從而達到平衡負載的作用。

每個虛擬節點都隸屬於某一個實際的物理節點,一個物理節點根據其性能的差異被分為一個或多個虛擬節點。各個虛擬節點的能力基本相當,並隨機分布在哈希環上。

Dynamo將整個哈希環划分成Q等份,每個等份稱為一個數據分區(Partition)。在存儲數據時,每個數據會被先分配到某個數據分區,再根據負責該數據分區的虛擬節點,最終確定其所存儲的物理節點。

1.4 數據復制

數據復制是提升數據庫高可用的常見手段,從實現方式上可分為同步復制、異步復制、半同步復制等,從使用場景上又可分為單向復制、雙向復制、環形復制等。

Dynamo 的設計中為了保證容災,數據被復制到 N 台主機上,N 就是數據的冗余副本數目,還記得我們說過 Dynamo 中每個節點有一個模塊叫做請求協調器么,它接收到某個數據鍵值 K 之后會將其往圓環后的 N - 1 個節點進行復制,保證該鍵值 KN 個副本,因此 Dynamo 中實際上每個節點既存儲自己接收的數據,也存儲為其他節點保留的副本數據。

1.5 讀寫流程

Dynamo 會在數據的所有副本中選取一個作為協調者,由該副本負責轉發讀寫請求和收集反饋結果。通常情況下,該副本是客戶端從內存中維護的 數據 - 節點 映射關系中取得的,將請求直接發往該節點。

對於寫請求,該副本會接收寫請求,並記錄該數據的更新者和時間戳,並將寫請求轉發給其他副本,待 W 個副本反饋寫入完成后向客戶端反饋寫入操作成功;讀取流程類似,轉發讀請求至所有副本,待收到 R 個副本的結果后嘗試選取最新的數據版本,一旦發現數據沖突則保留沖突反饋給客戶端處理。

顯而易見的是,由於協調者是處理讀寫請求的唯一入口,因此該副本所在節點的負載肯定會飆高。

1.6 數據沖突解決

分布式系統架構中通常考慮的三個因素:

  1. 可靠性(Reliability)
  2. 可用性(Availability)
  3. 一致性(Consistency)

Dynamo選擇通過犧牲一致性保證系統的可靠性和可用性 ,沒有采用強一致性模型采用了最終一致性模型

在數據存在 N 個冗余副本的情況下,想要保證強一致需要等待所有副本寫入完成才能返回給客戶端寫入成功,但這是性能有損的,實踐中通常不這么做。Dynamo 允許用戶設置至少寫入 W 個副本才返回,而讀取的時候需要從 R 個副本上讀到值才能返回,因此只要 W + R > N,就能保證一定能讀到正確的值。

但是這有個問題是如何判斷返回的 R 個值中哪個是最新的呢,即每個數據都應該有一個版本信息。Dynamo 為了解決這個問題引入向量時鍾的概念,簡單來說就是每次寫入操作,寫入的副本會為這條數據變更新增一個更新者和版本號的向量組 作為版本信息,在后續的復制流程中也會帶上這部分信息。

由於Dynamo中可能出現同一個數據被多個節點同時更新的情況,且無法保證數據副本的更新順序,這有可能會導致數據沖突

數據沖突問題如何解決?Dynamo中采用了向量時鍾技術(Vector Clock)

Dynamo中的向量時鍾通過[node, counter]對來表示。其中 node 表示操作節點。 counter是其對應的計數器,初始值為 0 節點每進行一次更新操作則計數器加 1。

既然有版本沖突的問題,沖突版本的合並就只能交給上層應用來做

1.7 集群成員狀態監測

Dynamo 想要做到 HA(高可用),除了數據復制之外,還需要定時探測集群節點的可用性,有的業界產品依賴外部服務統一處理,例如 MySQLMHARocketMQNSTiDBPD 等,也有的依賴於節點間自適應管理,例如 Redis 集群和 Dynamo,這二者均采用了 Gossip 協議作為集群間節點信息交換的解決方案,無需引入外部服務,是完全的去中心化的架構。

由於Dynamo采用了無中心的架構,每個成員節點都需要保存其他節點的路由信息。為了保證每個節點都能擁有最新的成員節點信息,Dynamo中采用了一種類似於Gossip(閑聊)協議的技術

Dynamo中還通過Gossip來實現錯誤檢測任何節點向其他節點發起通信后,如果對方沒有回應,則認為對方節點失效

為了避免新加入的節點之間不能及時發現其他節點的存在,Dynamo中設置了一些種子節點(Seed Node)。種子節點和所有的節點都有聯系。當新節點加入時,它扮演一個中介的角色,使新加入節點之間互相感知。

1.8 容錯機制

1.8.1 臨時故障處理機制

為了處理臨時失效的節點,Dynamo中采用了一種帶有監聽的數據回傳機制(Hinted Handoff)。當虛擬節點A失效后,會將數據臨時存放在節點D的臨時空間中,並在節點A重新可用后,由節點D將數據回傳給節點A。

1.8.2 永久性故障處理機制

Dynamo采用Merkle哈希樹技術來加快檢測和減少數據傳輸量。每個虛擬節點保存三顆Merkle樹,即每個鍵值區間建立一個Merkle樹。Dynamo中Merkle哈希樹的葉子節點是存儲每個數據分區內所有數據對應的哈希值,父節點是其所有子節點的哈希值。Merkle樹最大特點是只要比較某個子樹就可以完成數據同步檢測和定位,進而進行同步,大大減少了同步過程中所需傳輸數據量,提高了系統效率。

0x02 NetFlix Dynomite

2.1 概述

Dynomite 是 NetFlix 對亞馬遜分布式存儲引擎 Dynamo 的一個開源通用實現,它不僅支持基於內存的 K/V 數據庫,還支持持久化的 Mysql、BerkeleyDb、LevelDb 等數據庫,並具有簡單、高效、支持跨數據中心的數據復制等優點。Dynomite 的最終目標是提供數據庫存儲引擎不能提供的簡單、高效、跨數據中心的數據復制功能。目前,Dynomite 已經實現了對 Redis 和 Memcached 的支持。

2.1 概念

Dynomite有數據中心、機架、節點的三層概念,數據中心可以有多個機架rack,機架可以有多個節點。每個機架數據是完整的,機架上的不同節點各有一部分數據,即是數據分片。

每個 Dynomite 集群包括多個數據中心(dc),每個數據中心都有一組機架,每個機架包括多個節點,每個機架都包括完整的數據集,該數據集被划分在同一機架的多個節點上。因此,多個機架架構能夠提供更高的可用性的數據服務。機架上的每個節點都有個一個唯一的標示,該標示用來識別節點屬於哪個數據集。每個 Dynomite 節點都有一個 Dynomite process 組件用來協同數據服務器提供服務,該組件具有代理、路由、協調等作用。

可能某些物理機在一個機房或者機架甚至就是一個機器上的幾個虛擬機,那么這些機器之間的通信等速度肯定會更快,這些機器可以組成一個集群,就叫一個rack。

在dynomite拓撲結構中,每個rack都是一個完整集群,每個rack的都擁有完整的數據,多個rack間相互備份,這就達到了高可用。

dynomite結構中,每個rack都是一個一致性hash環,具體規則是rack上每個節點都是個redis master,是可讀寫的。在每個redis節點上都掛載着一個dynomite代理,每個代理持有一個tokens,一致性hash的分配就是根據這個tokens來的,tokens計算規則:從0開始 token = (4294967295 / numberOfNodesInRack) * nodeIndex。每個rack上存在節點都是可以不同的,不需要對應,因為每個rack上的tokens都是重新計算的。
當客戶端的請求到達任意一個dynomite代理后,dynomite會根據tokens計算出這個key是否屬於自己管理的節點,如果不是的話,會把請求發送到對應的dynomite代理上。

同時,還會把這個請求發送到其他的rack的dynomite代理上,以此來完成rack間的數據同步,這個rack間的數據同步時異步的,但是當我們要求強一致性的時候,可以通過配置參數,當有多少個rack完成數據寫入時,才返回結果,根據對一致性要求程度的不同來設置不同的參數。

2.2 數據復制

Dynomite 支持多數據中心的復制,當發送寫操作時,客戶端能夠連接到 Dynomite 集群的任意一個節點。如果 Dynomite 節點恰好接收的數據是屬於本節點的數據時,該數據首先會被寫到本地數據庫服務中,並且異步的復制到所有數據中心的集群中的其他機架中。如果節點接收到不屬於本節點的數據,Dynomite 將會以一個協調者的角色發送寫的操作到相同機架上應該存儲數據的節點上,並復制寫操作到其他機架和數據中心的相應節點上

Dynomite 還具有一個常規、一致性的哈希環,但是復制是不對稱的。Dyno 客戶端的本地寫使用了基於令牌的負載均衡,Dyno 客戶端在相同區域知道 Dynomite 的集群拓撲結構,因此,Dynomite 能夠使用一致性哈希直接將數據寫到一個具體的節點中。

2.3 Redis指令支持度

支持度較高,除了以下情況外未發現其他不支持的指令

  • keys * 、flushall、del key1 key2 等批量執行指令實際上只能處理到Dynomite直接連接的Redis節點的數據。這很好理解,因為批量指令要到多個實例去執行並合並結果,執行時間會較長,而且如果執行結果只有部分正常,合並后的執行結果將會相當復雜。其中keys * 指令會獲取到Dynomite鏈接的Redis實例的key列表
  • 訂閱發布指令不支持,估計也是因為集群下比較難處理
  • 不支持 rename 指令

2.4 優缺點及其應用於生產環境的風險評估

優點

  • 支持多主集群
  • 配置使用相對較為簡單直觀
  • 比起直連Redis性能折損相當少,可以忽略
  • 對Redis的支持度相當高,完全足夠平時開發使用

缺點

  • 集群功能的輔助功能不夠完整,缺少不停機動態擴容功能
  • 缺少內置的數據同步功能,新增節點
  • 缺少內置的數據同步功能,Dynomite或Redis節點故障停機重啟后不會自動從其他節點同步數據
  • 高可用功能有一定缺陷,Dynomite節點對應的Redis掛掉之后,訪問這個節點時,如果key是屬於這個Redis的會直接報錯,不會到其他數據中心拿數據
  • 文檔比較少特別是中文文檔,不夠詳細,比如各類配置的可選項、各配置的關聯互動、異常處理說明、第三方配合使用工具說明很少,
  • 社區不活躍
  • 更新有點慢,4-6個月更新一次代碼

對於數據庫集群方案,以下幾點非常重要

  1. 零侵入:業務系統不需要做任何改造就能接入
  2. 高吞吐量:基於現有業務峰值TPS乘以10,得出TPS要達到1萬
  3. 低延時:多活業務不會出現跨機房讀取數據的情況,所以定的目標延時低於1s。實際情況延時在50ms左右
  4. 高堆積能力:基於跨機房網絡的不確定性,當網絡閃斷時能夠保證指令不丟失
  5. 高可用性:當網絡故障或者Redis宕機恢復時,同步任務能自動恢復
  6. 可配置性:業務系統可以自由定制需要同步哪些Key

Dynomite在第1、2、3 方面做得比較好,第4支持但是有一定缺陷,第5不夠完善,6不支持。

總的來說Dynomite作為集群方案是功能不夠完善,和Redis Cluster相比多了多主功能,但是缺失動態擴容、自動同步數據等功能;高可用方面也有一定缺陷。社區活躍度和文檔都比較欠缺,更新較慢。生產環境使用風險較大。如果實在要用建議搭配Redis Cluster使用以解決動態擴容、新增節點和故障節點自動同步數據等問題,並且應該將其當做緩存集群,避免當做持久化數據庫,特別是用戶數據等核心數據。

0xFF 參考

Amazon基礎存儲架構Dynamo

Dynomite: NetFlix對dynamo的開源通用實現

重讀 Amazon Dynamo 論文有感

基於Dynomite的分布式延遲隊列

Amazon Dynamo論文中文版

Dynomite研究(Netflix數據庫同步工具)

剖析寫一致原理以及相關參數

Quorum 機制

Redis高可用第三方開源集群方案介紹

分布式系統之Quorum機制


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM