這是Jay Kreps在三月寫的一篇文章,用來介紹Kafka Streams。當時Kafka Streams還沒有正式釋出,所以具體的API和功能和0.10.0.0版(2016年6月釋出)有所區別。但是Jay Krpes在這簡文章裡介紹了很多Kafka Streams在設計方面的考慮,還是很值得一看的。
以下的並不會完全按照原文翻譯,因為那麼搞太累了……這篇檔案的確很長,而且Jay Kreps寫的重複的地方也挺多,有些地方也有些故弄玄虛的意思。不過他想說的道理倒挺容易搞清楚。
我很高興能宣佈Kafka的新特性-Kafka Streams的預覽。Kafka Streams是一個使用Apache Kafka來構造分散式流處理程式的Java庫。它前作為Kafka 0.10版本的一部分,其原始碼在Apache Kafka專案下。。
使用Kafka Streams構建的一個流處理程式看起來像是這樣:
需要注意的是:Kafka Streams是一個Java庫,而不是一個流處理框架,這點和Strom等流處理框架有明顯地不同
這個程式和0.10.0.0版在細節上有很多不同。對Kafka 0.10.0.0版的Kafka Streams, 實際能執行的例子可以在Kafka Streams工程的examples包底下找到。需要注意的是,這個例子使用了lambda表示式,這是JAVA8的特性。
在KStream的構造上,體現了它跟Kafka的緊密關係。比如,它預設的輸入流的元素就是K,V對形式的,輸出流也是這樣,因此在構造輸入輸出流時需要分別指定K和V的Serde。其中KStream的API使用了很多集合函式,像map, flatMap, countByKey等,這個也可以稱為Kafka Streams的DSL。
雖然只是一個庫,但是Kafka Streams直接解決了在流處理中會遇到的很多難題:
- 一次一件事件的處理(而不是microbatch),延遲在毫秒
- 有狀態的處理,包括分散式join和aggregation
- 一個方便的DSL
- 使用類似於DataFlow的模型來處理亂序資料的windowing問題
- 分散式處理,並且有容錯機制,可以快速地實現failover
- 有重新處理資料的能力,所以當你的程式碼更改後,你可以重新計算輸出。
- 沒有不可用時間的滾動佈署。
對於想要跳過這些前言,想直接看文件的人,你們可以直接去到Kafka Streams documention. 這個blog的目的在於少談"what"(因為相關的文件會進行詳細地描述),多談"why"。
但是,它到底是啥呢?
Kafka Streams是一個用來構建流處理程式的庫,特別是其輸入是一個Kafka topic,輸出是另一個Kafka topic的程式(或者是呼叫外部服務,或者是更新資料庫,或者其它)。它使得你以一種分散式以及容錯的方式來做這件事情。
在流處理領域有很多正在進行的有趣的工作,包括像 Apache Spark, Apache Storm, Apache Flink, 和 Apache Samza這樣的的開源框架,也包括像Google’s DataFlow 和 AWS Lambda一樣的專有服務。所有,需要列一下Kafka Streams和這些東西的相似以及不同的地方。
坦率地說,在這個生態系統中,有開源社群帶來的非常多的各種雜亂地創新。我們對於所有這些不同的處理層(processing layer)感到很興奮:儘管有時候這會讓人感到有點困惑,但是技術水平的確在很快地進步。我們想讓Kafka能夠成為所有這些處理層的合適的資料來源。我們想要Kafka Streams填充的空缺不大在於這些框架所關注的分析領域,而在於構建用於處理流式資料的核心應用和微服務。我在下面一節將會深入講述這些不同之處,並且開始講解Kafka Streams是怎麼使這種型別的程式更簡單的。
嬉皮士,流處理,和Kafka
如果想要知道一個系統設計是否在真實情況下工作良好,唯一的方法就是把它構建出來,把它用於真實的程式,然後看看它有什麼不足。在我之前在LinkedIn的工作中,我很幸運地能夠成為設計和構造流處理框架Apache Samza的小組的成員。我們把它推出到一系列內部程式之中,在生產中提供為它提供支援,並且幫助把它作為一個Apache專案開源。
那麼,我們學到了什麼呢?很多。我們曾經有過的一個關鍵的錯覺是以為流處理將會被以一種類似於實時的MapReduce層的方式使用。我們最終卻發現,大部分對流處理有需求的應用實際上和我們通常使用Hive或者Spark job所做的事情有很大不同,這些應用更接近於一種非同步的微服務,而不是批量分析任務的快速版本。
我所說是什麼意思呢?我的意思是大部分流處理程式是用來實現核心的業務邏輯,而不是用於對業務進行分析。
構建這樣的流處理程式需要解決的問題和典型的MapReduce或Spark任務需要解決的分析或ETL問題是非常不同的。它們需要通常的程式所經歷的處理過程,比如配置,佈署,監控,等。簡而言之,它們更像是微服務(我知道這是一個被賦予了過多意義的名詞),而不像是MapReduce任務。Kafka取代了HTTP請求為這樣的流處理程式提供事件流(event streams)。
之前的話,人們用Kafka構造流處理程式時有兩個選擇:
1. 直接拿Consumer和Producer的API進行開發
2. 採用一個成熟的流處理框架
這兩種選擇各有不足。當直接使用Kafka consumer和producer API時,你如果想要實現比較複雜的邏輯,像聚合和join,就得在這些API的基礎上自己實現,還是有些麻煩。如果用流處理框架,那麼就新增了很多很多複雜性,對於除錯、效能優化、監控,都帶來很多困難。如果你的程式既有同步的部分,又有非同步的部分,那麼就就不得不在流處理框架和你用於實現你的程式的機制之間分隔開。
雖然,事情不總是這樣。比如你已經有了一個Spark叢集用來跑批處理任何,這時候你想加一個Spark Streaming任務,額外新增的複雜性就挺小。但是,如果你專門為了一個應用佈署一個Spark叢集,那麼這的確大大增加了複雜性。
但是,我們對Kafka的定位是:它應該成為流處理的基本元素,所以我們想要Kafka提供給你能夠擺脫流處理框架、但是又具有非常小的複雜性的東西。
我們的目的是使流處理足夠簡化,使它能夠成為構造非同步服務的主流程式設計模型。這有很多種方法,但是有三個大的方面是想在這個blog裡深入討論一下:
這三個方面比較重要,所以把英文也列出來。
- Making Kafka Streams a fully embedded library with no stream processing cluster—just Kafka and your application.
- Fully integrating the idea of tables of state with streams of events and making both of these available in a single conceptual framework.
- Giving a processing model that is fully integrated with the core abstractions Kafka provides to reduce the total number of moving pieces in a stream architecture.
- 使得Kafka Streams成為一個嵌入式的libray,而不依賴於任何流處理框架。
- 把“有狀態的表”和"事件流“緊密結合,使它們在同一個概念框架內可用。
- 提供一個和Kafka的核心抽象完全整合的處理模型,來減少流處理架構內的不確定部分的數量。
下面對每個方面單獨進行討論。
簡化點1: 不依賴框架的流處理
Kafka Streams使得構建流處理服務更簡單的第一點就是:它不依賴於叢集和框架,它只是一個庫(而且是挺小的一個庫)。你只需要Kafka和你自己的程式碼。Kafka會協調你的程式程式碼,使得它們可以處理故障,在不同程式例項間分發負載,在新的程式例項加入時重新對負載進行平衡。
我下面會講一下為什麼我認為這是很重要的,以及我們之前的一點經歷,來幫助理解這個模型的重要性。
治癒MapReduce的宿醉
我前邊講到我們構造Apache Samza的經歷,以及人們實際想要的(簡單的流服務)和我們構建的東西(實時的MapReduce)之間的距離。我認為這種概念的錯位是普遍的,畢竟流處理做的很多事情是從批處理世界中接管一些能力,用於低延遲的領域。同樣的MapReduce遺產影響了其它主流的流處理平臺(Storm, Spark等),就像它們對Samza的影響一樣。
在LinkedIn在很多生產資料的處理服務是屬於低延遲領域的:email, 使用者生成的內容,新訊息反饋等。其它的很多公司也應該有類似的非同步服務,比如零售業需要給商品排序、重新定價,然後賣出,對於金融公司,實時資料更是核心。大部分這些業務,都是非同步的,對於渲染頁面或者更新移動app的螢幕就不會有這樣的問題(這些是同步的)。
那麼為什麼在Storm, Samza, Spark Streaming這樣的流處理框架之上構建這樣的核心應用這麼繁瑣呢?
一個批處理框架,像是MapReduce或者Spark需要解決一些困難的問題:
- 它必須在一個機器池之上管理很多短期任務,並且在叢集中有效地排程資源分配
- 為了做到這點,它必須動態地把你的程式碼、配置、依賴的庫以及其它所有需要的東西,打包並且物理地佈署到將要執行它的機器上。
- 它必須管理程式,並且實現共享叢集的不同任務之間的隔離。
不幸的是,為了解決這些問題,框架就得變得很有侵入性。為了做到容錯和擴充套件,框架得控制你的程式如何佈署、配置、監控和打包。
那麼,Kafka Streams有什麼不同呢?
Kafka Streams對它想要解決的問題要更關注得多。它做了以下的事情:
- 當你的程式的新的例項加入,或已經有例項退出時,它會重新平衡要處理的負載
- 維護表的本地狀態
- 從錯誤中恢復
它使用了Kafka為普通的consumer所提供的同樣的組管理協議(group manager protocol)來實現。Kafka Streams可以有一些本地的狀態,儲存在磁碟上,但是它只是一個快取。如果這個快取丟失了,或者這個程式例項被轉移到了別的地方,這個本地狀態是可以被重建的。你可以把Kafka Streams這個庫用在你的程式裡,然後啟動任意數量的你想要程式例項,Kafka將會把它們進行分割槽,並且在這些例項間進行負載的平衡。
這對於實現像滾動重啟(rolling restart)或者無當機時間的擴充套件(no-downtime expansion)這樣簡單的事情是很重要的。在現代的軟體工程中,我們把這樣的功能看做是應該的,但是很多流處理框架卻做不到這點。
Dockers, Mesos, 以及Kurbernetes, 我的天哪!
從流處理框架中分離出打包和佈署的原因是,打包和佈署這個領域本身就正在進行自身的復興。Kafka Streams可以使用經典的老實巴交維工具,像是Puppet, Chef, Salt來佈署,把可以從命令列來啟動。如果你年輕,時髦,你也可以把你的程式做成Dock映象;或者你不是這樣的人,那麼你可以用WAR檔案。
但是,對於尋找更加有靈活的管理方式的人,有很多框架的目標就是讓程式更加靈活。這裡列了一部分:
- Apache Mesos with a framework like Marathon
- Kubernetes
- YARN with something like Slider
- Swarm from Docker
- Various hosted container services such as ECS from Amazon
- Cloud Foundry
這個生態系統就和流處理生態一樣專注。
的確,Mesos和Kubernets想要解決的問題是把程式分佈到很多機器上,這也是當你佈署一個Storm任務到Storm叢集時,Storm嘗試解決的問題。關鍵在於,這個問題最終被發現是挺難的,而這些通用的框架,至少是其中優秀的那些,會比其它的做得好得多-它們具有執行像在保持並行度的情況下重啟、對主機的粘性(sticky host affinity)、真正的基於cgroup的隔離、用docker打包、花哨的UI等等功能。
你可以在這些框架裡的任何一種裡使用Kafka Streams,就像你會對其它程式做的一樣,這是用來實現動態和有彈性的程式管理的一種簡單的方式。比如,如果你有Mesos和Marathon,你可以使用Marathon UI直接啟動你的Kafka Streams程式,然後動態地擴充套件它,而不會有服務中斷, Meos會管理好程式,Kafka會管理和負載勻衡以及維護你的任務程式的狀態。
使用一種這些的框架的開銷是和使用Storm這樣的框架的叢集管理部分是一樣的,但是優點是所有這些框架都是可選的(當然,Kafka Streams沒有了它們也可以很好的工作)。
簡化點2:Streams Meet Tables
Kafka Strems用於簡化處理程式的另一個關鍵方式是把“表”和"流“這兩個概念緊密地結合在一起。我們在之前的"turning the database inside out"中簡化這個想法。那句話抓住了作為結果的系統是如何重鑄程式和它的資料之彰的關係以及它是怎麼應於資料變化,這樣的要點。為了理想這些,我會回顧一下,解釋我對於”table"和"stream"的定義,以及把二者結合在一起如何能夠簡化常見的非同步程式。
傳統的資料庫都是關於在表格中儲存狀態的。當需要對事件流進行反應時,傳統資料庫做得並不好。什麼是事件呢?事件只是一些已經發生了的事-可以是一個點選、一次出售、源自某個感測器的一個動態,或者抽象成任何這個世界上發生的事情。
像Storm一樣的流處理程式,是從這個等式的另一端出發的。它們被設計用於處理事件流,但是基於流來產生狀態卻是後面才加進來的。
我認為非同步程式的基本問題是把代表當前世界狀態的tables與代表正在發生事件的event streams結合在一起。框架需要處理好如何表示它們,以及如何在它們之間進行轉化。
為什麼說這些概念是相關的呢?我們舉一個零售商的簡單例子。對於零售商而言,核心的事件流是賣出商品、訂購新商品以及接收訂購的商品。“庫存表”是一個基於當前的存貨量,通過售出和接收流進行加減的“表”。對於零售商而言兩個關鍵的流處理動作是當庫存開始降低時訂購商品,以及根據供需關係調整商品價格。
表和流是一體的雙面
在我們開始研究流處理之前,讓我們先試著想解表和流的關係。我想在這裡最好引用一下Pat Helland關於資料庫和日誌的話:
事務日誌記錄了對於資料庫的所有改變。高速的append操作是日誌發生改變的唯一方式。從這個角度來看,資料庫儲存了日誌裡最新記錄的快取。事實記錄於日誌中。資料庫是一部分日誌的快取。被快取的部分剛好是每個記錄的最新值,以及源自於日誌的索引值。
這到底是在說什麼呢?它的意義實際上位於表和流的關係的核心。
讓我們以這個問題開始:什麼是流呢?這很簡單,流就是一系列的記錄。Kafka把流建模成日誌,也就是說,一個無盡的健/值對序列:
key1 => value1key2 => value2key1 => value3...
那麼,什麼是表呢?我認為我們都知道,表就是像這樣的東西:
Key1 |
Value1 |
Key2 |
Value3 |
其中value可能是很多列,但是我們可以忽略其中的細節,簡單地把它們認為是KV對(新增更多的列並不會改變將要討論的東西)。
但是當我們的流隨時間持續更新,新的記錄出現了,這只是我們的表在某個特定時間的snapshot。表格是怎麼變化的呢?它們是被更新的。一個表實際上並不是單一一個東西,而是像下面這樣的一系列東西:
time = 0
key1 | value1 |
time = 1
Key1 |
Value1 |
Key2 |
Value2 |
time = 2
Key1 |
Value3 |
Key2 |
Value2 |
但是這個序列有一些重複。如果你把沒有改變的行去掉,只記錄更新,那麼就可以用一個有序的更新序列來表示這張表:
但是,這不就變成流了嗎?這種型別的流通常補稱為changelog, 因為它展示了更新序列,按照更新的順序記錄了每個記錄的最新的值。
所以,表就是流之上的一個特殊的檢視。這樣說可能有些奇怪,但是我認為這種形式的表跟我們腦海中的長方形的表對於“表實際上是什麼”是一樣可以反映其本質的。或者,這樣實際上更加自然,因為它抓住了“隨時間改變”的概念(想一想:有什麼資料真的不會改變呢?)。
換句話說,就像Pat Helland指出的那樣,一張表就是一個流裡的每個key的最新的值的快取。
用資料庫的術語來說:一個純粹的流就是所有的更新都被解釋成INSERT語句(因為沒有記錄會替換已有的記錄)的表,而一張表就是一個所有的改變都被解釋成UPDATE的流(因為所有使用同樣的key的已存在的行都會被覆蓋)。
這種雙面性被構建進Kafka中已經有一段時間了,它被以compacted topics的形式展現。
表和流處理
好的,這就是流和表是什麼。那麼,這跟流處理有啥關係呢?因為,最終你會發現,流和表的關係正是流處理問題的核心。
我上面已經給了一個零售商的例子,在這個例子裡“商品到貨”和“商品售出”這兩個流的結果就是一個存貨表,而對存貨表的更改也會觸發像“訂貨”和“更改價格”這樣的處理。
在這個例子中,存貨表當然不只是在流處理框架中創造出來的東西,它們可能已經在一個資料庫中了。那好,把一個由變化組成的流捕捉到一個表中被稱為Change Capture, 資料庫就做了這個事。Change capture資料流的格式就是我之前描述的changelog格式。這型別的change capture是你可以使用Kafka Connect輕鬆搞定的事情,Kafka Connect是一個用於data capture的框架,是Kafka 0.9版本新加的。
通過以這種方式構建表的概念,Kafka使得你從變化流(stream of changes)得到的表中推匯出數值。換句話說,就是讓你可以像處理點選流資料一樣處理資料庫的變化流。
你可以把這種基於資料庫變化觸發計算的功能看作類似於資料庫的觸發器和物化檢視功能,但是這個功能卻不僅限於一個資料庫,也不僅限於PL/SQL,它可以在資料中心的級別執行,並且可以工作於任何資料來源。
Join和Aggregate也是表
我們到了怎麼樣可以把一個把變成一個更新流(也是一個changelog),並且使用KafkaStreams基於它計算一些東西.但是表/流的雙面性用相反的方式也是可行的.
假如你有一個使用者的點選流,你想計算每個分戶的點選總數.KafkaStreams可以讓你計算這種聚合(aggregation),並且,你所計算出來的每個使用者的佔擊數就是一張表.
在實現時,Kafka Streams把這種基於流計算出來的表儲存在一個本地資料庫中(預設是RocksDB,但是你可以plugin其它資料庫).這個Job的輸出就是這個表的hcnagelog. 這個changelog是用於高可用的計算的(譯註:就是當一個計算任務失敗,然後在別的地方重啟時,可以從失敗之前的位置繼續,而不用整個重新計算),但是它也可以被其它的KafkaStreams程式消費和處理,也可以用KafkaConnect導到其它的系統裡.
這種支援本地儲存的架構已經在Apache Samza中出現,我這前從系統架構的角度寫過一篇關於這個的文章.KafkaStreams與Apache Samza的關鍵的革新是表的概念不再是一個低層的基礎設施,而是一個和stream一樣的一等成員.Streams在Kafka Streams提供的programming DSL中用KStream類表示, 表是用KTable類表示.它們有一些共同的操作,也可以像表/流的雙面性暗示的那樣可以互相轉換,但是,它們也有不同之處.(譯註:接下來的幾句比較難懂,如果覺得理解得不對,可以看原文).比如,對一個KTable執行取合操作時,Kafka Streams知道這個KTable底層是一個stream of updates,因此會基於這個事實進行處理.這樣做是有必要的,是因對一個正在變化的表計算sum的語義跟對一個由不可變的更新組成的流計算sum的語義是完全不同的.與之相似的還有,join兩個流(比如點選點和印象流)的語法和對一個表和一個流(比如點選流和賬戶表)進行join的語義是完全不同的.通過用DSL對這兩個概念進行建模,這些細節自動就分清楚了.(譯註:我覺得這段話的意思是就Kafka Streams會考慮到KTable底層實際上是一個流,所以會採用與計算普通表的aggregation和join不同的特殊的計算方式)
WIndows和Tables
視窗、時間和亂序的事件是流處理領域的另一個難搞的方面。但是,令人驚奇的是,可以證明的是一個簡單的解決方案落到了表的概念上面。緊密關注流處理領域的人應該聽說過"event time"這個概念,它被Google Dataflow團隊的人非常有說服力地頻繁地討論。他們抓住的問題是:如果事件無序地達到,那麼怎麼做windowed操作呢?亂序的資料在大多數分散式場景下是無法避免的,因為我們的確無法保證在不同的資料中心或者不同的裝置上生成的資料的順序。
在零售商的例子中,一個這種windowed computing的例子就是在一個十分鐘的時間視窗中計算每種商品的售出數量。怎麼能知道什麼時候這個視窗結束了呢?怎麼知道在這個時間段的所有出售事件都已經到達而且被處理了呢?如果這些都不能確定的話,怎麼能給出每種商口的售出總數的最終值呢?你無論在什麼時候基於此時統計的數量做出答案,都可能會太早了,在後續可能會有更多的事件到達,使得你之前的答案是錯誤的。
Kafka Streams使得處理這個問題變得很簡單:windowed aggregation的語義,例如count,就表示對於這個windows的“迄今為止"的count。隨著新的資料的到達,它保持更新,下流的接收者可以自已決定什麼時候完成統計。對,這個可以更新的數量的概念看起來莫名其秒的熟悉:它不是別的,就是一個表,被更新的windows就是key的一部分。自然而然的,下游操作知道這個流表示一個表,並且在這些更新到達時處理它們。
在資料庫變化流之上進行計算和處理亂序事件的windowd aggregation,使用的是同樣的機制,我認為這是很優雅的。這種表和流的關係並不是我們發明的,在舊的流處理的文章中,比如CQL中,已經展示了它的很多細節,但是這個理論卻沒有融合進大多數現實世界的系統——資料庫處理表時、流處理系統處理流時,並且也沒多數沒有把兩者都做為一等公民。
Tables + Embeddable Libary = Stateful Services
有一個基於我上邊提出的一些特性的正在發展的功能可能不是那麼明顯。我討論了Kafka Streams是如何讓你透明地在RocksDB或其它本地資料結構中維護一個基於流推演出來的表的。因為這個處理的過程的狀態都在物理上存在於你的程式中,這就開啟了另一項令人興奮的新的用途的可能性:使得你的程式可以直接查詢這個狀態。
我們當前還沒暴露出來這個介面-我們現在還專注於使得流處理的API先穩事實上下來,但是,我覺得對於一些特定型別的資料敏感的程式,這是一個很吸引人的架構。
這意味著,你可構建,比如,一個嵌入了Kafka Streams的REST服務,它可以直接查詢資料流通過流處理運算得到的本地的聚合結果。這種型別的有狀態的服務的好處在這裡討論過。並不是在所有領域這麼做都合適,你通常只是想要把結果輸出到一個外部的資料庫中。但是,假如你的服務的每個請求都需要訪問很多資料,那麼把這些資料放在本地記憶體或者一個很快的本地RocksDB例項中會非常有用。
簡化點3: 簡單即為美
我們的所有這些的最高目錄是使得構建和操作流處理程式的過程變得更簡單。我們的信念是流處理應該是一個構建應用程式的主流方式,公司所做的事情的很大一部分在非同步領域,流處理正是用來幹這個的。但是為了使這點成為現實,我們還需要使Kafka Streams在這方面更簡單更可依賴。這種對於操作的簡化的一部分就是擺脫對外部叢集的依賴,但是它還簡化了其它的地方。
如果對人們是怎麼構建流處理程式進行觀察的話,你會發現除了框架本身,流處理程式傾向於具有高度的架構複雜性。這是一個典型的流處理程式的架構圖。
(圖)
這裡有如此多的會變化的部分:
- Kafka 自身
- 一個流處理框架,例如Storm或者Spark或者其它的,它們通常包含一系列的master程式和在每個結點上的守護程式。
- 你的實際的流處理job
- 一個輔助的資料庫,用於查詢和聚合
- 一個被應用程式查詢的資料庫,它接收來自於流處理任務的輸出。
- 一個Hadoop叢集(它本身就有一系列變化的部分)來重新處理資料
- 為你的使用者或客戶的請求提供服務的請求/響應式的程式
把這麼一大堆東西弄下來不僅不是人們想追求的,而且通常也是不現實的。即使你已經有了這個架構的所有部分,把它個整合在一起,把它監控好,能夠發揮它的所有作用,也是非常非常困難的。
Kafka Streams的一個最令人欣喜的事情就是它的核心概念很少,而且它們貫穿於整個系統中。
我們已經談論過一些大的點:擺脫額外的流處理叢集,把表格和有狀態的處理完全整合進流處理本身。使用Kafka Streams,這個架構可以瘦身成這樣:
但是使得流處理變得簡單這個目標比這兩點遠得多。
因為它直接構建於Kafka的基礎操作之上,Kafka Streams非常小。它的整個程式碼基礎只有不到九千行。你喜歡的話,一下行就看完了。這意味著你會遇到的除了Kafka自己的producer和consumer以外的複雜性是很容易承擔的。
這有很多小的含義:
- 輸出和辦理出都只是Kafka topics
- 資料模型自始至終都是Kafka的Keyd record資料模型
- 分割槽模型就是Kafka的分割槽模型(譯註:這裡就是指”資料分割槽”這件事的實現方式),Kafka的partitionor也可以用於streams。
- 用於管理分割槽、分配、存活狀態的group membership機制也就是Kafka的group membership機制
- 表和其它的有狀態的計算都是log compacted topics(譯註:是指用的是compacted topics)。
- 對於Producer, consumer和流處理程式,metrics都是統一的,所以監控的時候只要抓取一種metrics就行了(譯註:是指這三個部分用的是同樣的metrics機制)。
- 你的程式的position被使用offset來維護,就像Kafka consumer一樣。
- 用於做windowing操作的時間戳就是0.10加到Kafka的那個timestamp機制,它可以提供給你基於event-time的處理
簡單來說一個kafka Strems程式在很多方面看起來就像其它的直接用Kafka producer或consumer寫的程式一樣,但是它寫起來要簡潔得多。
除了Kafka client暴露出來那些配置以外,額外的配置項非常少。
如果你改了程式碼,想要使用新的邏輯重新處理資料,你也不需要一個完全不同的系統。你只需要回退你程式的Kafka offsets,然後讓它重新處理資料(你當然也可以在Hadoop端或者其它地方重新處理,但是關鍵是你可以選擇不這麼做).
儘管最初的樣例架構是由一系列獨立的元件組成,並且它們也只是部分地工作在一起,但是我們希望你將來會感覺到Kafka、Kafka Connect和Kafka Streams就是為了一起工作而設計的。
接下來呢?
就像其它的預覽版一樣,有一些功能我們還沒有完成。下面是一些將會新增進來的功能。
可查詢的狀態
接下來會利用內建的表提供提供對程式狀態的查詢。
端到端的語義
當前的KafkaStreams繼承了Kafka的"at least once"的訊息傳遞語義。Kafka社群正在探索如何實現跨Kafka Connect, Kafka, KafkaStream和其它計算引擎的訊息傳遞語義。
支援Java以外的語言