理解cassandra架構
本文是我在看cassandra官方文件時寫的一篇翻譯,由於能力有限,很多地方都翻譯的不到位或者和原意有出入,希望大家可以給予指正,由於翻譯的較早,而且沒有全部完成,有些觀點可能已經在最新的cassandra中被更新或者改變,我也會在之後的時間將這些內容補全和修復
Cassandra是一種無效能損耗的高擴充性和可用性的分散式資料庫。線性的可伸縮性以及被商品級硬體設施和雲基礎架構驗證的容錯技術使它成為任務關鍵型資料儲存的良好平臺。Cassandra支援跨多個資料中心的副本備份是非常棒的,為使用者提供低延遲和即使某個區域停電也能正常運轉的放心。
節點間通訊(gossip)
Gossip是一種點對點的通訊協議,按照這個協議節點間定期的交換自己和其他他們知道的節點的狀態資訊。Gossip程式每秒執行一次來與叢集上的最多其他3個節點交換狀態資訊。 這些節點交換自己的資訊和其他的與這些節點通訊的節點資訊。所以所有的節點可以快速的瞭解到叢集上的其他節點。
為了防止gossip通訊出現問題,為叢集中所有的節點使用了相同列表的種子節點。這種情況在第一個節點啟動時非常重要。預設情況下,一個節點在隨後的重啟中會記住與它通訊的其他節點。種子節點的選定除了為新節點加入叢集時引導gossiped過程外再無其他目的。種子節點不會有單點故障,除了引導節點外再無其他特定的目的。
在多個資料中心叢集,從每個資料中心的種子列表中選取一個節點是一個好主意。建議每個資料中心指定多餘一個種子節點來提高容錯能力。否則,當引導一個節點時gossip不得不與另一個資料中心通訊。
不建議為每個節點都建立種子節點,因為這增了加維護量同時降低了效能。Gossip的優化不是關鍵,但是建議使用一個有少量種子節點的列表(大約每個資料中心三個節點)
失敗檢測和恢復
如果另一個節點掛掉了或者正在恢復中,失敗檢測方法用於本地確定gossip的狀態和歷史。Cassandra使用這個資訊避免客戶端請求被路由到不可到達的節點。(Cassandra也可以避免請求被路由到活著的但是效率低下的節點,請參考dynamic snitch
Gossip程式使用直接方式(節點的gossiping直接導向他)和間接方式(節點的資訊被傳達2手,三手,等等)跟蹤節點的狀態。Cassandra不是使用固定的閾值來標記失敗的節點,而是使用一個責權檢測機制來計算考慮了賬戶網路效能,工作量和歷史條件的每個節點的閾值。在gossip交換期間,每個節點維護一個與叢集中的其他節點的關於gossip資訊的上次到達時間的滑動視窗。通過配置phi_convict_threshold 屬性來調整錯誤檢測器的靈敏程度。較低的值增加了無反應節點被標記為down的可能性,而較高的值減少了瞬時錯誤引起的節點故障的可能性。大多數情況使用預設值即可,但是為亞馬遜EC2將其增加到10-12(由於經常遇到的網路擁堵)。在不穩定的網路環境(例如有時候EC2就是這樣),提高值為10或12有利於防止虛假故障,不建議使用值高於12和低於5。
節點失敗可能由各種原因引起,如硬體失敗和網路中斷。節點中斷往往瞬變,但可以持續很長時間。因為節點中斷很少意味著它將從叢集中永久的離開,這不會自動導致永久從環中移除節點。其他節點將定期與失敗節點嘗試建立連線檢視他們是否備份。要在叢集上永久改變節點的資格,管理員必須從cassandra環上使用 nodetool utility.工具精準的新增或者移除節點。當一個節點在當機後重新聯機時,或許它已經遺失了它所維護的對於副本資料的寫操作。存在一個修復機制以恢復遺失的資料,例如hinted handoffs和使用nodetool手動修復。當機時間的長短將決定哪種修復機制被用於保持資料一致性。
一致性hash允許資料分佈跨越一個叢集,以減少增加或減少節點時進行的重組操作。一致性hash基於partition key為資料分割槽,關於partition key和主見的介紹,請參考
例如,你有如下資料
Cassandra是一種無效能損耗的高擴充性和可用性的分散式資料庫。線性的可伸縮性以及被商品級硬體設施和雲基礎架構驗證的容錯技術使它成為任務關鍵型資料儲存的良好平臺。Cassandra支援跨多個資料中心的副本備份是非常棒的,為使用者提供低延遲和即使某個區域停電也能正常運轉的放心。
節點間通訊(gossip) Gossip是一種點對點的通訊協議,按照這個協議節點間定期的交換自己和其他他們知道的節點的狀態資訊。Gossip程式每秒執行一次來與叢集上的最多其他3個節點交換狀態資訊。 這些節點交換自己的資訊和其他的與這些節點通訊的節點資訊。所以所有的節點可以快速的瞭解到叢集上的其他節點。 為了防止gossip通訊出現問題,為叢集中所有的節點使用了相同列表的種子節點。這種情況在第一個節點啟動時非常重要。預設情況下,一個節點在隨後的重啟中會記住與它通訊的其他節點。種子節點的選定除了為新節點加入叢集時引導gossiped過程外再無其他目的。種子節點不會有單點故障,除了引導節點外再無其他特定的目的。 在多個資料中心叢集,從每個資料中心的種子列表中選取一個節點是一個好主意。建議每個資料中心指定多餘一個種子節點來提高容錯能力。否則,當引導一個節點時gossip不得不與另一個資料中心通訊。 不建議為每個節點都建立種子節點,因為這增了加維護量同時降低了效能。Gossip的優化不是關鍵,但是建議使用一個有少量種子節點的列表(大約每個資料中心三個節點)
失敗檢測和恢復 如果另一個節點掛掉了或者正在恢復中,失敗檢測方法用於本地確定gossip的狀態和歷史。Cassandra使用這個資訊避免客戶端請求被路由到不可到達的節點。(Cassandra也可以避免請求被路由到活著的但是效率低下的節點,請參考dynamic snitch
Gossip程式使用直接方式(節點的gossiping直接導向他)和間接方式(節點的資訊被傳達2手,三手,等等)跟蹤節點的狀態。Cassandra不是使用固定的閾值來標記失敗的節點,而是使用一個責權檢測機制來計算考慮了賬戶網路效能,工作量和歷史條件的每個節點的閾值。在gossip交換期間,每個節點維護一個與叢集中的其他節點的關於gossip資訊的上次到達時間的滑動視窗。通過配置phi_convict_threshold 屬性來調整錯誤檢測器的靈敏程度。較低的值增加了無反應節點被標記為down的可能性,而較高的值減少了瞬時錯誤引起的節點故障的可能性。大多數情況使用預設值即可,但是為亞馬遜EC2將其增加到10-12(由於經常遇到的網路擁堵)。在不穩定的網路環境(例如有時候EC2就是這樣),提高值為10或12有利於防止虛假故障,不建議使用值高於12和低於5。 節點失敗可能由各種原因引起,如硬體失敗和網路中斷。節點中斷往往瞬變,但可以持續很長時間。因為節點中斷很少意味著它將從叢集中永久的離開,這不會自動導致永久從環中移除節點。其他節點將定期與失敗節點嘗試建立連線檢視他們是否備份。要在叢集上永久改變節點的資格,管理員必須從cassandra環上使用 nodetool utility.工具精準的新增或者移除節點。當一個節點在當機後重新聯機時,或許它已經遺失了它所維護的對於副本資料的寫操作。存在一個修復機制以恢復遺失的資料,例如hinted handoffs和使用nodetool手動修復。當機時間的長短將決定哪種修復機制被用於保持資料一致性。
一致性hash允許資料分佈跨越一個叢集,以減少增加或減少節點時進行的重組操作。一致性hash基於partition key為資料分割槽,關於partition key和主見的介紹,請參考
例如,你有如下資料
Cassandra assigns a hash value to each partition key:
叢集中的每個節點對基於hash值得一段資料負責。在叢集中四個節點的hash值
cassandra基於partition key的值和每個節點所負責的值得範圍來為每個節點分配資料。例如,在一個4個節點的叢集 中,資料如下分佈
Virtual nodes
虛擬節點,稱為Vnodes,以更新的力度跨節點分佈資料,如果使用計算token的話這很容易實現。Vnodes簡化了cassadra中的許多工。
更多資訊,請參考cassandora1.2 中關於虛擬節點的主題。 Virtual nodes in Cassandra 1.2
將一個存在的節點轉換為虛擬節點,參考 Enabling virtual nodes on an existing production cluster.
How data is distributed across a cluster (using virtual nodes)
虛擬節點使用一致性hash來分配資料,不需要生成和分配新的token
Partitioners
一個partitioner決定資料分散式的儲存在叢集中的節點上(包括副本)。基本上,分割槽程式使用hash函式從partition key中派生出一個token,該token代表了一行資料。每行的資料之後按token的值跨叢集分佈。 Murmur3Partitioner 和RandomPartitioner 使用token來為每個節點分配相同比例的資料,表格中的資料均等的分佈在整個環上,或是其他組上如祕鑰空間。即使表使用不同的分割槽鍵如username或者timestamps也是按這種情況來做。而且在此基礎上,對於叢集的讀寫操作也被均勻的分佈,負載均衡被簡化因為hash range的每個部分獲取到row的數量是均等的。更多細節參考
這兩個分割槽演算法的區別是如何生成token的hash值,RandomPartitioner 使用一個加密hash,他生成hash的時間要比Murmur3Partitioner 長,Cassoandra不需要加密hash,所以使用Murmur3Partitioner 在3-5分鐘內產生完hash值可以改進效率。
Cassandra支援如下的分割槽程式,可以在cassandra.yaml檔案中設定他們。 Murmur3Partitioner (預設)基於MurmurHash hash值跨叢集均勻分佈節點。 RandomPartitioner 基於MD5 hash值跨叢集均勻分佈節點。 ByteOrderedPartition 按照資料的祕鑰位元組字典順序有序分佈。 Murmur3Partitioner 作為預設的分割槽策略應用於cassandra1.2以後,在部分情況下作為生成新叢集的首選。 然而,分割槽程式間並不相容, 使用一種分割槽程式後很難再轉換為另一種分割槽程式。 如果使用虛擬節點(vnodes),你不必計算tokens。如果不使用vnodes,你必須計算tokens的數量然後為cassandra.yaml檔案中的initial_token引數賦值。請參見 Generating tokens 同時使用某種分割槽程式的對應方法。
Murmur3Partitioner是預設分割槽程式,Murmur3Partitioner比RandomPartitioner更快更有效率,Murmur3Partitioner 可以使用vnodes,然而,如果你不使用vnodes,你必須計算token的數量,正如 Generating tokens中描述的那樣。 為新的叢集使用Murmur3Partitioner。你無法將已經存在的叢集的分割槽程式改變為另一種分割槽程式。Murmur3Partitioner使用 MurmurHash 函式。該 雜湊函式建立一個64-bit的hash值作為分割槽鍵,可能的hash值得範圍從 -263 to +263-1 當使用Murmur3Partitioner時, 你可以通過使用token功能在一個CQL語句中查詢所有行。
RandomPartitioner 是cassandra1.2之前的預設分割槽程式,它包含向後的相容性。RandomPartitioner 可以和vnodes一起使用。然而,如果你不使用vnodes,你必須計算tokens,如Generating tokens中描述的那樣。RandomPartitioner 使用MD5 hash值作為行的鍵值來跨多個節點均勻的分佈資料。可能的hash值範圍從0-2127-1
casssandra為順序分割槽提供ByteOrderedPartition方式。他提供向後相容性。分割槽程式使用祕鑰位元組的詞法順序來排序行。通過檢視你的分割槽祕鑰資料的實際值並且使用祕鑰中前導字元的十六進位制表示形式來計算tokens的值。例如,如果你想按照行的字母順序分割槽,你可以使用16進製表示形式41帶指定A token. 使用順序分割槽允許基於主鍵 的順序查詢。這意味著你可以進行掃描就好像你通過傳統的索引移動游標一樣。例如,如果你的應用使用使用者名稱作為分割槽主鍵,你可以檢索使用者名稱落在jake和joe之間的行,這種檢索形式使用RandomPartitioner 關鍵字是不可能實現的,因為鍵是以MD5 hash值來儲存的(非順序的)。 雖然有能力在行上做範圍查詢聽起來是順序分割槽的一個可取特點,但是通過使用表索引可以實現相同的功能。 以下情況不建議使用順序分割槽程式: Difficult load balancing 對於叢集的負載均衡來說需要更多的管理開銷。一個順序的分割槽程式需要管理員基於分割槽祕鑰分配的預估值手動計算分割槽的範圍。在實踐中,一旦分散式的資料被載入,就需要積極的四處移動節點的token來容納這些資料。
Sequential writes can cause hot spots 順序寫可能導致熱點發生 如果你的應用試圖一次寫入或者更新一個順序塊的行的資料,然後這些寫入不會垮叢集分散式,他們都被提交至一個節點。這個問題通常在應用程式處理時間戳資料時產生
Uneven load balancing for multiple tables -多個表的不平衡的負載均衡 如果你的應用程式有多個表,這些表有不同的行鍵值和不同的分散式資料。順序分割槽程式使一個表平衡可能導致熱點和同一叢集下其他表的不均勻分佈。
Snitches
snitch決定節點屬於哪些資料中心和機架。他們告知cassandra使用什麼樣的網路拓撲結構以便請求被有效的路由同時讓cassandra通過將機器分組到資料中心和機架的方式來分發副本。具體來說,駐留在副本上的副本策略基於由新的snitch提供的資訊。所有節點都必須返回到同一機架和資料中心。cassandro儘量不在同一機架上儲存一個以上副本。如果你改變snitch,你需要執行額外的步驟因為snitche影響了副本的駐留位置。參考
預設情況下,所有的snitches還使用了一個動態snitch層來監視讀取延遲,並在可能的情況下,將請求從表現不佳的節點路由到別的節點。動態snitch預設情況下是可用的而且是被建議用在大多數部署上的。更多關於動態snitch如何工作,請參考 Dynamic snitching in Cassandra: past, present, and future.
在cassandra.yaml檔案中為每個節點配置動態snitch的閾值
cassandra-topology.properties檔案中的詳細網路資訊,使用這個snitch時,你可以自定義你的資料中心名字。確保資料中心的名字和祕鑰空間中定義的資料中心名字對應。叢集中的每個節點都應該在cassandra-topology.properties檔案中定義,同時,這個檔案應該和叢集上的每個節點完全等價。
產品: 如果你兩個非均勻的ip和兩個物理資料中心,每個資料中心有2個機架,一個分析資料中心用於副本資料分析。那麼cassandra-topology.properties 檔案可能類似於
# Data Center One 175.56.12.105=DC1:RAC1 120.53.24.101=DC1:RAC2 # Data Center Two 110.56.12.120=DC2:RAC1 50.33.23.120=DC2:RAC2 # Analytics Replication Group 172.106.12.120=DC3:RAC1 # default for unknown nodes
Determines the location of nodes by rack and data center. GossipingPropertyFileSnitch 的配置包含在cassandra-rackdc.properties檔案中。 為了配置一個節點使用GossipingPropertyFileSnitch ,按照如下編輯cassandra-rackdc.properties 定義資料中心和機架包含這個節點,預設的設定為: dc=DC1
資料中心和機架名字是大小寫敏感的
為了節省頻寬,新增prefer_local=true 選項,這個選項告訴cassandra當通訊非跨越多個資料中心時使用本地IP地址
從propertyfilesnitch遷移到gossipingpropertyfilesnitch 為了允許從propertyfilesnitch遷移,當cassandra-rackdc.properties檔案檔案存在時,gossipingpropertyfilesnitch會使用它。遷移完成之後刪掉這個檔案。更過關於遷移的資訊,參見
當cassandra-topology.properties檔案存在時,GossipingPropertyFileSnitch 總是匯入它。在所有叢集的每個節點上移除這個檔案,或者在任何從PropertyFileSnitch.遷移過來的叢集上移除這個檔案。
Related information
Storage engine Cassandra 使用一個類似於Log-Structured Merge Tree的儲存結構。不像典型的關係型資料庫使用B樹。Cassandra避免在寫之前讀。Read-before-write,特別是在大型分散式系統中,可能導致讀效能的大量延遲和其他問題。例如,兩個客戶端同時讀,其中一個使用UpdateA更新了行,另一個使用updateB操作更新航。同時移除UpdateA. 這種競爭將導致模糊的查詢結果,哪個update是正確的呢? 要避免在cassandra中使用在寫之前讀,儲存引擎組在記憶體中插入和更新資料,一段時間之後,順序的以追加模式將資料寫入磁碟。一旦寫入磁碟,資料將變成不可變的並且永遠不會被覆蓋。讀取資料涉及結合這個永恆不變的順序寫資料來發現正確的查詢結果。你可以使用輕量級的事物(LWT)在寫資料之前檢查資料的狀態。然而,此功能建議有限的使用它。 Log-structured引擎避免覆蓋和使用順序I/O來更新資料對於寫入SSD和HDD來說是個必要條件。在HDD上,隨機寫操作比順序寫操作涉及更多的定址操作。定址操作效能損失非常大。因此Cassandra是按順序永久寫入檔案的,因此避免了寫放大和磁碟失敗,資料庫容器很便宜,使用SSD效能會更好。對於許多其他型別資料庫,在SSD上的寫放大問題。
Cassandra 如何讀寫資料 為了管理和訪問cassandra中的資料,理解cassandra如何儲存資料非常重要。Hinted handoff特性加上cassandra對於資料庫ACID(atomic,consistent,isolated,durable)的一致性與非一致性是理解cassandra讀寫的關鍵概念。在cassandra中,一致性是指如何在所有副本上更新和同步一行資料。 客戶端工具和應用程式介面(APIs)可用於開發資料儲存和檢索的應用程式。
資料如何寫入 cassandra分為幾個階段處理資料的寫入,從log的寫入開始,以資料寫入到磁碟結束。
log寫入和記憶體儲存 當一次寫入發生時,cassandra在記憶體結構中儲存的資料稱為記憶體表,同時提供 configurable durability,.同時寫操作被追加到磁碟上的commit log中。Commit log接收每個寫入cassandra節點的寫請求,這些長久的寫操作永久存在即使一個節點斷電。記憶體表是cassandra通過鍵查詢的資料分割槽回寫快取。記憶體表按順序儲存寫操作直到達到設定上限,然後flush他們。
從記憶體表中flush資料 為了flush資料,cassandra以記憶體中的順序將資料寫入磁碟。一個分割槽索引同時在磁碟上被建立出來用來將token對映到磁碟上的一個位置。當記憶體結構表中的內容超過configurable threshold或者commitlog的空間超過了commitlog_total_space_in_mb , 記憶體表被放置在一個佇列中向磁碟flush. 這個佇列在cassandra.yaml檔案中通過 memtable_heap_space_in_mb or memtable_offheap_space_in_mb屬性來設定。如果將要flush的資料超過了memtable_cleanup_threshold的限制,cassandra將阻塞寫直到下一次flush成功。你可以使用 nodetool flushor nodetool drain手動flush一張表。為了減少commit log回溯的時間,建議的最佳做法是在重啟節點之前重新整理記憶體表。如果一個節點停止工作,回溯commit log將會使記憶體表回到節點停止前的狀態。
Commit log中的資料在對應的記憶體表中的資料被重新整理到磁碟上的SStable中後被清除。
在磁碟上的SStable中儲存資料。 記憶體表和SSTable中的每個表都是可維護的。Commit log在表之間共享。SSTable是不可變的,在記憶體表被重新整理之後不會再次被寫入。因此,一個分割槽通常跨多個SSTable檔案儲存,許多其他的sstable結構檔案用於協助讀操作。
對於每個sstable,cassandra建立如下結構: Data(Data.db) sstable資料 Primary Index(Index.db) 每行鍵的索引,指向資料檔案中他們的位置。 Bloom filter (Filter.db) 一個儲存於記憶體中的結構用於在訪問磁碟上的sstable之前檢查行資料是否存在於記憶體表 Compression Information (CompressionInfo.db) 一個用於儲存未壓縮檔案長度的資訊,資料偏移量塊和其他壓縮資訊 Statistics (Statistics.db) 關於sstable內容的統計後設資料。 Digest (Digest.crc32, Digest.adler32, Digest.sha1) 一個儲存adler32資料檔案校驗和的檔案 CRC (CRC.db) 一個儲存CRC32未壓縮檔案資料塊的檔案 SSTable Index Summary (SUMMARY.db) 一個分割槽索引儲存於記憶體中的例子 SSTable Table of Contents (TOC.txt) 一個用於儲存所有sstable TOC元件列表的檔案 Secondary Index (SI_.*.db) 內建的二級索引。每個sstable檔案可能存在多個sls
sstable是儲存在磁碟上的檔案。Cassandra2.2之後為了縮短檔案路徑改變了檔案的命名約定。資料檔案存在於通過安裝檔案安裝的資料目錄中,對於每一個祕鑰空間,每張表儲存在每個資料資料夾內。例如: /data/data/ks1/cf1-5be396077b811e3a3ab9dc4b9ac088d/la-1-big-Data.db 代表了一個資料檔案。Ks1代表了祕鑰空間名字以區別用於以流方式或者批量方式載入資料的祕鑰空間。本例中的 5be396077b811e3a3ab9dc4b9ac088d 十六進位制字串,被追加到表的名稱中代表表的唯一Id
cassandra為每個表建立一個子目錄,可以允許你將表連線到一個可選的物理驅動器或者資料卷。這提供了一種能力-將非常活躍的表移動到更快的介質上,例如SSD提供的更好執行效率,同時為了更好的儲存層I/O均衡也可以跨所有的附加儲存裝置來劃分表。
資料如何維護 Cassandra寫過程將資料儲存在稱為SSTable的結構中。SSTable是不可變得。Cassandra在新的SSTables中為插入和更新的資料寫入新的時間戳來代替插入和更新資料時覆蓋已經存在的行。同時,cassandra也不會就地刪除資料,相反,cassandra使用一個結束標記 來標記資料已經被刪除。 隨著時間的推移,cassandra可能對一行寫出很多版本,每一個在不同的sstable中。每個版本可能有一系列唯一的列儲存,使用不同的時間戳。這意味 著cassandra必須訪問越來越多的sstable以檢索整行資料。 要保證資料庫健康,cassandra定期合併sstable,丟棄舊資料,這個過程稱為壓縮。 壓縮 壓縮通過partition key來合併每個sstable表中的資料,選擇最新時間戳的資料版本。合併過程是很有效率的,因為行是按照每個sstable表分割槽鍵進行排序的,合併的過程不使用隨機I/O. 在移除刪除的列和行之後,壓縮過程整合sstables 成為一個新的單獨的sstable.只要使用舊的檔案的被掛起的讀操作完成,舊的sstable就將被刪除
壓縮導致了舊的sstable和新的sstable在磁碟空間和I/O上的臨時共存,當壓縮完成時,壓縮釋放由舊的SSTable佔據的磁碟空間。用壓縮後的sstable逐步取代舊的sstable提高了讀取的效能。Cassandra能夠直接從新的sstable表中讀取資料而不需要等待整個壓縮過程完成
當cassandra處理讀寫時,他同時在頁面快取中將舊的sstable檔案替換為新的sstable檔案。當將讀操作從舊的sstable一點點匯出時,快取新的sstable的工作在同時進行,這不會引起巨大的快取遺失。即使在高負載下,cassandra也能提供一個可預知的高效能
壓縮策略 cassandra支援不同的壓縮策略。每個都有自己的特點。為了正確的選取合適你的應用工作負載的策略,瞭解每個策略如何工作十分重要。雖然以下的每節都以廣義的介紹開始,但是如何選取一個壓縮策略仍然有很多複雜的因素。有關更多的深入瞭解每種策略有何優勢以及討論每種策略特定的用例,請參考 Which compaction strategy is best?.
SizeTieredCompactionStrategy (STCS)
建議寫密集型工作負載 當積累一系列(預設4個)相似大小的SSTable,The SizeTieredCompactionStrategy (STCS)啟動一次壓縮。 這種壓縮策略將這些sstable壓縮成一個更大的sstable. 然後這些更大的sstable被壓縮成更大的sstable.在任何給定的時間,一些不同大小的sstable是共同存在的。
這種策略對於壓縮一個寫密集型的工作負載來說能夠很好的工作,但他使讀變得很慢,因為按照大小進行合併的過程 不會按照行來進行分組。由於這個原因,更可能的是對於特定行的資料可能遍佈許多sstables。此外,對於刪除資料的回收並沒有如預期般發生,因為sstable的大小是壓縮的觸發器,同時sstable不可能增長的足夠以合併和回收舊資料。因為最大的sstable的大小不斷增長,用於壓縮儲存新舊sstable的磁碟空間的數量可能超過一個典型節點上的磁碟空間的數量。
Pros:寫密集型壓縮工作負載執行良好 Cons:可以保留陳舊的資料很長時間, 記憶體需要量隨時間而增長。
LeveledCompactionStrategy (LCS)
建議讀密集型工作負載使用 The LeveledCompactionStrategy (LCS)用於減輕STCS的有關讀操作發生的一些問題。這種策略工作在一系列的等級之上。首先,記憶體表在L0上首先被重新整理到SSTables.然後,壓縮在L1將sstables合併成更大的sstable.
大於L1等級的sstables將合併成一個大於等於sstable_size_in_mb (預設160M) 大小的sstable. 如果一個L1 等級的sstable儲存了大於L2等級的分割槽資料,LCS將把SStable移動到L2的下一等級上。 在許多插入之後的等級壓縮
在L0以上的每個等級,LCS建立相同大小的SSTable.每個等級是上一個等級的10倍大小。所以level1是L0的10倍,L2是L0的100倍。如果壓縮的結果是L1的等級 上有多於10個sstable,那麼多於的sstable將會被移動到L2。
LCS壓縮過程保證以L1開始的每層的sstable沒有重疊資料。對於許多讀取操作,這種保證可以使cassandra能夠僅從1-2個表中檢索需要的資料,事實上,所有讀取請求的90%由一張sstable就可以滿足。因為LCS不會壓縮L0的表,然而,涉及許多L0層sstable的資源密集型的讀取仍然可能發生。
在L0層之上,LCS需要較少的磁碟空間用於壓縮-通常狀況下,10倍的SSTable的固定大小。過時的資料更加頻繁的被清除,所以,在磁碟上清除sstable中使用較少的那部分資料。然而,LCS壓過過程發生的太頻繁給節點帶來了過多的I/O負擔, 對於寫密集的工作流程,使用這種策略的回報與I/O操作帶來的效能損失相比通常是不值得的。在許多情況下,LCS-configured測試表揭示了寫和壓縮的I/O飽和程度
Cassandra2.2以後使用LCS在叢集中引導一個新的節點效能改進繞過了壓縮操作,原始的資料直接被移動到了正確的LEVEL因為沒有已經存在的資料。所以每層沒有分割槽層疊出現。更多的資訊,請參考Apache Apache Cassandra 2.2 - Bootstrapping Performance Improvements for Leveled Compaction.
好處:磁碟要求更容易預測。讀操作延遲更容易遇見。陳舊的資料更加頻繁的被清楚。 缺點:更高的I/O利用率影響操作的延遲
DateTieredCompactionStrategy (DTCS)
建議時間序列和到期時間工作流使用
DTCS與STCS類似。但是不是基於SSTable的大小而壓縮,而是基於SSTable的年齡而壓縮。配置time windows確保新資料和舊資料不會在在合併表中被混合。事實上,使用(Time-To-Live)TTL時間戳,DTCS可以將全部的過期資料都清理出去。如果時間序列的提取以一個平穩的速率,這種策略經常會生成類似大小的sstable表。
當系統在可配置的時間間隔內達到了確定的最低限度數目的sstable的時候,DTCS將會合並sstable表。就像在STC中的一樣,需要的sstable數量在給定的時間內減少時,DTCS將sstable表合併成一個更大的表。然而,DTCS放棄壓縮到達了一個按照配置確定的階段的SSTable。這減少了時間資料的重寫次數。 對於最後一個小時的有價值的資料的查詢(或者與配置的時間間隔良好協調的其他時間間隔)能在DTCS-compacted sstables上被非常高效率的執行。
有一種情況使用這種策略會導致困難-無序寫入,例如:一次操作使用了一個過去的時間戳寫入了一條時間戳記錄。讀取修改可能引入一條無需的時間戳,所以,確保當使用DTCS時關閉讀取修改功能。
好處:專門用於時間序列資料 缺點:無序的時間注入可能引起錯誤。讀取修復必須關閉DTCS,同時時間戳操作不允許使用BATCH, DELETE, INSERT and UPDATE CQL 命令。
那種壓縮策略最好: 要實現最好的壓縮策略: 1 重新審視你的應用的需求 2 配置表以使用最合適的策略 3 針對你的資料測試壓縮策略
以下的問題基於cassandra開發者和使用者的經驗來描述上述策略
你的表格需要處理時間序列資料嗎? 如果需要,DTCS是你最好的選擇。要避免問題發生,重審上述描述。如果你的表格不關注時間序列資料,那麼選擇可能會變得很複雜,以下關於其他因素的介紹問題可以指導你的選擇。
你的表是處理讀多還是寫多? 如果你的表處理讀是寫的2倍以上那麼LCS是個很好的選擇,特別是隨機讀。如果讀寫比例接近,那麼LCS的效能損失帶來的弊端將比利益還高。避免LCS被高容量的寫入搞得很快不堪重負。 表中的資料經常變嗎? LCS的一個優勢是它在一個小的SSTable集合中儲存相關資料。如果你的資料不可變或者不受經常的插入刪除的影響,STCS可以實現相同型別的分組而不受LCS效能的影響。
你需要讀寫活動的預測值嗎? LCS在可預見的的大小和數量內保持SSTable,例如,如果你的表的讀/寫 率很小,同時在讀上期望符合Service Level agrrementst(SLA),LCS為了在可預見的等級上保證讀的效率和延遲而帶來的寫的效能損失是值得的。同時你可以通過橫向擴充套件增加更多節點來克服寫上的損失。 你的表將由批處理程式填充嗎? 對於批處理讀寫,STCS的效能要高於LCS。批處理基本不會產生碎片,而LCS卻沒有這種好處。同時批處理操作也是壓垮LCS-configured 表。 你的系統有磁碟空間限制嗎? LCS處理磁碟空間比STCS更有效率;除了用於資料處理,還需要10%的額外空間。STCS和DTCS大多數情況需要50%以上的剩餘空間。 你的系統到達了I/O限制了嗎? LCS比DTCS或者STCS需要更多的I/O操作,切換到LCS可能帶來更多的I/P負載以抵消其優勢。
測試壓縮策略 一些建議用來決定哪個壓縮策略適合你的系統: 1 使用其中的一個壓縮策略建立一個三個節點的叢集,使用cassandra-stress進行壓力測試,檢視結果 2 在已經存在的叢集上建立一個節點同時使用cassandra 寫測量模式來舉例live data。請參考 What’s new in Cassandra 1.1: live traffic sampling.
配置和執行壓縮 在create table 或者 alter table命令中使用引數來為一張表設定壓縮策略。具體請參考
你可以使用nodetool compact 命令手動開始壓縮。
更多關於壓縮的資訊 以下一些開發者部落格提供了更多關於測試壓縮策略的資訊
資料如何更新? 插入一個完全一個樣的主鍵被視為upsert. 如果一條記錄在資料庫中不存在,一個upsert將在資料庫中寫入一條記錄. 如果那條資料的主鍵已經存在,一條新的包含一個最新時間戳的記錄將被寫入。如果這條資料在一次讀請求中被檢索,只有最新的記錄會被檢索到,老一點的時間戳資料將被標記為刪除。最後的效果類似於使用新資料交換覆蓋舊資料,即使cassandra不會覆蓋資料。最終,更新使用順序I/O儲存到磁碟存於新的sstable. 在更新期間,cassandra使用 記錄時間戳並且在磁碟上寫入列。如果使用者多次寫入相同的資料,只有記憶體表中儲存的最新的資料才會被重新整理到磁碟上。
資料如何刪除? Cassandra刪除資料的過程被設計用來改進效能,同時與cassandra內建的屬性一起工作來分散式資料和提高容錯。 Cassandra將刪除視為插入或者upsert,以delete 命令加入分割槽的資料其實是一個叫做tombstone 的刪除標記。墓碑經過Cassandra的寫路徑,被寫入一個或多個節點的sstable中。墓碑關鍵的區別特徵是:它有一個內建的過期時間,在過期時間結束時,墓碑將作為正常Cassandra壓縮過程的一部分被刪除。
在一個分散式系統中刪除 在一個多節點叢集中,cassandra在兩個或者更多節點上儲存同一資料的多個副本,這防止了資料的丟失,但這複雜化了刪除過程。如果一個節點收到了一條刪除它所儲存的本地資料的命令,該節點墓碑指定的記錄並試圖將墓碑傳遞到包含該記錄的副本的其他節點上。但如果一個副本節點在那個時刻沒有響應,它沒有馬上收到墓碑,所以它仍然包含著預刪除記錄的版本。如果在該節點恢復前叢集中的其他節點已經刪除了墓碑,Cassandra把該剛恢復過來的節點上的這條記錄視為新資料,然後把他傳播到叢集中其他的節點上。這種標記為已經刪除但是仍然存在的記錄被稱為 為了防止殭屍記錄的再現,cassandra給予每一個墓碑一個過渡期。這個過渡期的目的是給予響應節點時間以恢復和正常處理墓碑。如果一個客戶端在過渡期內向墓碑記錄傳送了一條更新命令,cassandra將會覆蓋該墓碑。如果一個客戶端在過渡期向墓碑記錄傳送了一條讀命令,cassandra將忽略這個墓碑同時從其他副本查詢可能存在的該條記錄。
當一個停止響應的節點恢復時,cassandra使用 hinted handoff 來重做當節點掛掉時未作的資料庫的插入和刪除。在一個墓碑的過渡期,cassandra不會重做插入和刪除。如果一個節點在過渡期結束後仍然沒有恢復,cassandra可能會錯過刪除這個節點。
Hinted Handoff: repair during write path 有時,當資料被寫入時一個節點會變得不可用。不可用的原因可能是硬體原因,網路問題,或者過載節點經歷了長時間的垃圾收集後暫停的。按照設計,hinted handoff 本質上允許Cassandra在叢集的執行能力下降時仍然可以繼續執行相同數量的寫。
如果hinted handoff 在cassandra.yaml 中被啟用,在故障檢測器將一個節點標記為down之後,錯過的寫操作將被協調員儲存一段時間。在cassandra3.0及其之後,hint儲存於每個節點的本地hint目錄以改進重做的效能。對於標記為downed的節點,hint由一個target ID,一個hint ID(即一個時間UUID),一個標示cassandra版本的訊息ID和資料塊本身組成。Hint每10秒鐘被重新整理到磁碟一次,減少過時的hint。當gossip發現一個節點已經重新上線時,協調員重新執行每個剩餘的hint以便將資料寫入新返回的節點,然後將hint 檔案刪除。如果一個節點關閉超過max_hint_window_in_ms (預設為3小時),協調員將停止寫入新的hints.
協調員還會通過gossip每十分鐘檢查一次由於停電故障造成的hint寫入超時,如果一個備份節點被過載或者變得不可用,而且故障檢測器還沒有將這個節點標記為不可用,那麼將會預料到大多數或者全部對於節點的寫操作在由write_request_timeout_in_ms, (10 seconds by default).引起的超時之後將會失敗。協調員返回一個TimeOutException異常,寫入將會失敗但是hint將會被儲存。
如果多個節點同時經理短暫中斷,
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Cassandra assigns a hash value to each partition key:
Partition key | Murmur3 hash value |
jim | -2245462676723223822 |
carol | 7723358927203680754 |
johnny | -6723372854036780875 |
suzy | 1168604627387940318 |
叢集中的每個節點對基於hash值得一段資料負責。在叢集中四個節點的hash值
cassandra基於partition key的值和每個節點所負責的值得範圍來為每個節點分配資料。例如,在一個4個節點的叢集 中,資料如下分佈
Node | Start range | End range | Partition key | Hash value |
A | -9223372036854775808 | -4611686018427387904 | johnny | -6723372854036780875 |
B | -4611686018427387903 | -1 | jim | -2245462676723223822 |
C | 0 | 4611686018427387903 | suzy | 1168604627387940318 |
D | 4611686018427387904 | 9223372036854775807 | carol | 7723358927203680754 |
Virtual nodes
虛擬節點,稱為Vnodes,以更新的力度跨節點分佈資料,如果使用計算token的話這很容易實現。Vnodes簡化了cassadra中的許多工。
- Tokens被自動計算和分配給每個節點
- 當新增和刪除節點時再平衡叢集自動完成。當一個節點加入叢集時,假設該節點為叢集中其他節點的部分資料負責(即其他節點中的部分資料再平衡後應該儲存在該節點上),如果一個節點掛掉了,負載均勻的分佈到叢集中的其他節點上。
- 重建一個死去的節點很快因為這涉及了叢集中每個其他節點
- 分配給每臺機器的虛擬節點的比例可以被指定,所以較小和較大的計算機可以用於構建叢集。
更多資訊,請參考cassandora1.2 中關於虛擬節點的主題。
Virtual nodes in Cassandra 1.2
將一個存在的節點轉換為虛擬節點,參考
Enabling virtual nodes on an existing production cluster.
How data is distributed across a cluster (using virtual nodes)
虛擬節點使用一致性hash來分配資料,不需要生成和分配新的token
Partitioners
一個partitioner決定資料分散式的儲存在叢集中的節點上(包括副本)。基本上,分割槽程式使用hash函式從partition key中派生出一個token,該token代表了一行資料。每行的資料之後按token的值跨叢集分佈。
Murmur3Partitioner 和RandomPartitioner 使用token來為每個節點分配相同比例的資料,表格中的資料均等的分佈在整個環上,或是其他組上如祕鑰空間。即使表使用不同的分割槽鍵如username或者timestamps也是按這種情況來做。而且在此基礎上,對於叢集的讀寫操作也被均勻的分佈,負載均衡被簡化因為hash range的每個部分獲取到row的數量是均等的。更多細節參考
這兩個分割槽演算法的區別是如何生成token的hash值,RandomPartitioner 使用一個加密hash,他生成hash的時間要比Murmur3Partitioner 長,Cassoandra不需要加密hash,所以使用Murmur3Partitioner 在3-5分鐘內產生完hash值可以改進效率。
Cassandra支援如下的分割槽程式,可以在cassandra.yaml檔案中設定他們。
Murmur3Partitioner (預設)基於MurmurHash hash值跨叢集均勻分佈節點。
RandomPartitioner 基於MD5 hash值跨叢集均勻分佈節點。
ByteOrderedPartition 按照資料的祕鑰位元組字典順序有序分佈。
Murmur3Partitioner 作為預設的分割槽策略應用於cassandra1.2以後,在部分情況下作為生成新叢集的首選。
然而,分割槽程式間並不相容, 使用一種分割槽程式後很難再轉換為另一種分割槽程式。
如果使用虛擬節點(vnodes),你不必計算tokens。如果不使用vnodes,你必須計算tokens的數量然後為cassandra.yaml檔案中的initial_token引數賦值。請參見
Generating tokens 同時使用某種分割槽程式的對應方法。
- Murmur3Partitioner
The Murmur3Partitioner provides fast hashing and good performance.
Murmur3Partitioner是預設分割槽程式,Murmur3Partitioner比RandomPartitioner更快更有效率,Murmur3Partitioner 可以使用vnodes,然而,如果你不使用vnodes,你必須計算token的數量,正如
Generating tokens中描述的那樣。
為新的叢集使用Murmur3Partitioner。你無法將已經存在的叢集的分割槽程式改變為另一種分割槽程式。Murmur3Partitioner使用
MurmurHash 函式。該 雜湊函式建立一個64-bit的hash值作為分割槽鍵,可能的hash值得範圍從
-263 to +263-1
當使用Murmur3Partitioner時,
你可以通過使用token功能在一個CQL語句中查詢所有行。
- RandomPartitioner
The default partitioner prior to Cassandra 1.2.
RandomPartitioner 是cassandra1.2之前的預設分割槽程式,它包含向後的相容性。RandomPartitioner 可以和vnodes一起使用。然而,如果你不使用vnodes,你必須計算tokens,如Generating tokens中描述的那樣。RandomPartitioner 使用MD5 hash值作為行的鍵值來跨多個節點均勻的分佈資料。可能的hash值範圍從0-2127-1
- ByteOrderedPartitioner
Cassandra provides this partitioner for ordered partitioning. It is included for backwards compatibility.
casssandra為順序分割槽提供ByteOrderedPartition方式。他提供向後相容性。分割槽程式使用祕鑰位元組的詞法順序來排序行。通過檢視你的分割槽祕鑰資料的實際值並且使用祕鑰中前導字元的十六進位制表示形式來計算tokens的值。例如,如果你想按照行的字母順序分割槽,你可以使用16進製表示形式41帶指定A token.
使用順序分割槽允許基於主鍵 的順序查詢。這意味著你可以進行掃描就好像你通過傳統的索引移動游標一樣。例如,如果你的應用使用使用者名稱作為分割槽主鍵,你可以檢索使用者名稱落在jake和joe之間的行,這種檢索形式使用RandomPartitioner 關鍵字是不可能實現的,因為鍵是以MD5 hash值來儲存的(非順序的)。
雖然有能力在行上做範圍查詢聽起來是順序分割槽的一個可取特點,但是通過使用表索引可以實現相同的功能。
以下情況不建議使用順序分割槽程式:
Difficult load balancing
對於叢集的負載均衡來說需要更多的管理開銷。一個順序的分割槽程式需要管理員基於分割槽祕鑰分配的預估值手動計算分割槽的範圍。在實踐中,一旦分散式的資料被載入,就需要積極的四處移動節點的token來容納這些資料。
Sequential writes can cause hot spots 順序寫可能導致熱點發生
如果你的應用試圖一次寫入或者更新一個順序塊的行的資料,然後這些寫入不會垮叢集分散式,他們都被提交至一個節點。這個問題通常在應用程式處理時間戳資料時產生
Uneven load balancing for multiple tables -多個表的不平衡的負載均衡
如果你的應用程式有多個表,這些表有不同的行鍵值和不同的分散式資料。順序分割槽程式使一個表平衡可能導致熱點和同一叢集下其他表的不均勻分佈。
Snitches
snitch決定節點屬於哪些資料中心和機架。他們告知cassandra使用什麼樣的網路拓撲結構以便請求被有效的路由同時讓cassandra通過將機器分組到資料中心和機架的方式來分發副本。具體來說,駐留在副本上的副本策略基於由新的snitch提供的資訊。所有節點都必須返回到同一機架和資料中心。cassandro儘量不在同一機架上儲存一個以上副本。如果你改變snitch,你需要執行額外的步驟因為snitche影響了副本的駐留位置。參考
- Dynamic snitching
Monitors the performance of reads from the various replicas and chooses the best replica based on this history.
預設情況下,所有的snitches還使用了一個動態snitch層來監視讀取延遲,並在可能的情況下,將請求從表現不佳的節點路由到別的節點。動態snitch預設情況下是可用的而且是被建議用在大多數部署上的。更多關於動態snitch如何工作,請參考
Dynamic snitching in Cassandra: past, present, and future.
在cassandra.yaml檔案中為每個節點配置動態snitch的閾值
- SimpleSnitch
The SimpleSnitch is used only for single-data center deployments. - Simplesnitch 用於單資料中心的部署。它不識別資料中心或機架資訊並且僅能使用者單資料中心部署或者公共雲上的單個區域。
- RackInferringSnitch
Determines the location of nodes by rack and data center corresponding to the IP addresses.
- RackInferringSnitch 由資料中心和機架確定相鄰的節點,假設分別對應於節點ip地址的第三和第二部分。這種snitch最好用於編寫一個客戶自定義snitch 類的示例。
- PropertyFileSnitch 自己決定每個資料中心和機架內的節點IP
- 這種snitch由機架和資料中心決定相鄰的節點。它使用在
cassandra-topology.properties檔案中的詳細網路資訊,使用這個snitch時,你可以自定義你的資料中心名字。確保資料中心的名字和祕鑰空間中定義的資料中心名字對應。叢集中的每個節點都應該在cassandra-topology.properties檔案中定義,同時,這個檔案應該和叢集上的每個節點完全等價。
產品:
如果你兩個非均勻的ip和兩個物理資料中心,每個資料中心有2個機架,一個分析資料中心用於副本資料分析。那麼cassandra-topology.properties 檔案可能類似於
# Data Center One
175.56.12.105=DC1:RAC1
175.50.13.200=DC1:RAC1
175.54.35.197=DC1:RAC1
120.53.24.101=DC1:RAC2
120.55.16.200=DC1:RAC2
120.57.102.103=DC1:RAC2
# Data Center Two
110.56.12.120=DC2:RAC1
110.50.13.201=DC2:RAC1
110.54.35.184=DC2:RAC1
50.33.23.120=DC2:RAC2
50.45.14.220=DC2:RAC2
50.17.10.203=DC2:RAC2
# Analytics Replication Group
172.106.12.120=DC3:RAC1
172.106.12.121=DC3:RAC1
172.106.12.122=DC3:RAC1
# default for unknown nodes
default =DC3:RAC1
Determines the location of nodes by rack and data center.
- GossipingPropertyFileSnitch-建議生產環境使用
- Automatically updates all nodes using gossip when adding new nodes and is recommended for production.
- 生產環境建議使用這個snitch.它使用在cassandra-rackdc.properties 檔案中定義的節點的機架和資料中心資訊並把這些資訊通過gossip傳播到其他節點。
GossipingPropertyFileSnitch 的配置包含在cassandra-rackdc.properties檔案中。
為了配置一個節點使用GossipingPropertyFileSnitch ,按照如下編輯cassandra-rackdc.properties
定義資料中心和機架包含這個節點,預設的設定為:
dc=DC1
rack=RAC1
資料中心和機架名字是大小寫敏感的
為了節省頻寬,新增prefer_local=true 選項,這個選項告訴cassandra當通訊非跨越多個資料中心時使用本地IP地址
從propertyfilesnitch遷移到gossipingpropertyfilesnitch
為了允許從propertyfilesnitch遷移,當cassandra-rackdc.properties檔案檔案存在時,gossipingpropertyfilesnitch會使用它。遷移完成之後刪掉這個檔案。更過關於遷移的資訊,參見
當cassandra-topology.properties檔案存在時,GossipingPropertyFileSnitch 總是匯入它。在所有叢集的每個節點上移除這個檔案,或者在任何從PropertyFileSnitch.遷移過來的叢集上移除這個檔案。
- Ec2Snitch
Use the Ec2Snitch with Amazon EC2 in a single region. - Ec2MultiRegionSnitch
Use the Ec2MultiRegionSnitch for deployments on Amazon EC2 where the cluster spans multiple regions. - GoogleCloudSnitch
Use the GoogleCloudSnitch for Cassandra deployments on Google Cloud Platform across one or more regions. - CloudstackSnitch
Use the CloudstackSnitch for Apache Cloudstack environments.
Related information
Storage engine
Cassandra 使用一個類似於Log-Structured Merge Tree的儲存結構。不像典型的關係型資料庫使用B樹。Cassandra避免在寫之前讀。Read-before-write,特別是在大型分散式系統中,可能導致讀效能的大量延遲和其他問題。例如,兩個客戶端同時讀,其中一個使用UpdateA更新了行,另一個使用updateB操作更新航。同時移除UpdateA. 這種競爭將導致模糊的查詢結果,哪個update是正確的呢?
要避免在cassandra中使用在寫之前讀,儲存引擎組在記憶體中插入和更新資料,一段時間之後,順序的以追加模式將資料寫入磁碟。一旦寫入磁碟,資料將變成不可變的並且永遠不會被覆蓋。讀取資料涉及結合這個永恆不變的順序寫資料來發現正確的查詢結果。你可以使用輕量級的事物(LWT)在寫資料之前檢查資料的狀態。然而,此功能建議有限的使用它。
Log-structured引擎避免覆蓋和使用順序I/O來更新資料對於寫入SSD和HDD來說是個必要條件。在HDD上,隨機寫操作比順序寫操作涉及更多的定址操作。定址操作效能損失非常大。因此Cassandra是按順序永久寫入檔案的,因此避免了寫放大和磁碟失敗,資料庫容器很便宜,使用SSD效能會更好。對於許多其他型別資料庫,在SSD上的寫放大問題。
Cassandra 如何讀寫資料
為了管理和訪問cassandra中的資料,理解cassandra如何儲存資料非常重要。Hinted handoff特性加上cassandra對於資料庫ACID(atomic,consistent,isolated,durable)的一致性與非一致性是理解cassandra讀寫的關鍵概念。在cassandra中,一致性是指如何在所有副本上更新和同步一行資料。
客戶端工具和應用程式介面(APIs)可用於開發資料儲存和檢索的應用程式。
資料如何寫入
cassandra分為幾個階段處理資料的寫入,從log的寫入開始,以資料寫入到磁碟結束。
- 在commit log中記錄log
- 在記憶體中寫入資料
- 從記憶體中將資料匯出
- 在磁碟上的SSTable中儲存資料
log寫入和記憶體儲存
當一次寫入發生時,cassandra在記憶體結構中儲存的資料稱為記憶體表,同時提供
configurable durability,.同時寫操作被追加到磁碟上的commit log中。Commit log接收每個寫入cassandra節點的寫請求,這些長久的寫操作永久存在即使一個節點斷電。記憶體表是cassandra通過鍵查詢的資料分割槽回寫快取。記憶體表按順序儲存寫操作直到達到設定上限,然後flush他們。
從記憶體表中flush資料
為了flush資料,cassandra以記憶體中的順序將資料寫入磁碟。一個分割槽索引同時在磁碟上被建立出來用來將token對映到磁碟上的一個位置。當記憶體結構表中的內容超過configurable threshold或者commitlog的空間超過了commitlog_total_space_in_mb , 記憶體表被放置在一個佇列中向磁碟flush. 這個佇列在cassandra.yaml檔案中通過
memtable_heap_space_in_mb or memtable_offheap_space_in_mb屬性來設定。如果將要flush的資料超過了memtable_cleanup_threshold的限制,cassandra將阻塞寫直到下一次flush成功。你可以使用
nodetool flushor nodetool drain手動flush一張表。為了減少commit log回溯的時間,建議的最佳做法是在重啟節點之前重新整理記憶體表。如果一個節點停止工作,回溯commit log將會使記憶體表回到節點停止前的狀態。
Commit log中的資料在對應的記憶體表中的資料被重新整理到磁碟上的SStable中後被清除。
在磁碟上的SStable中儲存資料。
記憶體表和SSTable中的每個表都是可維護的。Commit log在表之間共享。SSTable是不可變的,在記憶體表被重新整理之後不會再次被寫入。因此,一個分割槽通常跨多個SSTable檔案儲存,許多其他的sstable結構檔案用於協助讀操作。
對於每個sstable,cassandra建立如下結構:
Data(Data.db)
sstable資料
Primary Index(Index.db)
每行鍵的索引,指向資料檔案中他們的位置。
Bloom filter (Filter.db)
一個儲存於記憶體中的結構用於在訪問磁碟上的sstable之前檢查行資料是否存在於記憶體表
Compression Information (CompressionInfo.db)
一個用於儲存未壓縮檔案長度的資訊,資料偏移量塊和其他壓縮資訊
Statistics (Statistics.db)
關於sstable內容的統計後設資料。
Digest (Digest.crc32, Digest.adler32, Digest.sha1)
一個儲存adler32資料檔案校驗和的檔案
CRC (CRC.db)
一個儲存CRC32未壓縮檔案資料塊的檔案
SSTable Index Summary (SUMMARY.db)
一個分割槽索引儲存於記憶體中的例子
SSTable Table of Contents (TOC.txt)
一個用於儲存所有sstable TOC元件列表的檔案
Secondary Index (SI_.*.db)
內建的二級索引。每個sstable檔案可能存在多個sls
sstable是儲存在磁碟上的檔案。Cassandra2.2之後為了縮短檔案路徑改變了檔案的命名約定。資料檔案存在於通過安裝檔案安裝的資料目錄中,對於每一個祕鑰空間,每張表儲存在每個資料資料夾內。例如:
/data/data/ks1/cf1-5be396077b811e3a3ab9dc4b9ac088d/la-1-big-Data.db
代表了一個資料檔案。Ks1代表了祕鑰空間名字以區別用於以流方式或者批量方式載入資料的祕鑰空間。本例中的
5be396077b811e3a3ab9dc4b9ac088d 十六進位制字串,被追加到表的名稱中代表表的唯一Id
cassandra為每個表建立一個子目錄,可以允許你將表連線到一個可選的物理驅動器或者資料卷。這提供了一種能力-將非常活躍的表移動到更快的介質上,例如SSD提供的更好執行效率,同時為了更好的儲存層I/O均衡也可以跨所有的附加儲存裝置來劃分表。
資料如何維護
Cassandra寫過程將資料儲存在稱為SSTable的結構中。SSTable是不可變得。Cassandra在新的SSTables中為插入和更新的資料寫入新的時間戳來代替插入和更新資料時覆蓋已經存在的行。同時,cassandra也不會就地刪除資料,相反,cassandra使用一個結束標記
來標記資料已經被刪除。
隨著時間的推移,cassandra可能對一行寫出很多版本,每一個在不同的sstable中。每個版本可能有一系列唯一的列儲存,使用不同的時間戳。這意味 著cassandra必須訪問越來越多的sstable以檢索整行資料。
要保證資料庫健康,cassandra定期合併sstable,丟棄舊資料,這個過程稱為壓縮。
壓縮
壓縮通過partition key來合併每個sstable表中的資料,選擇最新時間戳的資料版本。合併過程是很有效率的,因為行是按照每個sstable表分割槽鍵進行排序的,合併的過程不使用隨機I/O. 在移除刪除的列和行之後,壓縮過程整合sstables 成為一個新的單獨的sstable.只要使用舊的檔案的被掛起的讀操作完成,舊的sstable就將被刪除
壓縮導致了舊的sstable和新的sstable在磁碟空間和I/O上的臨時共存,當壓縮完成時,壓縮釋放由舊的SSTable佔據的磁碟空間。用壓縮後的sstable逐步取代舊的sstable提高了讀取的效能。Cassandra能夠直接從新的sstable表中讀取資料而不需要等待整個壓縮過程完成
當cassandra處理讀寫時,他同時在頁面快取中將舊的sstable檔案替換為新的sstable檔案。當將讀操作從舊的sstable一點點匯出時,快取新的sstable的工作在同時進行,這不會引起巨大的快取遺失。即使在高負載下,cassandra也能提供一個可預知的高效能
壓縮策略
cassandra支援不同的壓縮策略。每個都有自己的特點。為了正確的選取合適你的應用工作負載的策略,瞭解每個策略如何工作十分重要。雖然以下的每節都以廣義的介紹開始,但是如何選取一個壓縮策略仍然有很多複雜的因素。有關更多的深入瞭解每種策略有何優勢以及討論每種策略特定的用例,請參考
Which compaction strategy is best?.
SizeTieredCompactionStrategy (STCS)
建議寫密集型工作負載
當積累一系列(預設4個)相似大小的SSTable,The SizeTieredCompactionStrategy (STCS)啟動一次壓縮。 這種壓縮策略將這些sstable壓縮成一個更大的sstable. 然後這些更大的sstable被壓縮成更大的sstable.在任何給定的時間,一些不同大小的sstable是共同存在的。
這種策略對於壓縮一個寫密集型的工作負載來說能夠很好的工作,但他使讀變得很慢,因為按照大小進行合併的過程
不會按照行來進行分組。由於這個原因,更可能的是對於特定行的資料可能遍佈許多sstables。此外,對於刪除資料的回收並沒有如預期般發生,因為sstable的大小是壓縮的觸發器,同時sstable不可能增長的足夠以合併和回收舊資料。因為最大的sstable的大小不斷增長,用於壓縮儲存新舊sstable的磁碟空間的數量可能超過一個典型節點上的磁碟空間的數量。
Pros:寫密集型壓縮工作負載執行良好
Cons:可以保留陳舊的資料很長時間, 記憶體需要量隨時間而增長。
LeveledCompactionStrategy (LCS)
建議讀密集型工作負載使用
The LeveledCompactionStrategy (LCS)用於減輕STCS的有關讀操作發生的一些問題。這種策略工作在一系列的等級之上。首先,記憶體表在L0上首先被重新整理到SSTables.然後,壓縮在L1將sstables合併成更大的sstable.
大於L1等級的sstables將合併成一個大於等於sstable_size_in_mb (預設160M)
大小的sstable. 如果一個L1 等級的sstable儲存了大於L2等級的分割槽資料,LCS將把SStable移動到L2的下一等級上。
在許多插入之後的等級壓縮
在L0以上的每個等級,LCS建立相同大小的SSTable.每個等級是上一個等級的10倍大小。所以level1是L0的10倍,L2是L0的100倍。如果壓縮的結果是L1的等級 上有多於10個sstable,那麼多於的sstable將會被移動到L2。
LCS壓縮過程保證以L1開始的每層的sstable沒有重疊資料。對於許多讀取操作,這種保證可以使cassandra能夠僅從1-2個表中檢索需要的資料,事實上,所有讀取請求的90%由一張sstable就可以滿足。因為LCS不會壓縮L0的表,然而,涉及許多L0層sstable的資源密集型的讀取仍然可能發生。
在L0層之上,LCS需要較少的磁碟空間用於壓縮-通常狀況下,10倍的SSTable的固定大小。過時的資料更加頻繁的被清除,所以,在磁碟上清除sstable中使用較少的那部分資料。然而,LCS壓過過程發生的太頻繁給節點帶來了過多的I/O負擔,
對於寫密集的工作流程,使用這種策略的回報與I/O操作帶來的效能損失相比通常是不值得的。在許多情況下,LCS-configured測試表揭示了寫和壓縮的I/O飽和程度
Cassandra2.2以後使用LCS在叢集中引導一個新的節點效能改進繞過了壓縮操作,原始的資料直接被移動到了正確的LEVEL因為沒有已經存在的資料。所以每層沒有分割槽層疊出現。更多的資訊,請參考Apache
Apache Cassandra 2.2 - Bootstrapping Performance Improvements for Leveled Compaction.
好處:磁碟要求更容易預測。讀操作延遲更容易遇見。陳舊的資料更加頻繁的被清楚。
缺點:更高的I/O利用率影響操作的延遲
DateTieredCompactionStrategy (DTCS)
建議時間序列和到期時間工作流使用
DTCS與STCS類似。但是不是基於SSTable的大小而壓縮,而是基於SSTable的年齡而壓縮。配置time windows確保新資料和舊資料不會在在合併表中被混合。事實上,使用(Time-To-Live)TTL時間戳,DTCS可以將全部的過期資料都清理出去。如果時間序列的提取以一個平穩的速率,這種策略經常會生成類似大小的sstable表。
當系統在可配置的時間間隔內達到了確定的最低限度數目的sstable的時候,DTCS將會合並sstable表。就像在STC中的一樣,需要的sstable數量在給定的時間內減少時,DTCS將sstable表合併成一個更大的表。然而,DTCS放棄壓縮到達了一個按照配置確定的階段的SSTable。這減少了時間資料的重寫次數。
對於最後一個小時的有價值的資料的查詢(或者與配置的時間間隔良好協調的其他時間間隔)能在DTCS-compacted sstables上被非常高效率的執行。
有一種情況使用這種策略會導致困難-無序寫入,例如:一次操作使用了一個過去的時間戳寫入了一條時間戳記錄。讀取修改可能引入一條無需的時間戳,所以,確保當使用DTCS時關閉讀取修改功能。
好處:專門用於時間序列資料
缺點:無序的時間注入可能引起錯誤。讀取修復必須關閉DTCS,同時時間戳操作不允許使用BATCH, DELETE, INSERT and UPDATE CQL 命令。
那種壓縮策略最好:
要實現最好的壓縮策略:
1 重新審視你的應用的需求
2 配置表以使用最合適的策略
3 針對你的資料測試壓縮策略
以下的問題基於cassandra開發者和使用者的經驗來描述上述策略
你的表格需要處理時間序列資料嗎?
如果需要,DTCS是你最好的選擇。要避免問題發生,重審上述描述。如果你的表格不關注時間序列資料,那麼選擇可能會變得很複雜,以下關於其他因素的介紹問題可以指導你的選擇。
你的表是處理讀多還是寫多?
如果你的表處理讀是寫的2倍以上那麼LCS是個很好的選擇,特別是隨機讀。如果讀寫比例接近,那麼LCS的效能損失帶來的弊端將比利益還高。避免LCS被高容量的寫入搞得很快不堪重負。
表中的資料經常變嗎?
LCS的一個優勢是它在一個小的SSTable集合中儲存相關資料。如果你的資料不可變或者不受經常的插入刪除的影響,STCS可以實現相同型別的分組而不受LCS效能的影響。
你需要讀寫活動的預測值嗎?
LCS在可預見的的大小和數量內保持SSTable,例如,如果你的表的讀/寫 率很小,同時在讀上期望符合Service Level agrrementst(SLA),LCS為了在可預見的等級上保證讀的效率和延遲而帶來的寫的效能損失是值得的。同時你可以通過橫向擴充套件增加更多節點來克服寫上的損失。
你的表將由批處理程式填充嗎?
對於批處理讀寫,STCS的效能要高於LCS。批處理基本不會產生碎片,而LCS卻沒有這種好處。同時批處理操作也是壓垮LCS-configured 表。
你的系統有磁碟空間限制嗎?
LCS處理磁碟空間比STCS更有效率;除了用於資料處理,還需要10%的額外空間。STCS和DTCS大多數情況需要50%以上的剩餘空間。
你的系統到達了I/O限制了嗎?
LCS比DTCS或者STCS需要更多的I/O操作,切換到LCS可能帶來更多的I/P負載以抵消其優勢。
測試壓縮策略
一些建議用來決定哪個壓縮策略適合你的系統:
1 使用其中的一個壓縮策略建立一個三個節點的叢集,使用cassandra-stress進行壓力測試,檢視結果
2 在已經存在的叢集上建立一個節點同時使用cassandra 寫測量模式來舉例live data。請參考
What’s new in Cassandra 1.1: live traffic sampling.
配置和執行壓縮
在create table 或者 alter table命令中使用引數來為一張表設定壓縮策略。具體請參考
你可以使用nodetool compact 命令手動開始壓縮。
更多關於壓縮的資訊
以下一些開發者部落格提供了更多關於測試壓縮策略的資訊
- When to Use Leveled Compaction
- Leveled compaction in Apache Cassandra
- DateTieredCompactionStrategy: Notes from the Field
- Date-Tiered Compaction in Cassandra
- DateTieredCompactionStrategy: Compaction for Time Series Data.
- What delays a tombstone purge when using LCS in Cassandra
資料如何更新?
插入一個完全一個樣的主鍵被視為upsert. 如果一條記錄在資料庫中不存在,一個upsert將在資料庫中寫入一條記錄. 如果那條資料的主鍵已經存在,一條新的包含一個最新時間戳的記錄將被寫入。如果這條資料在一次讀請求中被檢索,只有最新的記錄會被檢索到,老一點的時間戳資料將被標記為刪除。最後的效果類似於使用新資料交換覆蓋舊資料,即使cassandra不會覆蓋資料。最終,更新使用順序I/O儲存到磁碟存於新的sstable. 在更新期間,cassandra使用
記錄時間戳並且在磁碟上寫入列。如果使用者多次寫入相同的資料,只有記憶體表中儲存的最新的資料才會被重新整理到磁碟上。
資料如何刪除?
Cassandra刪除資料的過程被設計用來改進效能,同時與cassandra內建的屬性一起工作來分散式資料和提高容錯。
Cassandra將刪除視為插入或者upsert,以delete 命令加入分割槽的資料其實是一個叫做tombstone
的刪除標記。墓碑經過Cassandra的寫路徑,被寫入一個或多個節點的sstable中。墓碑關鍵的區別特徵是:它有一個內建的過期時間,在過期時間結束時,墓碑將作為正常Cassandra壓縮過程的一部分被刪除。
在一個分散式系統中刪除
在一個多節點叢集中,cassandra在兩個或者更多節點上儲存同一資料的多個副本,這防止了資料的丟失,但這複雜化了刪除過程。如果一個節點收到了一條刪除它所儲存的本地資料的命令,該節點墓碑指定的記錄並試圖將墓碑傳遞到包含該記錄的副本的其他節點上。但如果一個副本節點在那個時刻沒有響應,它沒有馬上收到墓碑,所以它仍然包含著預刪除記錄的版本。如果在該節點恢復前叢集中的其他節點已經刪除了墓碑,Cassandra把該剛恢復過來的節點上的這條記錄視為新資料,然後把他傳播到叢集中其他的節點上。這種標記為已經刪除但是仍然存在的記錄被稱為
為了防止殭屍記錄的再現,cassandra給予每一個墓碑一個過渡期。這個過渡期的目的是給予響應節點時間以恢復和正常處理墓碑。如果一個客戶端在過渡期內向墓碑記錄傳送了一條更新命令,cassandra將會覆蓋該墓碑。如果一個客戶端在過渡期向墓碑記錄傳送了一條讀命令,cassandra將忽略這個墓碑同時從其他副本查詢可能存在的該條記錄。
當一個停止響應的節點恢復時,cassandra使用 hinted handoff 來重做當節點掛掉時未作的資料庫的插入和刪除。在一個墓碑的過渡期,cassandra不會重做插入和刪除。如果一個節點在過渡期結束後仍然沒有恢復,cassandra可能會錯過刪除這個節點。
Hinted Handoff: repair during write path
有時,當資料被寫入時一個節點會變得不可用。不可用的原因可能是硬體原因,網路問題,或者過載節點經歷了長時間的垃圾收集後暫停的。按照設計,hinted handoff 本質上允許Cassandra在叢集的執行能力下降時仍然可以繼續執行相同數量的寫。
如果hinted handoff 在cassandra.yaml 中被啟用,在故障檢測器將一個節點標記為down之後,錯過的寫操作將被協調員儲存一段時間。在cassandra3.0及其之後,hint儲存於每個節點的本地hint目錄以改進重做的效能。對於標記為downed的節點,hint由一個target ID,一個hint ID(即一個時間UUID),一個標示cassandra版本的訊息ID和資料塊本身組成。Hint每10秒鐘被重新整理到磁碟一次,減少過時的hint。當gossip發現一個節點已經重新上線時,協調員重新執行每個剩餘的hint以便將資料寫入新返回的節點,然後將hint 檔案刪除。如果一個節點關閉超過max_hint_window_in_ms (預設為3小時),協調員將停止寫入新的hints.
協調員還會通過gossip每十分鐘檢查一次由於停電故障造成的hint寫入超時,如果一個備份節點被過載或者變得不可用,而且故障檢測器還沒有將這個節點標記為不可用,那麼將會預料到大多數或者全部對於節點的寫操作在由write_request_timeout_in_ms, (10 seconds by default).引起的超時之後將會失敗。協調員返回一個TimeOutException異常,寫入將會失敗但是hint將會被儲存。
相關文章
- 重新理解架構架構
- HBase 與 Cassandra 架構對比分析的經驗分享架構
- 三層架構理解架構
- springcloud技術架構理解SpringGCCloud架構
- 深入理解lambada架構架構
- Tomcat 架構原理解析到架構設計借鑑Tomcat架構
- powerVR tbdr 硬體架構理解VR架構
- Kafka 概述:深入理解架構Kafka架構
- 如何理解多租戶架構?架構
- 理解Underscore的設計架構架構
- NUMA架構的個人理解架構
- 換個角度,重新理解架構架構
- 【譯】理解Node事件驅動架構事件架構
- 理解本真的REST架構風格REST架構
- 理解索引:HBase介紹和架構索引架構
- 架構師之路—理解設計模式架構設計模式
- 一文理解Netty模型架構Netty模型架構
- 說說你對前端架構的理解前端架構
- TiKV 新架構:Partitioned Raft KV 原理解析架構Raft
- 迴歸架構本質,重新理解微服務架構微服務
- 【AAC 系列四】深入理解架構元件:ViewModel架構元件View
- 【AAC 系列三】深入理解架構元件:LiveData架構元件LiveData
- 一文徹底理解微服務架構微服務架構
- 我對微服務架構的簡單理解微服務架構
- RocketMQ架構原理解析(三):訊息索引MQ架構索引
- 架構師對MVC設計模式的理解架構MVC設計模式
- 【許曉笛】重新理解EOS的系統架構架構
- 吊打面試官!從多維度理解架構面試架構
- RocketMQ架構原理解析(二):訊息儲存MQ架構
- Tomcat詳解系列(2) - 理解Tomcat架構設計Tomcat架構
- 使用 Cassandra、Astra 和 Stargate 構建儀表板 | baeldungAST
- 同是ZooKeeper,你和架構師的理解差在哪裡?架構
- 理解分散式系統中的快取架構(下)分散式快取架構
- 理解分散式系統中的快取架構(上)分散式快取架構
- 如何最簡單、通俗地理解GPT的Transformer架構?GPTORM架構
- 微服務架構的理解以及和 RPC 的關係微服務架構RPC
- 【AAC 系列二】深入理解架構元件的基石:Lifecycle架構元件
- 分散式架構原理解析,Java開發必修課分散式架構Java