Apache Cassandra 是高度可擴展的,高性能的分布式 NoSQL 數據庫。 Cassandra 旨在處理許多商品服務器上的大量數據,提供高可用性而無需擔心單點故障。
Cassandra 具有能夠處理大量數據的分布式架構。 數據放置在具有多個複制因子的不同機器上,以獲得高可用性,而無需擔心單點故障。
數據模型Key Space(對應 SQL 數據庫中的 database)
1. 一個 Key Space 中可包含若幹個 CF,如同 SQL 數據庫中一個 database 可包含多個 table
Key(對應 SQL 數據庫中的主鍵)
2. 在 Cassandra 中,每一行數據記錄是以 key/value 的形式存儲的,其中 key 是唯一标識。
column(對應 SQL 數據庫中的列)
3. Cassandra 中每個 key/value 對中的 value 又稱為 column,它是一個三元組,即:name,value 和 timestamp,其中 name 需要是唯一的。
super column(SQL 數據庫不支持)
4. cassandra 允許 key/value 中的 value 是一個 map(key/value_list),即某個 column 有多個子列。
Standard Column Family(相對應 SQL 數據庫中的 table)
5. 每個 CF 由一系列 row 組成,每個 row 包含一個 key 以及其對應的若幹 column。
Super Column Family(SQL 數據庫不支持)
6. 每個 SCF 由一系列 row 組成,每個 row 包含一個 key 以及其對應的若幹 super column。
Cassandra 一緻 Hash 和虛拟節點一緻性 Hash(多米諾 down 機)
為每個節點分配一個 token,根據這個 token 值來決定節點在集群中的位置以及這個節點所存儲的數據範圍。
虛拟節點(down 機多節點托管)
由于這種方式會造成數據分布不均的問題,在 Cassandra1.2 以後采用了虛拟節點的思想:不需要為每個節點分配 token,把圓環分成更多部分,讓每個節點負責多個部分的數據,這樣一個節點移除後,它所負責的多個 token 會托管給多個節點處理,這種思想解決了數據分布不均的問題。
如圖所示,上面部分是标準一緻性哈希,每個節點負責圓環中連續的一段,如果 Node2 突然down 掉,Node2 負責的數據托管給 Node1,即 Node1 負責 EFAB 四段,如果 Node1 裡面有很多熱點用戶産生的數據導緻 Node1 已經有點撐不住了,恰巧 B 也是熱點用戶産生的數據,這樣一來 Node1 可能會接着 down 機,Node1down 機,Node6 還 hold 住嗎?
下面部分是虛拟節點實現,每個節點不再負責連續部分,且圓環被分為更多的部分。如果 Node2突然 down 掉,Node2 負責的數據不全是托管給 Node1,而是托管給多個節點。而且也保持了一緻性哈希的特點。
Gossip 協議Gossip 算法如其名,靈感來自辦公室八卦,隻要一個人八卦一下,在有限的時間内所有的人都會知道該八卦的信息,這種方式也與病毒傳播類似,因此 Gossip 有衆多的别名“閑話算法”、“疫情傳播算法”、“病毒感染算法”、“謠言傳播算法”。 Gossip 的特點:在一個有界網絡中,每個節點都随機地與其他節點通信,經過一番雜亂無章的通信,最終所有節點的狀态都會達成一緻。因為 Gossip 不要求節點知道所有其他節點,因此又具有去中心化的特點,節點之間完全對等,不需要任何的中心節點。實際上 Gossip 可以用于衆多能接受“最終一緻性”的領域:失敗檢測、路由同步、Pub/Sub、動态負載均衡。
Gossip 節點的通信方式及收斂性
Gossip 兩個節點(A、B)之間存在三種通信方式(push、pull、push&pull)
1. push: A 節點将數據(key,value,version)及對應的版本号推送給 B 節點,B 節點更新 A 中比自己新的數據。
2. pull:A 僅将數據 key,version 推送給 B,B 将本地比 A 新的數據(Key,value,version)推送給 A,A 更新本地。
3. push/pull:與 pull 類似,隻是多了一步,A 再将本地比 B 新的數據推送給 B,B 更新本地。
如果把兩個節點數據同步一次定義為一個周期,則在一個周期内,push 需通信 1 次,pull 需 2 次,push/pull 則需 3 次,從效果上來講,push/pull 最好,理論上一個周期内可以使兩個節點完全一緻。直觀上也感覺,push/pull 的收斂速度是最快的。
gossip 的協議和 seed list(防止集群分列)
cassandra 使用稱為 gossip 的協議來發現加入 C 集群中的其他節點的位置和狀态信息。gossip 進程每秒都在進行,并與至多三個節點交換狀态信息。節點交換他們自己和所知道的信息,于是所有的節點很快就能學習到整個集群中的其他節點的信息。gossip 信息有一個相關的版本号,于是在一次 gossip 信息交換中,舊的信息會被新的信息覆蓋重寫。要阻止分區進行 gossip 交流,那麼在集群中的所有節點中使用相同的 seed list,種子節點的指定除了啟動起 gossip 進程外,沒有其他的目的。種子節點不是一個單點故障,他們在集群操作中也沒有其他的特殊目的,除了引導節點以外
數據複制Partitioners(計算 primary key token 的 hash 函數)
在 Cassandra 中,table 的每行由唯一的 primarykey 标識,partitioner 實際上為一 hash 函數用以計算 primary key 的 token。Cassandra 依據這個 token 值在集群中放置對應的行
兩種可用的複制策略:
SimpleStrategy:僅用于單數據中心,
将第一個 replica 放在由 partitioner 确定的節點中,其餘的 replicas 放在上述節點順時針方向的後續節點中。
NetworkTopologyStrategy:可用于較複雜的多數據中心。
可以指定在每個數據中心分别存儲多少份 replicas。
複制策略在創建 keyspace 時指定,如CREATE KEYSPACE Excelsior WITH REPLICATION = { 'class' :
'SimpleStrategy','replication_factor' : 3 };
CREATE KEYSPACE Excalibur WITH REPLICATION = {'class' :'NetworkTopologyStrategy',
'dc1' : 3, 'dc2' : 2};
數據寫請求和協調者協調者(coordinator)
協調者(coordinator)将 write 請求發送到擁有對應 row 的所有 replica 節點,隻要節點可用便獲取并執行寫請求。寫一緻性級别(write consistency level)确定要有多少個 replica 節點必須返回成功的确認信息。成功意味着數據被正确寫入了 commit log 和 memtable。
其中 dc1、dc2 這些數據中心名稱要與 snitch 中配置的名稱一緻.上面的拓撲策略表示在 dc1 配置3 個副本,在 dc2 配置 2 個副本
數據讀請求和後台修複1. 協調者首先與一緻性級别确定的所有 replica 聯系,被聯系的節點返回請求的數據。
2. 若多個節點被聯系,則來自各 replica 的 row 會在内存中作比較,若不一緻,則協調者使用含最新數據的 replica 向 client 返回結果。那麼比較操作過程中隻需要傳遞時間戳就可以,因為要比較的隻是哪個副本數據是最新的。
3. 協調者在後台聯系和比較來自其餘擁有對應 row 的 replica 的數據,若不一緻,會向過時的replica 發寫請求用最新的數據進行更新 read repair。
數據存儲(CommitLog、MemTable、SSTable)
寫請求分别到 CommitLog 和 MemTable, 并且 MemTable 的數據會刷寫到磁盤 SSTable 上. 除了寫數據,還有索引也會保存到磁盤上.
先将數據寫到磁盤中的 commitlog,同時追加到中内存中的數據結構 memtable 。這個時候就會返回客戶端狀态 , memtable 内 容 超 出 指 定 容 量 後 會 被 放 進 将 被 刷 入 磁 盤 的 隊 列(memtable_flush_queue_size 配置隊列長度)。若将被刷入磁盤的數據超出了隊列長度,将内存數據刷進磁盤中的 SSTable,之後 commit log 被清空。
SSTable 文件構成(BloomFilter、index、data、static)
SSTable 文件有 fileer(判斷數據 key 是否存在,這裡使用了 BloomFilter 提高效率),index(尋找對應 column 值所在 data 文件位置)文件,data(存儲真實數據)文件,static(存儲和統計column 和 row 大小)文件。
二級索引(對要索引的 value 摘要,生成 RowKey)在 Cassandra 中,數據都是以 Key-value 的形式保存的。
KeysIndex 所創建的二級索引也被保存在一張 ColumnFamily 中。在插入數據時,對需要進行索引的 value進行摘要,生成獨一無二的key,将其作為 RowKey保存在索引的 ColumnFamily 中;同時在 RowKey 上添加一個 Column,将插入數據的 RowKey 作為 name 域的值,value 域則賦空值,timestamp 域則賦為插入數據的時間戳。
如果有相同的 value 被索引了,則會在索引 ColumnFamily 中相同的 RowKey 後再添加新的Column。如果有新的 value 被索引,則會在索引 ColumnFamily 中添加新的 RowKey 以及對應新的 Column。
當對 value 進行查詢時,隻需計算該 value 的 RowKey,在索引 ColumnFamily 中的查找該RowKey,對其 Columns 進行遍曆就能得到該 value 所有數據的 RowKey。
數據讀寫數據寫入和更新(數據追加)
Cassandra 的設計思路與這些系統不同,無論是 insert 還是 remove 操作,都是在已有的數據後面進行追加,而不修改已有的數據。這種設計稱為 Log structured 存儲,顧名思義就是系統中的數據是以日志的形式存在的,所以隻會将新的數據追加到已有數據的後面。Log structured 存儲系統有兩個主要優點:
數據的寫和删除效率極高
傳統的存儲系統需要更新元信息和數據,因此磁盤的磁頭需要反複移動,這是一個比較耗時的操作,而 Log structured 的系統則是順序寫,可以充分利用文件系統的 cache,所以效率很高。
錯誤恢複簡單
由于數據本身就是以日志形式保存,老的數據不會被覆蓋,所以在設計 journal 的時候不需要考慮 undo,簡化了錯誤恢複。
讀的複雜度高
但是,Log structured 的存儲系統也引入了一個重要的問題:讀的複雜度和性能。理論上說,讀操作需要從後往前掃描數據,以找到某個記錄的最新版本。相比傳統的存儲系統,這是比較耗時的。
數據删除(column 的墓碑)
如果一次删除操作在一個節點上失敗了(總共 3 個節點,副本為 3, RF=3).整個删除操作仍然被認為成功的(因為有兩個節點應答成功,使用 CL.QUORUM 一緻性)。接下來如果讀發生在該節點上就會變的不明确,因為結果返回是空,還是返回數據,沒有辦法确定哪一種是正确的。
Cassandra 總是認為返回數據是對的,那就會發生删除的數據又出現了的事情,這些數據可以叫“僵屍”,并且他們的表現是不可預見的。
墓碑
删除一個 column 其實隻是插入一個關于這個 column 的墓碑(tombstone),并不直接删除原有的 column。該墓碑被作為對該 CF 的一次修改記錄在 Memtable 和 SSTable 中。墓碑的内容是删除請求被執行的時間,該時間是接受客戶端請求的存儲節點在執行該請求時的本地時間(local delete time),稱為本地删除時間。需要注意區分本地删除時間和時間戳,每個 CF 修改記錄都有一個時間戳,這個時間戳可以理解為該 column 的修改時間,是由客戶端給定的。
垃圾回收 compaction
由于被删除的 column 并不會立即被從磁盤中删除,所以系統占用的磁盤空間會越來越大,這就需要有一種垃圾回收的機制,定期删除被标記了墓碑的 column。垃圾回收是在 compaction 的過程中完成的。
數據讀取(memtable SStables)
為了滿足讀 cassandra 讀取的數據是 memtable 中的數據和 SStables 中數據的合并結果。讀取SSTables 中的數據就是查找到具體的哪些的 SSTables 以及數據在這些 SSTables 中的偏移量(SSTables 是按主鍵排序後的數據塊)。首先如果 row cache enable 了話,會檢測緩存。緩存命中直接返回數據,沒有則查找 Bloom filter,查找可能的 SSTable。然後有一層 Partition key cache,找 partition key 的位置。如果有根據找到的 partition 去壓縮偏移量映射表找具體的數據塊。如果緩存沒有,則要經過 Partition summary,Partition index 去找 partition key。然後經過壓縮偏移量映射表找具體的數據塊。
1. 檢查 memtable
2. 如果 enabled 了,檢查 row cache
3. 檢查 Bloom filter
4. 如果 enable 了,檢查 partition key 緩存
5. 如果在 partition key 緩存中找到了 partition key,直接去 compression offset 命中,如果沒
有,檢查 partition summary
6. 根據 compression offset map 找到數據位置
7. 從磁盤的 SSTable 中取出數據
可以轉發關注小編,每天更新幹貨好文感謝一路相伴,一起成長!!!!!!!!
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!