Cassandra的存儲機制

在2009年興起的NoSQL 運 動中,Cassandra是其中重要的一個分佈式key-value數據庫產品,由Facebook在2008年開源,目前是Apache的頂級項目。最 近twitter的一 篇聲明 ,表示將從MySQL遷移到Cassandra,更讓其聲名大振。Cassandra是結合了Google Bigtable的數據模型和Amazon Dynamo高可用框架的一個產品。其數據模型可以參考張瑞的blog

值得說一下的是Cassandra的存儲機制,也是借鑑了Bigtable的設計,採用Memtable和SSTable的方式。和關係數據庫一 樣,Cassandra在寫數據之前,也需要先記錄日誌,稱之爲commitlog ,然後數據纔會寫入到Column Family對應的Memtable中,並且Memtable中的內容是按照key排序好的。Memtable是一種內存結構,滿足一定條件後批量刷新到 磁盤上,存儲爲SSTable。這種機制,相當於緩存寫回機制(Write-back Cache),優勢在於將隨機IO寫變成順序IO寫,降低大量的寫操作對於存儲系統的壓力。SSTable一旦完成寫入,就不可變更,只能讀取。下一次 Memtable需要刷新到一個新的SSTable文件中。所以對於Cassandra來說,可以認爲只有順序寫,沒有隨機寫操作。

因爲SSTable數據不可更新,可能導致同一個Column Family的數據存儲在多個SSTable中,這時查詢數據時,需要去合併讀取Column Family所有的SSTable和Memtable,這樣到一個Column Family的數量很大的時候,可能導致查詢效率嚴重下降。因此需要有一種機制能快速定位查詢的Key落在哪些SSTable中,而不需要去讀取合併所有 的SSTable。Cassandra採用的是Bloom Filter 算法,通過多個hash函數將key映射到一 個位圖中,來快速判斷這個key屬於哪個SSTable。關於Bloom Filter,有興趣的可以去看看參考文章4,5和6。

爲了避免大量SSTable帶來的性能影響,Cassandra也提供一種定期將多個SSTable合併成一個新的SSTable的機制,因爲每個 SSTable中的key都是已經排序好的,因此只需要做一次合併排序就可以完成該任務,代價還是可以接受的。所以在Cassandra的數據存儲目錄 中,可以看到三種類型的文件,格式類似於:

  • Column Family Name-序號-Data.db
  • Column Family Name-序號-Filter.db
  • Column Family Name-序號-index.db

其中Data.db文件是SSTable數據文件,SSTable是Sorted Strings Table的縮寫,按照key排序後存儲key/value鍵值字符串。index.db是索引文件,保存的是每個key在數據文件中的偏移位置,而 Filter.db則是Bloom Filter算法生產的映射文件。

上面大致介紹了一下Cassandra的存儲機制,通過將最新的寫操作放在內存中的Memtable,然後定期刷新到磁盤持久化爲 SSTable,Cassandra將隨機寫操作轉換成了順序寫操作,這可以提升IO性能。

最新寫入的髒數據是在內存Memtable表中,因此必須有機制來確保異常情況下,能夠將內存中的數據恢復出來。和關係型數據庫系統一 樣,Cassandra也是採用的先寫日誌再寫數據的方式,其日誌稱之爲Commitlog。

和Memtable/SSTable不一樣的是,Commitlog是server級別的,不是Column Family級別的 。 每個Commitlog文件的大小是固定的,稱之爲一個Commitlog Segment,目前版本(0.5.1)中,這個大小是128MB,這是硬編碼在代碼(src/java/org/apache/cassandra /db/Commitlog.java)中的。當一個Commitlog文件寫滿以後,會新建一個的文件。當舊的Commitlog文件不再需要時,會自 動清除。

每個Commitlog文件(Segment)都有一個固定大小(大小根據Column Family的數目而定)的CommitlogHeader 結 構,其中有兩個重要的數組,每一個Column Family在這兩個數組中都存在一個對應的元素。其中一個是位圖數組(BitSet dirty ),如果Column Family對應的Memtable中有髒數據,則置爲1,否則爲0,這在恢復的時候可以指出哪些Column Family是需要利用Commitlog進行恢復的。另外一個是整數數組(int[] lastFlushedAt ), 保存的是Column Family在上一次Flush時日誌的偏移位置,恢復時則可以從這個位置讀取Commitlog記錄。通過這兩個數組結構,Cassandra可以在異 常重啓服務的時候根據持久化的SSTable和Commitlog重構內存中Memtable的內容,也就是類似Oracle等關係型數據庫的實例恢復。

當Memtable flush到磁盤的SStable時,會將所有Commitlog文件的dirty數組對應的位清零,而在Commitlog達到大小限制創建新的文件 時,dirty數組會從上一個文件中繼承過來。如果一個Commitlog文件的dirty數組全部被清零,則表示這個Commitlog在恢復的時候不 再需要,可以被清除。因此,在恢復的時候,所有的磁盤上存在的Commitlog文件都是需要的。

 

參考文章:
[1].http://wiki.apache .org/cassandra/MemtableSSTable
[2].http://wiki.apache.org/cassandra/ArchitectureSSTable
[3].http://blog.csdn.net/jiaomeng/archive/2007/01/27/1495500.aspx
[4].http://www.hellodba.net/2009/04/bloom_filter.html
[5].http://labs.google.com/papers/bigtable.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章