維護最終一致性數組
Cassandra 經過4個技術來維護數據的最終一致性,分別爲逆熵(Anti-Entropy),讀修復(Read Repair),提示移交(Hinted Handoff)和分佈式刪除。緩存
1) 逆熵數據結構
這是一種備份之間的同步機制。節點之間按期互相檢查數據對象的一致性,這裏採用的檢查不一致的方法是 Merkle Tree;dom
2) 讀修復分佈式
客戶端讀取某個對象的時候,觸發對該對象的一致性檢查:函數
讀取Key A的數據時,系統會讀取Key A的全部數據副本,若是發現有不一致,則進行一致性修復。spa
若是讀一致性要求爲ONE,會當即返回離客戶端最近的一份數據副本。而後會在後臺執行Read Repair。這意味着第一次讀取到的數據可能不是最新的數據;設計
若是讀一致性要求爲QUORUM,則會在讀取超過半數的一致性的副本後返回一份副本給客戶端,剩餘節點的一致性檢查和修復則在後臺執行;日誌
若是讀一致性要求高(ALL),則只有Read Repair完成後才能返回一致性的一份數據副本給客戶端。orm
可見,該機制有利於減小最終一致的時間窗口。
3) 提示移交
對寫操做,若是其中一個目標節點不在線,先將該對象中繼到另外一個節點上,中繼節點等目標節點上線再把對象給它:
Key A按照規則首要寫入節點爲N1,而後複製到N2。假如N1宕機,若是寫入N2能知足ConsistencyLevel要求,則Key A對應的RowMutation將封裝一個帶hint信息的頭部(包含了目標爲N1的信息),而後隨機寫入一個節點N3,此副本不可讀。同時正常複製一份數據到N2,此副本能夠提供讀。若是寫N2不知足寫一致性要求,則寫會失敗。 等到N1恢復後,本來應該寫入N1的帶hint頭的信息將從新寫回N1。
4) 分佈式刪除
單機刪除很是簡單,只須要把數據直接從磁盤上去掉便可,而對於分佈式,則不一樣,分佈式刪除的難點在於:若是某對象的一個備份節點 A 當前不在線,而其餘備份節點刪除了該對象,那麼等 A 再次上線時,它並不知道該數據已被刪除,因此會嘗試恢復其餘備份節點上的這個對象,這使得刪除操做無效。
Cassandra 的解決方案是:本地並不當即刪除一個數據對象,而是給該對象標記一個hint,按期對標記了hint的對象進行垃圾回收。在垃圾回收以前,hint一直存在,這使得其餘節點能夠有機會由其餘幾個一致性保證機制獲得這個hint。
Cassandra 經過將刪除操做轉化爲一個插入操做,巧妙地解決了這個問題。
Token,Partitioner
Cassandra中,Token是用來分區數據的關鍵。每一個節點都有一個第一無二的Token,代表該節點分配的數據範圍。節點的Token造成一個Token環。例如使用一致性HASH進行分區時,鍵值對將根據一致性Hash值來判斷數據應當屬於哪一個Token。
分區策略的不一樣,Token的類型和設置原則也有所不一樣。 Cassandra (0.6版本)自己支持三種分區策略:
RandomPartitioner:隨機分區是一種hash分區策略,使用的Token是大整數型(BigInteger),範圍爲0~2^127,Cassandra採用了MD5做爲hash函數,其結果是128位的整數值(其中一位是符號位,Token取絕對值爲結果)。所以極端狀況下,一個採用隨機分區策略的Cassandra集羣的節點能夠達到2^127+1個節點。採用隨機分區策略的集羣沒法支持針對Key的範圍查詢。
OrderPreservingPartitioner:若是要支持針對Key的範圍查詢,那麼能夠選擇這種有序分區策略。該策略採用的是字符串類型的Token。每一個節點的具體選擇須要根據Key的狀況來肯定。若是沒有指定InitialToken,則系統會使用一個長度爲16的隨機字符串做爲Token,字符串包含大小寫字符和數字。
CollatingOrderPreservingPartitioner:和OrderPreservingPartitioner同樣是有序分區策略。只是排序的方式不同,採用的是字節型Token,支持設置不一樣語言環境的排序方式,代碼中默認是en_US。
分區策略和每一個節點的Token(Initial Token)均可以在storage-conf.xml配置文件中設置。
bloom-filter, HASH
Bloom Filter是一種空間效率很高的隨機數據結構,本質上就是利用一個位數組來表示一個集合,並能判斷一個元素是否屬於這個集合。Bloom Filter的這種高效是有偏差的:在判斷一個元素是否屬於某個集合時,有可能會把不屬於這個集合的元素誤認爲屬於這個集合(false positive)。所以,Bloom Filter不適合那些「零錯誤」的應用場合,而在能容忍低錯誤率的場合下,Bloom Filter經過極少的錯誤換取了存儲空間的極大節省。
原理:位數組 + K個獨立hash(y)函數。將位數組中hash函數對應的值的位置設爲1,查找時若是發現全部hash函數對應位都是1說明存在,很明顯這個過程並不保證查找的結果是徹底正確的。
在Cassandra中,每一個鍵值對使用1Byte的位數組來實現bloom-filter。
圖4 Bloom Filter
Cassandra的存儲機制借鑑了Bigtable的設計,採用Memtable和SSTable的方式。
CommitLog
和HBase同樣,Cassandra在寫數據以前,也須要先記錄日誌,稱之爲Commit Log,而後數據纔會寫入到Column Family對應的MemTable中,且MemTable中的數據是按照key排序好的。SSTable一旦完成寫入,就不可變動,只能讀取。下一次Memtable須要刷新到一個新的SSTable文件中。因此對於Cassandra來講,能夠認爲只有順序寫,沒有隨機寫操做。
MenTable
MemTable是一種內存結構,當數據量達到塊大小時,將批量flush到磁盤上,存儲爲SSTable。這種機制,至關於緩存寫回機制(Write-back Cache),優點在於將隨機IO寫變成順序IO寫,下降大量的寫操做對於存儲系統的壓力。因此咱們能夠認爲Cassandra中只有順序寫操做,沒有隨機寫操做。
SSTable
SSTable是Read Only的,且通常狀況下,一個CF會對應多個SSTable,當用戶檢索數據時,Cassandra使用了Bloom Filter,即經過多個hash函數將key映射到一個位圖中,來快速判斷這個key屬於哪一個SSTable。
爲了減小大量SSTable帶來的開銷,Cassandra會按期進行compaction,簡單的說,compaction就是將同一個CF的多個SSTable合併成一個SSTable。在Cassandra中,compaction主要完成的任務是:
1) 垃圾回收: cassandra並不直接刪除數據,所以磁盤空間會消耗得愈來愈多,compaction 會把標記爲刪除的數據真正刪除;
2) 合併SSTable:compaction 將多個 SSTable 合併爲一個(合併的文件包括索引文件,數據文件,bloom filter文件),以提升讀操做的效率;
3) 生成 MerkleTree:在合併的過程當中會生成關於這個 CF 中數據的 MerkleTree,用於與其餘存儲節點對比以及修復數據。