Categories
程式開發

系統解讀Kafka的流和表(一):開篇


這是探索Kafka存儲層和處理層核心基礎系列文章的第一篇。在這篇文章中,我們將總體介紹事件、流、表以及流和表之間的二元性關係。後續的文章將著重探索Kafka的存儲層,也就是流和表的分佈式“文件系統”,然後再介紹位於存儲層之上的處理層。

我與很多Kafka用戶有過交流,他們當中有開發人員、運維人員和架構師,有一些有流式處理或Kafka使用經驗,有一些精通關係型數據庫(如Oracle和MySQL),有一些則兩者都不熟悉。不過,他們會問我相同的問題,比如:“事件流和數據庫表之間有什麼區別?Kafka的主題跟流是同一種東西嗎?如果把數據放在Kafka裡,如何最大程度地利用它們? ”

事件、流、表

我們先從最基本的開始:Kafka是什麼? Kafka是一個事件流平台,它提供了這三個關鍵特性:

  1. 發布和訂閱事件;
  2. 按需存儲事件;
  3. 處理和分析事件。

那麼這裡所說的事件是什麼東西?

事件記錄了真實世界“發生了某件事情”。從概念上講,一個事件包含一個鍵、一個值和時間戳。事件可以是一個普通的通知,可能不包含額外的信息,也可能包含所有可用於後續處理的細節。例如:

  • 鍵:“Alice”;
  • 值:“Is currently in Rome”;
  • 時間戳:“Dec. 3, 2019 at 9:06 a.m.”。

事件還可能是這樣的:

  • 賣出一件商品;
  • 數據庫表的一條記錄被更新;
  • 風機傳感器測量到葉片每分鐘轉14次;
  • 下棋時發生的一個動作,比如“白方將e2位置上的小兵移到e4上”;
  • Frank在2019年11月24晚上5點11分向Sally支付了200美元。

事件流平台捕捉事件,將事件形成事件流。事件流按照事件的順序記錄了真實世界發生的歷史,例如銷售賬簿或者象棋比賽時記錄的棋子移動順序。 Kafka的流可以記錄幾百年的業務歷史事件。它們是按順序排列的事件鏈,我們可以知道哪個事件是在哪個事件之前或之後發生的。所以,流代表了過去和現在:當時間從今天走向明天,或者從這一毫秒走到下一毫秒,新的事件會持續不斷地被追加到歷史中。

與事件流不一樣,數據庫的表代表的是世界在某個時間點的狀態,通常是“現在”。例如,商品的總銷量或者象棋比賽中棋盤的當前佈局。表是事件流的一個視圖,在捕捉到新事件時就會更新這個視圖。

系統解讀Kafka的流和表(一):開篇 1

流記錄了歷史,表代表的是狀態

在Kafka裡,流和表有很多不一樣的地方,其中最突出的一點是它們的內容是否可變(我所說的表是指Kafka Streams裡的KTable)。

  • 流提供的是不可變數據。它只支持插入(追加)新的事件,已有的事件不能被修改。流中的數據是持久化的,支持容錯。流中的事件包含了鍵,一個鍵可以對應多個事件,比如“與Bob相關的所有支付事件”。不嚴格地說,你可以把流看成是關係型數據庫裡的一張表,只是它沒有唯一鍵約束,而且只能追加記錄。
  • 表提供的是可變數據。你可以插入新數據,已有的數據可以被更新或刪除。事件的鍵(也就是數據行的標識)是可變的。與流一樣,表也是持久化的,支持容錯。現在的表就像是關係型數據庫裡的物化視圖,當輸入流發生變化時,它會自動更新,不會讓你直接對它執行插入、更新或刪除操作。

系統解讀Kafka的流和表(一):開篇 2

流和表的二元性

雖然流和表之間有所區別,但也存在非常緊密的聯繫。我們把它們之間的這種關係叫作流和表的二元性:

  • 我們可以通過一些聚合操作,比如COUNT()或者SUM(),將流轉成表。在像棋比賽中,我們可以通過重放所有已記錄的棋子移動事件來重建棋局的最新狀態(也就是表)。
  • 我們也可以通過捕獲表的變更事件(插入、更新、刪除),把事件匯聚成“變更流”,這樣就可以將表轉成流。這個過程一般被稱為變更數據捕獲,簡稱CDC(Change Data Capture)。在像棋比賽中,我們可以觀察最新的棋子移動,並把它記錄下來(加入到流中)。或者,我們也可以比較棋局狀態前後的變化,將發生變化的部分記錄下來,只是這種方式比前面那種要慢一些。

實際上,表的底層就是變更流。如果你有使用過Oracle或MySQL,就應該知道,這些關係型數據庫也存在變更流,只是實現細節被隱藏起來了,它們的名字叫重做日誌(redo log)或二進制日誌(binary log)。在事件流中,重做日誌是一等實體,也就是流。我們可以將流轉成表,也可以將表轉成流。

系統解讀Kafka的流和表(一):開篇 3

因為流和表的二元性,我們可以很容易地將流轉成表,或者反過來。

下面的例子使用COUNT()將流聚合成一個表。為了方便展示,圖中沒有顯示時間戳。隨著新的事件不斷被加入流中,表被持續更新,與關係型數據庫的物化視圖類似,只是它每秒鐘可以支持數百萬個事件。我們可以把這個想像成是對一個表進行CDC,然後生成一個輸出變更流。對一個事件流進行聚合操作則是反過來的:流成了表的輸入變更流。

在這個例子中,事件流中事件的鍵為用戶名,值為用戶所在位置,事件被持續地聚合成表,並根據鍵來跟踪用戶訪問過的位置次數。

系統解讀Kafka的流和表(一):開篇 4

將事件流聚合成表

下面是這個例子對應的代碼:

我們也可以看到表的輸出變更流。變更流對錶的變更做出實時響應,以此來生成警報。它也可以被用在運維中,比如將一個表從機器A遷移到機器B上。

系統解讀Kafka的流和表(一):開篇 5

每張表都自己的變更流(也叫變更日誌)

在後續的文章中,我們將會繼續討論流和表的二元性,它是Kafka彈性伸縮和容錯能力的基礎!

總結

在這篇文章中,我們了解了事件流平台的基本元素:事件、流和表。我們還介紹了流和表的二元性,以及為什麼說二元性是事件流平台(如Kafka)的核心。當然,這篇文章只是一個開始,在下一篇文章中,我們將深入了解Kafka的主題、分區和存儲。

原文鏈接:

https://www.confluent.io/blog/kafka-streams-tables-part-1-event-streaming/