大資料分散式儲存之Cassandra
分散式儲存需要考慮的問題
元資料管理
元資料是指資料本身的標識,通過元資料能很快的找到資料儲存的位置,比如在分散式檔案系統中,元資料是指檔案的路徑名+檔名;元資料管理包括集中式元資料管理架構和分散式元資料管理架構;集中式是指將元資料儲存到一個節點上,實現簡單,但具有單點故障和效能瓶頸的問題;分散式元資料架構是將元資料儲存到多個節點上,雖然解決了集中式元資料管理架構的問題,但卻引入了資料一致性的問題,如多節點之間的資料如何保持一致;
彈性伸縮
彈性伸縮需要考慮如下兩種情況:
-
- 某一節點宕機或磁碟壞掉的情況下如何保障系統還能正常執行並且資料不丟失;
- 資料和計算資源的負載均衡:當前資料庫叢集已經無法容納更多的資料時,如何通過加入新的資料節點分攤資料;或當前的資料庫叢集算力已經達到頂峰時,如何通過加入新的節點分攤算力;如何保證計算和資料均勻
效能與成本
高效而合理的儲存結構應在保障資料庫效能的情況下,最大程度降低系統能耗和構建/管理成本;如如何保障資料庫查詢不會掃描整個資料庫叢集?如何在算力、儲存不足的情況下能不加人為干預的動態加入新的節點?
CAP理論
作為分散式儲存系統的奠基石,CAP理論提出了在分散式系統架構過程中必須考慮的三個因素:
-
- C(一致性Consistency):對寫入的資料,分散式系統中的所有的備份節點是否都能得到最新的資料副本;
- A(可用性Availability):對每個讀取/寫入請求,都能得到相應的結果;
- P(分割槽容錯Partition tolerance):分散式叢集中任何節點的宕機都不會影響整個系統的繼續運作;
在分散式儲存系統中,一致性、分割槽容錯、可用性三者很難完全達到,只能滿足其中之二,但分割槽容錯又是必須滿足的,因此CAP最終演變為了CP和AP的對決。
Cassandra
特點
-
去中心化
相對於傳統的集中式元資料管理架構和Master/Slave的分散式資料庫架構,Cassandra採用了P2P(Peer-to-peer對等網路)協議,通過Gossip協議來維護和同步節點資訊;
每隔一秒,資料節點就會從叢集中隨機選擇一個節點,並初始化與它的一個Gossip會話,併發送一個GossipDigestSynMessage;這個節點收到訊息時,會返回一個GossipDigestAckMessage;傳送者收到ACK訊息時,會再次傳送一個GossipDigestAck2Message並結束此輪Gossip會話;
Cassandra採用累積型故障探測
對等網路中分散式一致性問題:
Cassandra使用Paxos共識演算法確保在分散式對等節點裡達成一致結果,而不需要一個主節點協調。
在Paxos演算法中,每個節點都可以擔任協調者的角色,向其他副本節點提議一個新值,每個副本節點會檢查該提議,如果這個提議是它看到的最新的提議,它會承諾不接受與之前任何提議關聯的提議,每個副本節點都會返回它接收到的最新的提議,如果這個提議被大多數副本接受,協調者就會提交這個提議。
-
可調複製一致性級別
Cassandra可通過可調節的一致性級別滿足CP和AP的需要;
寫複製一致性級別(不完全列表)
一致性級別 | 含義 |
ANY | 弱一致性,寫資料時,只要確保這個值能寫入到一個節點即保證寫入成功 |
QUORUM | 確保至少大多數副本(副本因子/2+1) |
ALL | 強一致性,要求要寫入到所有副本,如果有一個副本沒有響應,則操作失敗 |
如果寫複製一致性級別沒有設定為ALL的時候,必然會導致一些副本節點儲存的資料不是最新資料,因此要使用修復功能完成節點間的資料同步:讀修復和逆熵修復;
讀修復是指Cassandra從多個副本讀取出資料,並檢測到某些副本包含過期的資料,如果有最新值的節點數量不夠,就需要進行讀修復來更新那些過期的副本;
逆熵修復是一種在節點上手動的修復方式,通過判斷兩個副本之間Merkle樹是否相等來確定兩個副本的資料是否一致,如果不一致,則進行修復。
讀一致性級別(不完全列表)
一致性級別 | 含義 |
ONE,TWO,THREE | 立即返回響應查詢的第一個節點包含的記錄,建立一個後臺執行緒對這個記錄與其他副本上相同的記錄做比較,如果過期則進行讀修復 |
QUORUM | 查詢所有節點,一旦大多數節點(副本因子/2+1)做出響應,則向客戶端返回最新時間戳的值,必要時進行讀修復 |
ALL | 查詢所有節點,等待所有節點做出響應,向客戶端返回具有最新時間戳的值,必要時進行讀修復 |
-
易操作的資料介面
Cassandra作為NoSQL技術的代表性資料庫,提供了類似於SQL語言的CQL查詢語言,比如建立一個user表:
CREATE TABLE user(first_name text, last_name text, PRIMARY KEY(first_name));
當需要向user表中插入一條記錄時,可以使用下面的指令碼:
INSERT INTO user(first_name, last_name) VALUES('Bill', 'Nguyen');
當要進行資料查詢時,可以使用:
SELECT COUNT(*) FROM user;
資料分佈
在早期的Cassandra版本中,將這個叢集中的節點連線為一個環,併為環中的每個物理節點分配一個數據區間或範圍,由一個令牌來表示,通過這個令牌來確定資料在環中的位置:
當插入資料時,會通過一個Hash函式計算得到要插入資料的Hash值,通過這個Hash值得到這個資料在環中所處的位置或區間,並確定擁有這個資料的節點;但採用這種方式會存在一個問題,即增加或替換節點會有非常大的開銷,再平衡資料分佈時會移動大量的資料;
因此在Cassandra後期的版本中引入了虛擬節點,即不再為物理節點分配一個令牌,而將令牌區間分解為多個小區間(每個小區間對應一個虛擬節點),這樣每個物理節點就會被分配多個虛擬節點;在增加或替換節點時只需要遷移相應的虛擬節點即可。
高效能的寫操作
-
寫日誌優先
Cassandra進行寫操作時,會優先寫入提交日誌,提交日誌是支援Cassandra永續性目標的一種失敗恢復機制;
-
基於記憶體寫的資料結構
在提交日誌成功之後,值會被寫入到一個記憶體的資料結構中,這個記憶體結構稱之為memtable,每個表都會有一個或多個獨立的memtable;
當儲存在memtable中的記錄數量達到一個閾值的時候,memtable中的內容會被刷到磁盤裡一個名為SSTable的檔案中,然後再建立一個新的memtable;刷盤是非阻塞操作,與資料寫入可以同時進行;在memtable刷入成功之後會刪除掉對應的日誌;
-
資料合併
Cassandra對資料的寫操作都是以追加的方式順序進行,並不需要任何讀或者查詢操作,這就會導致同一條資料的操作分佈到多個SSTable中;同時SSTable是不可變的;
Cassandra的刪除操作並不是立即刪除,只是在值上放置一個墓碑,墓碑相當於刪除標誌,等到可以執行合併的時候,才真正刪除Cassandra中的老資料;
合併觸發的條件:每個層級下面會有多個SSTable,當某個層級的SSTable檔案數量達到Threshold之後,會將該層級的SSTable與上一層級的SSTable檔案合併,並寫入到新的SSTable中;合併過程中,鍵會歸併、列會組合、墓碑將會被刪除。
增強式的讀操作
由於對資料的更新都是順序,勢必會導致對同一條記錄多次更新的資料會落入到多個SSTable或MemTable中。
為提高查詢的速度,Cassandra使用BloomFilter檢測記錄是否存在於SSTable中,由於BloomFilter存在誤報的現象(不存在的記錄判斷為存在),可通過增加過濾器記憶體大小減少誤報率。
我的豆瓣賬號:https://www.douban.com/people/joenzhang