聊聊Cassandra-概覽
如果你想學習分布式係統,Cassandra可以說是一個好的開始。 Cassandra借鑒了兩篇重要的論文中的思想:Google的BigTable和Amazon的Dynamo。它的存儲基於BigTable,分布式基於Dynamo。這篇文章將嚐試解釋整體架構中的一些細節。
數據模型(Data Model)
在關係型數據庫中的一些常見術語在Cassandra中則有不同的定義。如果你能暫時忘記常規的定義,則閱讀本文可能會更加順利。
列(Colunmn)
“列”由一個name,一個相關的value和一個時間戳組成。name和value可以是任何類型,name不需要是字符串。一個列就是一個Name-Value-Timestamp集合。
列族(Column Family)
可以想象成在關係數據庫中一行所包含的一個key和一些列。
超列族(Super Column Family)
就是一個列族,這個列族中每個列的值就是一個列的集合。
大家可能會有些疑惑,可以看看下麵的圖片:
對Column Family再多說兩句。一個column family 可以被定義為一個有序rows的集合,每個row都包含了一個有序的columns的集合。Cassandra是一個自由的模式,之後你可以在任意時刻添加任意column到任意column family中。Columns不需要相同,並且每行都不需要有相同數量的columns。盡管這樣,在相同的column family有相同的columns還是比較好的,因為每個column family都存儲在一個單獨的文件中。
一個column family 有一個name和一個比較器,比較器的的值決定了columns的排序。每行中的key被用來決定該行存儲在集群中哪個節點中。
KeySpaces
是數據最外層的容器。可以把它想象成RDBMS中的一個數據庫。盡管不是必須的,但是為每個應用創建一個單獨的keyspace比較好。一個keyspace有一個name和一些別的屬性(比如說複製因子,複製策略等)。
Clusters
Cassandra運行在多個節點(一個集群)之上,它在集群間複製數據,所以當有一個節點宕機,另外的節點能接管工作。這讓Cassandra是高可用的。
簡而言之,Cassandra的數據模型像下麵這樣:
Cluster => Keyspace => Column Families (Standard or Super) => Column => (Name, Value, Timestamp)
一致性哈希
Cassandra是一個分布式數據庫,一般會運行在多個機器上。在這些節點中,我們該怎麼劃分數據呢?可以使用一個簡單的策略,比如在N個節點的集群中,把數據存放在(hash(key)%N)個機器上,但是當一個節點增加或者刪除的時候會引起一些問題,因為每個節點上的數據都會變化。為了避免這種情況,我們使用一致性哈希。
在一致性哈希中,機器被放在一個邏輯上的圓環上,如下圖所示,key同樣也在這個圓環上,並被分配到順時針的最近一個機器上,並複製N份到順時針前的節點上(N被稱為複製因子)。Cassandra是一個最終一致性的存儲係統, 會在後台進行複製操作。客戶端沒必要等待所有的副本寫入完成,可以設置要等待完成寫入的節點數。
現在,如果我們從圓環上增加或刪除一個機器,key隻會在移動到和它相鄰的節點上去。
反熵(Anti-Entropy) 和 讀修複
Anti-Entropy是Cassandra的一個副本同步機製,來保證在不同節點上的數據都被更新到最新的版本。Anti-Entropy使用Merkle Trees,對於每個column family,都會構造這個tree。為什麼叫Anti-Entropy呢?在一個最終一致性性的數據庫中,隨著時間流逝,應該被精確複製的節點都會慢慢互相偏差。這個偏差可以被認為是係統的“entropy”。反熵 就是讓節點之間互相同步的過程。
Hash Tree被交換用來找出陳舊的數據。他們被用來減少節點之間的數據交換。Hashes trees看起來像下麵這樣:
當反熵 開始的時候,hash trees被構建,並在節點之間互相交換。而不是交換真實的數據。然後從root開始比較。如果某些節點的hash不一樣,我們可以準確的判斷出哪些數據是陳舊的。
Memtables,SSTable and Commit Logs
一個寫操作會立即寫到節點的commit log中。隻有當這個請求被寫入到commit log中的時候,它才被認為是成功的。在被寫入commit log之後,這個value被寫入到一個被稱為memtable的內存結構中。當memtable的大小到達一個閾值的時候,它就被刷到磁盤中的SSTable中。Memtables根據key進行排序,然後被順序的寫到磁盤中。因此,寫入是非常快的。
在磁盤中的一個SSTable是不可變的。若幹個SSTable被一個compaction程序合並到一起。每個SSTable都有一個相關的布隆過濾器和一個索引。布隆過濾器可以快速的檢查一個元素是否在這個集合中。
讀的時候,Cassandra首先會檢查memtable。然後會嚐試查找所有的SSTable。
Compaction
在壓縮期間,SSTable會被合並:key會被合並,標記為tombstones 的數據會被丟棄,會創建新的索引。
什麼是tombstones?
當一個值被 刪除的時候,他不會真正的被刪除,但是會給他一個tombstone標記。為什麼要這麼做呢?因為如果一個值在一個副本中被刪除,而在另外的副本中沒被刪除,當重新調節的時候,係統會認為被刪除值的副本是沒有被更新的,然後又重新寫入這個值。Tombstones顯然會浪費空間,並且需要被清除。一個anti-entropy 開始的時候,在壓縮的時候是最好擺脫他們的時機。在每次GCGraceSeconds之後,Tombstones被會垃圾收集。
在壓縮的時候,合並的數據會被排序,一個新的索引也會被創建,然後新的合並後的數據、索引數據都會被寫到一個單獨的新的SSTable中。
Gossip 和失敗檢測
Cassandra使用Gossip協議來內部交流,所以每個節點都能知道別的節點的信息。 gossiper每秒運行一次。當節點發現目標節點上線的時候,會觸發暗示提交。
gossiper會定期的隨機選擇一個節點,並和它開始一個gossip回話。每個回合需要三種信息:
1.發送一個GossipDigestSynMessage給它選擇的節點。
2.當節點收到信息的是,他也返回一個GossipDigestAckMessage。
3.當節點收到ack信息的時候,他發送一個GossipDigestAck2Message給友節點來完成一個gossip回合。
每個節點都包含了死亡節點和可用節點的列表。Cassandra使用一個 Phi Accrual Failure Detection 技術來替代傳統的“heat beat”來檢查節點是否死亡。這個技術使用一個懷疑度概念來找出可能的死亡節點。
暗示提交(Hinted Handoff)
由於某些原因,節點的某些寫入的數據不可用。其他節點將會處理這個寫請求,並且等待著節點回來,當這個節點上線的時候,它會把寫入又發回給節點。這被稱為暗示提交。為什麼是暗示提交呢?
- 當一致性不是必須的時候保證高可用
- 減少死亡節點上線所需要的時間
一個寫入請求會被發送到所有的副本,當達到要求的數量的節點返回的時候,這個寫入會被認為是成功的。
所以,這隻是Cassandra架構的一個基本的概覽。一些主題如一致性哈希、anti-entropy 等等。在後麵我將單獨講這些東西。
最後更新:2017-05-19 10:25:12