選擇Cassandra 這個 NoSQL 數(shù)據(jù)庫,主要是因為它的高可用性、水平可擴展性以及處理高寫入吞吐量的能力。
一、批量 ETL 選項
將 Cassandra 引入我們的基礎(chǔ)設(shè)施后,我們的下一個挑戰(zhàn)是找到一種方法將 Cassandra 中的數(shù)據(jù)公開給我們的數(shù)據(jù)倉庫 BigQuery,以進行分析和報告。我們快速構(gòu)建了一個 Airflow hook 和操作符來執(zhí)行滿載。這顯然無法擴展,因為它會在每次加載時重寫整個數(shù)據(jù)庫。為了擴展管道,我們評估了兩種增量加載方法,但兩者都有其缺點:
- 范圍查詢。這是一種常見的 ETL 方法,其中通過范圍查詢定期(例如每小時或每天)提取數(shù)據(jù)。任何熟悉 Cassandra 數(shù)據(jù)建模的人都會很快意識到這種方法是多么不切實際。 Cassandra 表需要建模以優(yōu)化生產(chǎn)中使用的查詢模式。在大多數(shù)情況下,添加此查詢模式進行分析意味著使用不同的集群鍵克隆表。 RDBMS 人員可能會建議二級索引來支持這種查詢模式,但 Cassandra 中的二級索引是本地的,因此這種方法本身會帶來性能和擴展問題。
- 處理未合并的 SSTable。 SSTables 是 Cassandra 的不可變存儲文件。 Cassandra 提供了 sstabledump CLI 命令,可將 SSTable 內(nèi)容轉(zhuǎn)換為人類可讀的 JSON。然而,Cassandra 是建立在日志結(jié)構(gòu)合并 (LSM) 樹概念之上的,這意味著 SSTable 會定期合并到新的壓縮文件中。根據(jù)壓縮策略,在帶外檢測未合并的 SSTable 文件可能具有挑戰(zhàn)性(我們后來了解了 Cassandra 中的增量備份功能,該功能僅備份未壓縮的 SSTable;因此這種方法也能發(fā)揮作用。)
考慮到這些挑戰(zhàn),在為 MySQL 構(gòu)建和運營流數(shù)據(jù)管道后,我們開始探索 Cassandra 的流選項。
二、流媒體選項
雙寫
這個想法是每次在 Cassandra 上執(zhí)行寫入操作時都會發(fā)布到 Kafka。這種雙重寫入可以通過內(nèi)置觸發(fā)器或客戶端周圍的自定義包裝器來執(zhí)行。這種方法存在性能問題。首先,由于我們現(xiàn)在需要寫入兩個系統(tǒng)而不是一個系統(tǒng),因此寫入延遲增加了。更重要的是,當(dāng)對一個系統(tǒng)的寫入由于超時而失敗時,寫入是否成功是不確定的。為了保證兩個系統(tǒng)上的數(shù)據(jù)一致性,我們必須實現(xiàn)分布式事務(wù),但多次往返共識會增加延遲并進一步降低吞吐量。這違背了高寫入吞吐量數(shù)據(jù)庫的目的。
三、Kafka 作為事件源
這個想法是寫給 Kafka,而不是直接寫給 Cassandra;然后通過消費來自 Kafka 的事件將寫入應(yīng)用到 Cassandra。事件溯源是當(dāng)今非常流行的方法。但是,如果您已有直接寫入 Cassandra 的現(xiàn)有服務(wù),則需要更改應(yīng)用程序代碼并進行重要的遷移。這種方法還違反了讀你所寫的一致性:如果一個進程執(zhí)行寫入,那么執(zhí)行后續(xù)讀取的同一進程必須觀察寫入的效果。由于寫入是通過 Kafka 路由的,因此發(fā)出寫入和應(yīng)用寫入之間會存在延遲;在此期間,讀取 Cassandra 將導(dǎo)致數(shù)據(jù)過時。這可能會導(dǎo)致不可預(yù)見的生產(chǎn)問題。
四、解析提交日志
Cassandra 在 3.0 中引入了變更數(shù)據(jù)捕獲 (CDC) 功能來公開其提交日志。提交日志是 Cassandra 中的預(yù)寫日志,旨在在機器崩潰時提供持久性。它們通常在沖洗時被丟棄。啟用 CDC 后,它們會在刷新時傳輸?shù)奖镜?CDC 目錄,然后可由 Cassandra 節(jié)點上的其他進程讀取。這允許我們使用與 MySQL 流管道中相同的 CDC 機制。它將生產(chǎn)運營與分析分離,因此不需要應(yīng)用工程師進行額外的工作。
最終,在考慮了吞吐量、一致性和關(guān)注點分離之后,最后一個選項——解析提交日志——成為了最有力的競爭者。
五、提交日志深入探討
除了公開提交日志之外,Cassandra 還提供 CommitLogReader 和 CommitLogReadHandler 類來幫助進行日志的反序列化??磥砥D苦的工作已經(jīng)完成,剩下的就是應(yīng)用轉(zhuǎn)換——將反序列化表示轉(zhuǎn)換為 Avro 記錄并將其發(fā)布到 Kafka。然而,當(dāng)我們進一步深入研究 CDC 功能和 Cassandra 本身的實現(xiàn)時,我們意識到存在許多新的挑戰(zhàn)。
1.延遲處理
提交日志僅在 CDC 目錄已滿時到達,在這種情況下,它將被刷新/丟棄。這意味著記錄事件和捕獲事件之間存在延遲。如果執(zhí)行很少或不執(zhí)行寫入,則事件捕獲的延遲可能會任意長。
2.空間管理
在MySQL中,您可以設(shè)置binlog保留,以便在配置的保留期限后自動刪除日志。然而在 Cassandra 中沒有這樣的選項。一旦提交日志傳輸?shù)紺DC目錄,處理后必須進行消費以清理提交日志。如果 CDC 目錄的可用磁盤空間超過給定閾值,則對數(shù)據(jù)庫的進一步寫入將被拒絕。
3.重復(fù)的事件
單個 Cassandra 節(jié)點上的提交日志并不反映對集群的所有寫入;它們僅反映對節(jié)點的寫入。這使得有必要在所有節(jié)點上處理提交日志。但如果復(fù)制因子為 N,則每個事件的 N 個副本會發(fā)送到下游。
4.無序事件
對單個 Cassandra 節(jié)點的寫入在到達時會被連續(xù)記錄。但是,這些事件從發(fā)出時起可能會無序到達。這些事件的下游消費者必須了解事件時間并實現(xiàn)與 Cassandra 的讀取路徑類似的最后寫入獲勝邏輯,以獲得正確的結(jié)果。
5.帶外架構(gòu)更改
表的架構(gòu)更改通過gossip protocol進行通信,并且不會記錄在提交日志中。因此,只能盡力檢測架構(gòu)中的更改。
6.行數(shù)據(jù)不完整
Cassandra 不會執(zhí)行先讀后寫的操作,因此更改事件不會捕獲每個列的狀態(tài),它們僅捕獲已修改列的狀態(tài)。這使得更改事件不如整行可用時有用。
一旦我們深入了解 Cassandra 提交日志,我們就會根據(jù)給定的約束重新評估我們的要求,以設(shè)計最小可行的基礎(chǔ)設(shè)施。
六、最低限度可行的基礎(chǔ)設(shè)施
借鑒最小可行產(chǎn)品理念,我們希望設(shè)計一個具有最少功能和要求的數(shù)據(jù)管道,以滿足我們的直接客戶的需求。對于 Cassandra CDC,這意味著:
引入 CDC 不應(yīng)對生產(chǎn)數(shù)據(jù)庫的健康狀況和性能產(chǎn)生負面影響;運營放緩和系統(tǒng)停機比分析管道延遲的成本要高得多
查詢數(shù)據(jù)倉庫中的 Cassandra 表應(yīng)該與查詢生產(chǎn)數(shù)據(jù)庫的結(jié)果相匹配(排除延遲);具有重復(fù)和/或不完整的行會增加每個最終用戶的后處理工作量有了這些標(biāo)準,我們開始集思廣益尋找解決方案,并最終提出了三種方法:
1.無狀態(tài)流處理
- 該解決方案的靈感來自 Datastax 的高級復(fù)制博客文章。
- 這個想法是在每個 Cassandra 節(jié)點上部署一個代理來處理本地提交日志。每個代理都被視為基于分區(qū)鍵的寫入子集的“主要”,這樣每個事件都只有一個主要代理。
- 然后在CDC期間,為了避免重復(fù)事件,每個代理僅將事件發(fā)送到Kafka(如果它是該事件的主代理)。
- 為了處理最終的一致性,每個代理都會在事件到達時將其分類到每個表的時間切片窗口中(但不會立即發(fā)布它們);
- 當(dāng)窗口到期時,該窗口中的事件將被散列,并將散列與其他節(jié)點進行比較。如果它們不匹配,則從不一致的節(jié)點獲取數(shù)據(jù),以便最后一次寫入獲勝可以解析正確的值。
- 最后,該窗口中更正的事件將被發(fā)送到 Kafka。
- 任何超出時間切片窗口的無序事件都必須記錄到無序文件中并單獨處理。
- 由于重復(fù)數(shù)據(jù)刪除和排序是在內(nèi)存中完成的,因此對代理故障轉(zhuǎn)移導(dǎo)致數(shù)據(jù)丟失、影響生產(chǎn)數(shù)據(jù)庫的 OOM 問題以及此實現(xiàn)的整體復(fù)雜性的擔(dān)憂阻止了我們進一步探索它。
2.有狀態(tài)流處理
- 該解決方案功能最豐富。
- 這個想法是,每個 Cassandra 節(jié)點上的代理將處理提交日志并將事件發(fā)布到 Kafka,而無需重復(fù)數(shù)據(jù)刪除和排序。
- 然后,流處理引擎將消耗這些原始事件并完成繁重的工作(例如使用緩存過濾掉重復(fù)事件,使用事件時間窗口管理事件順序,以及通過在狀態(tài)存儲上執(zhí)行先讀后寫來捕獲未修改列的狀態(tài)) ),然后將這些派生事件發(fā)布到單獨的 Kafka 主題。
- 最后,KCBQ 將用于消費該主題中的事件并將其上傳到 BigQuery。這種方法很有吸引力,因為它一般性地解決了問題——任何人都可以訂閱后一個 Kafka 主題,而無需自己處理重復(fù)數(shù)據(jù)刪除和排序。
- 然而,這種方法會帶來大量的運營開銷;我們必須維護一個流處理引擎、一個數(shù)據(jù)庫和一個緩存。
3.讀取時處理
- 與之前的方法類似,其想法是處理每個 Cassandra 節(jié)點上的提交日志并將事件發(fā)送到 Kafka,無需重復(fù)數(shù)據(jù)刪除和排序。
- 與之前的方法不同,流處理部分被完全消除。相反,原始事件將通過 KCBQ 直接上傳到 BigQuery。視圖是在原始表之上創(chuàng)建的,用于處理重復(fù)數(shù)據(jù)刪除、排序和合并列以形成完整的行。由于 BigQuery 視圖是虛擬表,因此每次查詢視圖時都會延遲處理。為了防止視圖查詢變得過于昂貴,視圖將定期具體化。這種方法利用 BigQuery 的大規(guī)模并行查詢引擎,消除了操作復(fù)雜性和代碼復(fù)雜性。然而,缺點是非 KCBQ 下游消費者必須自己完成所有工作。
- 鑒于我們流式 Cassandra 的主要目的是數(shù)據(jù)倉庫,我們最終決定實現(xiàn)讀時處理。它為我們現(xiàn)有的用例提供了基本功能,并提供了將來擴展到上述其他兩個更通用的解決方案的靈活性。
七、Cassandra數(shù)據(jù)庫對Gossip協(xié)議的應(yīng)用
Cassandra數(shù)據(jù)庫使用Gossip協(xié)議主要有以下幾個用處:
節(jié)點發(fā)現(xiàn)和自動加入:Cassandra集群中的節(jié)點使用Gossip協(xié)議進行相互通信,通過定期交換消息來發(fā)現(xiàn)新加入的節(jié)點并自動將其加入到集群中。這使得節(jié)點的動態(tài)加入和離開成為可能,而無需依賴于集中式的節(jié)點發(fā)現(xiàn)服務(wù)。
全局狀態(tài)信息的傳播:Cassandra使用Gossip協(xié)議來傳播集群中節(jié)點的狀態(tài)信息,如節(jié)點的健康狀態(tài)、數(shù)據(jù)分布信息等。通過收集和傳播這些信息,集群中的節(jié)點可以更好地了解整個系統(tǒng)的狀態(tài),并做出相應(yīng)的調(diào)整和決策。
數(shù)據(jù)一致性的維護:Cassandra使用Gossip協(xié)議來傳播和更新副本之間的數(shù)據(jù)變更信息。節(jié)點會將數(shù)據(jù)變更信息傳播給其他節(jié)點,以保持副本之間的數(shù)據(jù)一致性。這種基于Gossip協(xié)議的數(shù)據(jù)傳播方式可以在分布式環(huán)境下有效地維護數(shù)據(jù)的一致性。
故障檢測和恢復(fù):通過Gossip協(xié)議,節(jié)點可以檢測到其他節(jié)點的故障,并將故障信息傳播給其他節(jié)點。這使得集群可以快速地檢測到故障節(jié)點并采取相應(yīng)的恢復(fù)措施。文章來源:http://www.zghlxwxcb.cn/news/detail-542722.html
總的來說,Cassandra使用Gossip協(xié)議來實現(xiàn)分布式環(huán)境下的節(jié)點發(fā)現(xiàn)、全局狀態(tài)信息傳播、數(shù)據(jù)一致性維護和故障檢測恢復(fù)等功能,確保集群的可靠性、容錯性和一致性。文章來源地址http://www.zghlxwxcb.cn/news/detail-542722.html
到了這里,關(guān)于Debezium日常分享系列之:流式傳輸 Cassandra的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!