Apache Cassandra 數據存儲模型

咱們在《Apache Cassandra 簡介》文章中介紹了 Cassandra 的數據模型相似於 Google 的 Bigtable,對應的開源實現爲 Apache HBase,並且咱們在 《HBase基本知識介紹及典型案例分析》 文章中簡單介紹了 Apache HBase 的數據模型。按照這個思路,Apache Cassandra 的數據模型應該和 Apache HBase 的數據模型很相似,那麼這二者的數據存儲模型是否是同樣的呢?本文將爲你們解答這些問題。咱們從 KeySpace -> Table -> Partition -> Row -> Cell 順序介紹。本文基於 Apache Cassandra 3.11.4 源碼進行介紹的,不一樣版本可能有些不同。服務器

Table & KeySpace

Cassandra 中的 KeySpace 概念和 RDBMS 裏面的 DataBase 概念很相似,一個 KeySpace 包含多張表,通常將有關聯的數據表放到同一個 KeySpace 下面。KeySpace 建立的時候能夠指定副本策略,副本因子以及是否啓用 CommitLog 機制(相似 HBase 中的 WAL)。spa

Cassandra 中表的概念和 RDBMS 很相似。不一樣的是在 Cassandra 中屬於同一張表的數據在物理上是分佈在不一樣節點上存儲的,同一張表由多個 Partition 組成。code

Partitions

Cassandra 通常是由多臺節點組成的,每臺節點負責必定範圍的,若是使用 Murmur3hash 的時候,每一個節點負責的 Token 相似於下面那樣:blog

因此 Token 範圍爲 -9223372036854775808 ~ -4611686018427387904 的數據存儲在 A 節點;同理,Token 範圍爲 -4611686018427387903 ~ -1 之間的數據存儲在 B節點,其餘相似;每一個 Token 範圍由多個 Partition 構成,每一個 Partition 由一行或多行數據組成,Partition 相似下面的:

其中,username 爲 Partition key;type 爲 Clustering key。那麼在這種狀況下,username = iteblog 的兩條數據構成一個 Partition;另外兩條構成分別構成兩個 Partitions。在底層存儲每一個 Partition 格式以下:

從上圖能夠看出,一個 Partition 是由 PartitionHeader、零個或多個 Row (格式在後面介紹)以及 EndPartition 三部分組成的。EndPartition 這個用於標記 Partition 結束,只佔用一個字節,並使用 0x00000001 標記。PartitionHeader 的格式以下:排序

  • Partition Key 就是咱們建表的時候指定的,因爲 Partition Key 長度使用兩字節表示,因此 Cassandra 中 Partition Key 長度必須小於等於 65535 字節。
  • Local Delete Time 是刪除發生時的服務器時間(以秒爲單位),與 gc_grace_seconds 進行比較以肯定什麼時候能夠清除它。當與 TTL 一塊兒使用時,localDeletionTime 是數據到期的時間。共佔四個字節;
  • Marked For Delete At 記錄刪除的時間戳,時間戳小於此值的數據被視爲已刪除,共佔用八字節。
  • Static Row:若是咱們建表的時候有 Static 字段,那麼標記爲 Static 的列會在這裏存儲。從這裏也能夠看出,partition key 相同的數據 Static 列只會保存一份數據。

在底層存儲中,多個 Partition 組成一個 SSTable(Sorted-String Table)文件。那麼同一個 SSTable 文件中的數據數據是如何組織的呢?答案是按照 Partition Key 計算獲得的 Token 升序排序的。索引

Row

上面看出,Partition 裏面包含了零個或多個 Row,這些 Row 對應的 Partition Key 是同樣的。非 Static 的 Row 在磁盤存儲的格式以下:

上面除了 flags 、Row Body Size 、 Previous Row Body Size 以及 Primary Key Liveness Timestamp 這四個字段必定會存在,其餘字段須要知足條件纔會存儲。下面對上面字段進行介紹:get

  • flags:Row 的標記信息,主要用於標記當前 Row 是否存在時間戳、TTL、被刪除、是否包含全部的列等信息。flag 字段佔用一個字節,
  • hasExtendedFlags:當前 Row 是否含有 Static 列,存在纔會有數據;
  • Clustering info:每一個 Row 包含零個或多個 Clustering 相關的信息。Clustering 信息就是咱們建立表的時候指定的 Clustering key 信息。每一個 Clustering Info 在持久化的時候會先存儲頭部信息,標記當前 Clustering key 是否爲空、是否爲 null 以及是否有值等信息;而後根據數據類型將值存下來,若是當前 Clustering key 的值佔用字節非固定,還須要存儲當前 Clustering key 值的字節數。
  • Row Body Size:當前 Row Body 的大小,Row Body 包含 primary key 的 liveness 信息、Row 是否刪除等信息以及 Cell 的信息。
  • Previous Row Body Size:前一個 Row Body 的大小,這個主要用於加速反向查詢的,不過當前並無使用;
  • Primary Key Liveness Timestamp:primary key 的 Liveness 用於肯定行是否還活着或已經死了(沒有 live cells 而且 liveness 爲空)。這個字段主要用於存儲當前 Row 的 Liveness 時間戳。注意,持久化到磁盤的時間戳是相對於當前 Memtable 最小時間戳的值。
  • Primary Key Liveness TTL:這個字段主要用於存儲當前 Row 的 Liveness TTL 信息。也是相對於當前 Memtable 最小 TTL 的值
  • Primary Key Liveness LocalExpirationTime:當前 Liveness 的 ExpirationTime,也是相對時間;
  • Row Marked For Delete At:當前 Row 的刪除時間,也是相對時間,精確到毫秒;
  • Row Local Deletion Time:當前被標記爲 tombstone 時服務器的時間,也是相對時間,精確到秒;
  • Columns Bitmap:從 Cassandra 3.x 開始,列的信息已經不保存到數據文件裏面了,列的信息是保存在對應 SSTable 的 md-X-big-Statistics.db 文件中。這個字段是用於標記當前行哪些列存在,哪些列不存在。若是列存在則標記爲0;若是列不存在則標記爲1;若是列所有存在,直接標記爲0。當表的字段數小於64個的時候,直接使用一個 long 類型的數據來存儲這個 bitmap。若是大於等於64個,處理方案稍微複雜一些:
    先保存一個標記位,標記當前表擁有的字段個數大於等於64;

若是存在的列沒有佔總列數的一半,則按照所有列的順序保存存在的列在排序後列的索引位置;
若是存在的列佔總列數超過一半,則按照所有列的順序保存不存在的列在排序後列的索引位置。
可見,Cassandra 經過將列的信息(包括列的名稱、類型、表名、keySpace等信息)保存到對應 SSTable 的 md-X-big-Statistics.db 文件中,相應的行只保存列是否存在的標記信息,這個能夠節省存儲空間的佔用。注意,HBase 存儲數據的時候每一個 Cell 都須要保存列名稱和列族名稱的。源碼

非 Static Row 的底層存儲格式已經在前面描述過,對於 Static Row 除了沒有上圖的 Clustering info 信息,其他都同樣,因此這裏就不介紹了。hash

上圖中最後有 N 個 Cell,那多個 Cell 之間的順序是如何保證的呢?答案是按照列的名稱字典順序升序排序的。好比咱們表的定義以下:it

CREATE TABLE iteblog (
  user_id text,
  type text,
  action text,
  username text,
  age text,
  email text,
  PRIMARY KEY(user_id)
);

那麼 Cell 的順序排列以下:

action -> age -> email -> type -> username

這個排序是經過 BTree 實現的,Row 的實現類爲 BTreeRow。

Cell

Cell 就是每列數據的底層實現,Cell 裏面包含了列的定義信息,好比是否被刪除、是否過時、是否設置了時間戳等。在 Cassandra 裏面,Column 有 Simple 和 Complex(CASSANDRA-8099引入的) 之分。non-frozen collection 或 UDT(用戶自定義類型)的列是 ComplexColumn(Complex Cell)。

Simple Cell(Simple Column)的底層格式

咱們正常使用的列就是屬於這種類型的,它的底層存儲格式以下:

  • flags:這個 Cell 的 flag 標記,主要用於標記當前 Cell 是否有值、是否被刪除、是否過時、是否使用 Row 時間戳、是否使用 Row TTL 等信息。flag 字段佔用一個字節,每位的含義表明以下:
  • timestamp:當前 Cell 的時間戳,Cassandra 中咱們能夠對每列設置時間戳;
  • deletion time:當前 Cell 的刪除時間;
  • ttl:當前 Cell 的 TTL,Cassandra 中咱們能夠對每列設置 TTL,表明這個 Cell 保留多長時間;
  • value:當前 Cell 的值;

Complex Cell(Complex Column)的底層格式

若是列屬於 non-frozen collection 或 UDT(用戶自定義類型),那麼這個屬於 Complex Cell,它的底層存儲格式以下:

能夠看出,Complex Cell 和 Simple Cell 大部分很相似,下面只介紹不同的地方:

  • Complex Cell Marked For Delete At & Complex Cell Local Deletion Time:這兩個屬性和前面的相似,只不過針對 Complex Cell 而言的。
  • Complex Cell Counts:Complex Cell 的個數;
  • path:當前 Cell 的路徑。

在 Cassandra 中, Complex Cell 的實現類是 ComplexColumnData。


原文連接 本文爲雲棲社區原創內容,未經容許不得轉載。

相關文章
相關標籤/搜索