Comparing the Cassandra Data Model to a Relational Database
- Keyspace 是一個應用程式資料的容器,類似關聯式資料庫的 database 或 schema。
- 在 keyspace 內部有很多的 column family, 類似 table。
- Column family 包含了很多的 columns,而一個 row key 指定了一個 columns 集合。
- 每一個 row key 所指定的 column 集合,這些 column 可以不同 (與關聯式資料庫不同)。
- Cassandra 不強制關聯 column families,而它們之間沒有 foreign keys,在 query 資料的時候也不能 join 起來。
- 以反正規化資料為設計。
About keyspace
- 一個 cluster 裡會有一個 keyspace 提供給每個應用程式使用。
- Replication 的控制是以 keyspace 為基礎,若資料有不同複本需求時,應該以不同的 keyspace 為管理。
- 使用 Data Definition Language (DDL) 命令(CLI 或 CQL) 來定義 keyspace。
About Column Families
- 在 Cassandra,你定義了 column family,每個 column family 能夠定義 column 的 metadata,但實際上儲存每一筆 row 的時候,會有哪些 columns 則是應用程式決定的,而且每個 row 可以有不一樣的 columns。
- 雖然 column family 可以有非常大的彈性,實行上,並不是完全的 "schema-less"。每個 column family 都應該被設計成只包含單一資料型態。
- Column family 的設計模式有兩種類型:static 和 dynamic column family。
- Static column family
- 使用一組靜態的欄位名稱,這很像傳統資料庫的 table。
- 可以預先定義 每個 column 的 metadata。
- 例如,一個用來儲存 user 的 column family,可能會有欄位:user name, address, email, phone number. 雖然每一個 row 都有相同的 column 集合,但卻不一定在儲存時都要有值。
- Dynamic column family
- 預先計算結果集(result sets),並儲存到資料列中以提供高效的資料檢索。
- 每一筆資料列都是一筆為了滿足搜尋的資料的快照(snapshot),有點像是具體化視觀表 (materialized view)。
- Dynamic column family 為每個 column 的名稱(name)和值(value) 定義了型態資訊(comparators,validators),而不是去定義每個 column 的 metadata,每個 column 實際的名稱和值,是應用程式在新增欄位時決定的。
- Row key 是唯一的,用來識別每一筆資料列,類似關聯式資料庫的 primary key (主鍵)。
- Column family 靠 row key 來達到資料分割 (partition) 的目的,而 row key 也隱含著索引的意味,它不能是空值。
About Columns
- 在 Cassandra,column 是最小的資料單位,它是由一個名稱(name)、一個值(value)、一個時間戳記(timestamp),所組成的。
- 如果排序對你來說很重要,那麼你可以自己維護一個索引表,利用這個索引表達成排序的需求。
- Column 並不一定要有值(可以是空的),允許只存 column name。
- Cassandra 的每個 column 都有 timestamp,它是用來判斷誰是最新的資料,並且可以被更新。
- timestamp 是客戶端應用程式所提供的,當多個客戶端同時儲存同一個欄位時,只有最新的那筆資料會被儲存。
About Special Columns (Counter, Expiring, Super)
- Expiring Columns
- Column 可以設定過期日 (expiration date),稱為 TTL ( time ot live ),單位是秒。
- 當有設定 TTL 的 column到期之後,就會被標記為 deleted ( with a tombstone)。
- 一但欄位被標記為 tombstone, 在 normal compaction (gc_grace_seconds) 以及 repair 的時候就會自動被清除。
- 可以透過以下兩種方式來設定,
CLI:SET
users['bobbyjo'][utf8('coupon_code')] = utf8('SAVE20')
WITHttl = 864000
;
cqlsh> UPDATE
users
USING TTL
432000
SET
'password' = 'ch@ngem3a'
WHEREKEY = 'jsmith'
;
- 如果你想要重設該 column 的 TTL,那麼就要重新 insert,並指定新的 TTL。
- 過期日的計算是在主要的 host (接受 insert 操作),但會被其它的 node 所解讀,所以 Server 之間的時間必須要同步,否則會不精準。
- Counter Columns
- 用來儲存計數的欄位。
- Counter column families 必須使用 CounterColumnType 做為 validator,所以 counter 必須被使用在專門的 column family。(目前無法與標準欄位放一起)
- 它只會做增量 (incrementing) 或減量 (decrementing)的更新。
- 要更新 counter column,客戶端要指定 counter 名稱和要增加或減少的值。
- counter 能夠以任何的 consistency level 被讀或寫入。
- 與一般的欄位不同,當寫入一個 counter 時,會在背景裡有發出一個讀的請求,以確保分散式 counter 的值在複本間保持一致性。
- Consistency Level ONE 是寫入 counter 最普遍的一致性級別,在這個級別下,所隱含的 read 請求,不會對寫入的延遲造成什麼衝擊。
- Super Columns
- Cassandra 的 column family 可以包含 regular columns 或是 super columns。
- Super column 包含一個 column name 和一個 sub-columns 的 map。
- Super column 可以指定一個 comparator 給 super column name 和 sub-column names。
- 類似實例化視圖(materialized view),可以做資料檢索。
- Data Types (comparators and validators)
- Column value 或 row key 的 data type,我們稱為 validator。
- Column name 的 data type,我們稱為 comparator。
- 在 cassandra 內部,若在建立 column family 的時候沒有指定 data type,預設是以 16 進位的位元陣列 (Bytes type) 來存。
- Cassandra 提供 validator 和 comparator 使用的 data type 中 CounterColumnType 只能用自在 column value。
- data type 請查詢:DataStax
- Validator
- 使用 key_validation_class property,定義預設的 row key validator 給所有的 column families。
- CounterColumnType 不能被用在 row key validator。
- static column family:使用 column_metadata property 來定義 column family 時,你應該要定義每個 column 和它的 data type。
- dynamic column family:你應該定義一個預設的 validator class:default_validation_class,而不是定義每個 column 的 data type。
- Key 和 column validators 在之後可以隨意的增加或修改。
- Comparator
- Row 和 column 會以 column name 的排序順序來存放。
- Comparator 指定 column name 的 data type。
- 當建立 column family 的時候指定了 comparator 後,之後就不能在變更了,這點與 validator 不同。
- Column Family Compression
- 每個 column family 都能設定資料壓縮。
- 壓縮可以讓資料量減少,這樣就可以最大化你的硬碟容量。
- 壓縮的好處,除了節省磁碟空間,也能減少磁碟的 IO,特別是以讀為主的工作。
- Cassandra 能夠快速從 SSTable 索引,找到 row 的位置,然後只解壓縮跟那筆 row 有關的資料的 chunk。
- 壓縮對於寫入的效能而言並沒有負面的影響。事實上,寫到壓縮的 table,效能有 10% 左右的提升。
- Cassandra 的 SSTable 資料檔案是 immutable 的,所以也就沒有重複壓縮的循環。SSTable 只會被壓縮一次,然後就寫到磁碟了。
- 壓縮能夠帶來以下的好處,依不同的 column families 的資料特性有所不同:
- 2X - 4X 資料量的減少。
- 25% - 35% 讀校能改善。
- 5% - 10% 寫校能改善。
- 使用時機:
- 壓縮最合適的 column family 是,有很多筆 row,每一筆 row 有同樣的 columns。
舉例來說,一個 column family 包含 user 相關的資料,如 username, email, 等,可以被選為要壓縮的對象。更多更類似的 row 的資料,將得到更大的壓縮率,而在讀取時會有更大的效能提升。 - 在每筆 row 會有不同的 columns set 的 column family,就不是很適合壓縮,所以 Dynamic column families 不會有太好壓縮率。
- 設定
- 透過 compression_options 來設定 column family 的壓縮。
- 當你在一個 column family 設定壓縮後,那些已經存在磁碟的 SSTable 不會馬上進行壓縮,不過在之後的 compaction 程序會進行壓縮,但新建立的 SSTable 會立即被壓縮。
- 若有必要,你可以使用 nodetool upgradesstables 或 scrub 強迫重寫並壓縮這些 SSTable。
- 透過 CLI 設定
UPDATE COLUMN FAMILY
users
WITH compaction_strategy=LeveledCompactionStrategy
AND compaction_strategy_options={sstable_size_in_mb: 10}; - Cassandra 1.1 之後才能透過 CQL 來設定 compression (DataStax)。
About Primary Indexes
- Column family 的 primary index 就是 row key 的索引。
- Row 的分配是藉由 cluster-configured partitioner 和 key-configured replia placement strategy。
- Primary index 能讓 Cassandra 透過 row key 找出 row。
- 每一個節點都知道任何一個節點所管理的 row key 的範圍。
- 每個 row 請求都能夠透過 row indexes 並只在相關的複本節點上,地找到 row 的位置。
About Secondary Indexes
- Secondary indexes 是用來參考 column value。
- Cassandra 支援 type KEYS 的 secondary index (hash index)。
- 使用 secondary indexes 來查找資料時,透過指定的值和使用對應的欄位名稱(predicate)。
WHERE column x = value y
- 何時使用
- 當資料列包含了索引値。
- 在一個特定的 column 其中的值都是唯一的。(ex, mail)
- 當你查詢或維護一個 index 表花了很多時間時。
- 舉例,若你想要 透過 mail address 來查找一個 user,這會比維護一個做為 index 表格的 dynamic column family 還要有效率。
- 如何使用
- 當你在 column 建立 secondary index時,這會在背景裡建立資料的索引。
- 建立的方式
- 建立 column family時
CREATE COLUMN FAMILY
users
WITH
comparator=UTF8Type
AND
column_metadata=[
{column_name: full_name, validation_class: UTF8Type},{column_name: email, validation_class: UTF8Type},
{column_name: birth_year, validation_class: LongType, index_type: KEYS},
{column_name: state, validation_class: UTF8Type, index_type: KEYS}]
;
- 用 UPDATE 來建立已經存在的 column
UPDATE COLUMN FAMILY
users
WITH
comparator=UTF8Type
AND
column_metadata=[
{column_name: full_name, validation_class: UTF8Type},{column_name: email, validation_class: UTF8Type},
{column_name: birth_year, validation_class: LongType, index_type: KEYS},
{column_name: state, validation_class: UTF8Type, index_type: KEYS}]
;
- 使用 secondary index
- CLI
GET
users
WHERE
state = 'TX'
;
- CQL
SELECT
*
FROM
users
WHERE
state = 'TX'
;
沒有留言 :
張貼留言