這是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以外的語言
http://www.cnblogs.com/devos/p/5616086.html