??很高興宣布,Apache Kafka的一項新功能預(yù)覽叫Kafka Streams。Kafka Streams是一個使用Apache Kafka用于構(gòu)建分布流處理應(yīng)用的Java庫。這將是即將更新Kafka-0.10版本的一部分,并且已經(jīng)提供可以很容易試用的預(yù)覽版。
??使用Kafka Stream構(gòu)建一個流處理應(yīng)用如下所示:
- 具有毫秒級延遲的Event-at-a-time處理(不是小批量)
- 狀態(tài)處理,包括分布式Join和聚合
- 方便的DSL
- 使用DataFlow-like模型處理帶有window的無序數(shù)據(jù)
- 分布式處理和快速故障切換容錯
- 再處理能力,以便當你代碼改動時,重新計算輸出
- 無停機時間滾動部署
??對于想要跳過序言和剛剛深入到文檔的人們,可以去看Kafka Stream文檔。本博客主旨會少“是什么”,深度講解“為什么”。
??Kafka Stream是構(gòu)建流處理應(yīng)用,尤其是轉(zhuǎn)變Kafka輸入topic為Kafka輸出topic(或調(diào)用外部服務(wù),更新數(shù)據(jù)庫)應(yīng)用的庫。讓你能夠以分布式、容錯和簡潔的代碼做到這一點。
??流處理領(lǐng)域工作中有非常有趣的事情發(fā)生。從Apache Spark、Apache Storm、Apache Flink和Apache Samza到專有服務(wù),例如Google的DataFlow和AWS Lambda。因此Kafka Stream和這些應(yīng)用的異同是值得概述的。
??坦率的講,生態(tài)系統(tǒng)中有大量凌亂的創(chuàng)新,開源是其中重要的部分。對這些不同的處理層非常興奮:即使它有時候有點混亂,技術(shù)發(fā)展水平迅速推進。努力讓Kafka和這些開源軟件工作一樣好。我們發(fā)現(xiàn)Kafka Stream與專注于分析為重點領(lǐng)域的這些框架和更多的構(gòu)建處理數(shù)據(jù)流的核心應(yīng)用以及微服務(wù)差距很大。在下一節(jié),我們將深入講這些區(qū)別,現(xiàn)在讓我們深入到Kafka Stream如何簡化此類應(yīng)用。
??真正了解現(xiàn)實世界一個系統(tǒng)設(shè)計工作的唯一方法是去建立、部署實際應(yīng)用,并觀察是否達到預(yù)期。在以往的角色,Linkedin中幸運的成為設(shè)想和構(gòu)建流處理框架Apache Samza團隊的一部分。推出一組內(nèi)部應(yīng)用程序,在生產(chǎn)中支持,并使其成為Apache的一個開源項目。
??學到了什么?很多。曾經(jīng)一個關(guān)鍵的誤解是流處理在某種程度上以實時Mapreduce層使用。最總才意識到,流處理最引人矚目的應(yīng)用是與你通常使用Hive或Spark工作相當不同,更接近與一種異步微服務(wù),而不是成為一個更快版本的批分析工作。
??什么意思呢?是指這些流處理應(yīng)用是實現(xiàn)業(yè)務(wù)核心功能的軟件,而不是對業(yè)務(wù)計算分析。
??建立這種類型的流處理應(yīng)用需要解決的是與典型Mapreduce或Spark作業(yè)的分析或ETL領(lǐng)域不同的需求。他們需要經(jīng)過和正常應(yīng)用通過配置、部署、監(jiān)控等方面相同的過程,他們更喜歡微服務(wù)而不是Mapreduce工作。這類型的流應(yīng)用處理來自Kafka的異步事件流而不是HTTP請求。
??如何用Kafka構(gòu)建流處理應(yīng)用,有兩個選擇:
- 只需要構(gòu)建一個直接使用Kafka producer和consumer的API應(yīng)用
- 采用一個完整的流處理框架
??對簡單問題直接使用Kafka API工作非常好。不對應(yīng)用程序添加任何本章的依賴。我們稱之為“時髦流處理”,因為它是一種呼吁喜歡自己掌控的人們使用的低技術(shù)解決方案。對簡單的同時處理一條信息表現(xiàn)非常好,但是當你想要做更多的工作,如計算聚合或Join流時,問題出現(xiàn)了。在這種情況下在Kafka consumer API上解決這個問題相當復雜的。
??在一個完整的流處理框架中pull讓你輕松訪問更高級的操作。但是對于簡單應(yīng)用的成本是極其復雜的。這使得一切變得困難,從調(diào)試到性能優(yōu)化到監(jiān)控到部署。更糟糕的是,如果你的應(yīng)用擁有同步和異步碎片然后最后在為實現(xiàn)服務(wù)或應(yīng)用分割機制或者流處理框架的代碼。以這種方式真的很難建立并操作業(yè)務(wù)的重要部分。
??不是所有領(lǐng)域出現(xiàn)這個問題,畢竟如果你已經(jīng)使用Spark構(gòu)建一個批工作流,并且為了一些實時數(shù)位你希望向這個組合添加Spark Streaming工作,額外的復雜度相當?shù)?,它重新利用你已?jīng)擁有的技術(shù)。
??然后如果為了這個新應(yīng)用的唯一目的部署Spark集群,這將是非常復雜的。
??因為在Kafka中已經(jīng)設(shè)計了核心抽象是我們想要提供的流處理基元,為你提供你愿意擁有的流處理框架。但是有點超出了正常Kafka produce和consumer API的額外操作復雜度。
??換句話說,我們的目的如下所示:
- 讓Kafka Stream完全嵌入沒有流處理集群的庫,只是Kafka和你的應(yīng)用程序
- 完全整合事件流和狀態(tài)表的想法,使得二者可用在單一框架
- 賦予完全由Kafka提供的個新抽象處理模型,降低在流架構(gòu)中移動碎片的總數(shù)
??讓我們深入到每個領(lǐng)域。
??Kafka Stream如何構(gòu)建更簡單的流服務(wù)的第一個方面是集群和框架自由,它只是一個庫(而且是非常小的一個)。你不需要去搭建任何特殊的Kafka Stream集群,并且沒有集群管理,nimbus,守護進程,或類似的東西。如果你擁有kafka,除了你自己的應(yīng)用代碼你不需要別的。你的應(yīng)用代碼將配合Kafka處理故障,瓜分實例中的處理負荷,若更多實例啟動,并動態(tài)平衡負荷。
??我會進一步講解,為什么我認為這是重要的,通過介紹了解這種模式的重要。
??我已經(jīng)涵蓋搭建Samza經(jīng)驗以及搭建(實時MapReduce)和人們真正想要(簡單流服務(wù))的概念切割。我認為這種問題的誤解是常見的,畢竟流處理所做的是從批世界獲取的能力以及滿足低延遲情況可用。同樣的MapReduce傳統(tǒng)影響了其他流處理平臺(Storm,Spark),不亞于Samza。
??在Linkedin發(fā)現(xiàn),生產(chǎn)數(shù)據(jù)處理服務(wù)正處于低延遲領(lǐng)域:優(yōu)先郵件,規(guī)范用戶產(chǎn)生的內(nèi)容,以及處理新聞推送等等。
??這種異步服務(wù)對網(wǎng)絡(luò)公司是幾乎唯一的,物流公司需要實時管理、交付,零售商需要對銷售產(chǎn)品重新訂購、重新定價,在許多方面,實時數(shù)據(jù)是金融公司紛紛看好的核心。畢竟,許多業(yè)務(wù)是異步的,在呈現(xiàn)網(wǎng)頁或更新手機應(yīng)用的過程中并不發(fā)生。
??為什么像Storm、Samza、Spark Streaming如此嚴峻的在流處理框架的頂端構(gòu)建這種類型的核心應(yīng)用?
??類似MapReduce和Spark的批處理框架需要解決大量問題:
- 在大量的機器上不得不復用眾多的瞬態(tài)工作,并有效的分配集群資源
- 要做到這一點,需要動態(tài)打包代碼、配置、庫和你需要運行的其他東西,并完全的部署到執(zhí)行機器上
- 需要管理進程,并試圖保證集群共享任務(wù)的隔離
??不幸的是,解決這些問題使得框架相當復雜。為了換取容錯和擴展性,他們想要控制代碼如何部署、配置、監(jiān)控和打包各個方面。
??更現(xiàn)代化的處理框架在嘗試包裝這個方面做的非常好,但是你不能避免的事實是該框架試圖以某種形式序列化你的代碼,并發(fā)送到網(wǎng)絡(luò)中。
??Kafka Stream更加專注于解決問題,做了一下工作:
??通過使用完全相同的組管理協(xié)議,Kafka提供正常consumer完成這點。結(jié)果是,Kafka Stream應(yīng)用就像任何其他服務(wù)??赡苡幸恍┐疟P上的本地狀態(tài),但是只是一個緩存,如果丟失或者應(yīng)用實例移動到別處,可以重新創(chuàng)建。你只需要應(yīng)用中的庫,啟動應(yīng)用程序?qū)嵗?,并且在這些實例下Kafka會分區(qū)、平衡任務(wù)。
??對于做一些簡單的類似回滾重啟或者無停機擴容是相當重要的,這些在現(xiàn)代軟件引擎中是習以為常的,但是對于流處理來說仍然是遙不可及的。
??從流處理框架分離封裝和部署如此重要的原因之一,是因為封裝和部署正在復興。Kafka Stream應(yīng)用能夠使用傳統(tǒng)的ops工具部署,如Puppet,Chef,Salt或者從命令行啟動進行。如果你還年輕,或者作為一個WAR文件,你可以打包你應(yīng)用作為一個Docker鏡像。
??但是,對于尋找更彈性管理的人,有旨在是應(yīng)用更動態(tài)的主機框架。部分名單包括:
- 類似Marathon帶有框架的Apache Mesos
- Kubernetes
- YARN
- 來自Dockers的Swarm
- 亞馬遜各種托管容器服務(wù),如ECS
- Cloud Foundry
??幾乎和流處理的生態(tài)系統(tǒng)一樣混亂。
??事實上,Mesos和Kubernetes正在試圖解決機器進程位置,Storm集群同樣在嘗試解決,當你不是一個Storm工作到Storm集群。關(guān)鍵區(qū)別是,這個問題非常困難,這些通用框架,至少是不錯的,能夠讓你可控并行的回滾重啟、sticky host affinity、真正的基于cgroup隔離、封裝dockers、華而不實的UI界面等等。
??你可以在這些框架中使用Kafka Stream,和其他應(yīng)用程序類似,這是一個簡單的方法獲取動態(tài)彈性管理。例如,如果你擁有Mesos和Marathon,你可以通過Marathon UI直接啟動你的Kafka Stream應(yīng)用,并無需停機的動態(tài)擴展,Mesos主要管理進程,Kafka采取負載均衡并維護你的作業(yè)處理狀態(tài)。
??采用其中一個框架的開銷相當于類似Storm操作集群管理,但是優(yōu)點是,這些框架完全是可選的(當然沒有他們,Kafka Stream正常工作)。
??下一個Kafka Stream 簡化流應(yīng)用的關(guān)鍵是完全集成流賀彪的概念。我們在之前以 “turning the database inside out”的方式討論過這個想法,這句話捕獲了所得系統(tǒng)如何重鑄應(yīng)用和數(shù)據(jù)關(guān)系,以及如何重鑄數(shù)據(jù)變化的重點。為了明白這一點,我會解釋我所認為table和stream的含義,以及為什么二者結(jié)合簡化了異步通用模式一大堆東西。
??傳統(tǒng)數(shù)據(jù)庫,存儲表的全狀態(tài)。數(shù)據(jù)庫做不到的是響應(yīng)數(shù)據(jù)流。什么是事件?事件是世界上發(fā)生的事情,可能是點擊,銷售等等。
??類似Storm的流處理系統(tǒng)已經(jīng)從另一個方向啟動。他們構(gòu)建處理事件流,但是計算流狀態(tài)的想法是之后了。
??我認為,異步應(yīng)用問題的根本是結(jié)合帶有正在發(fā)生事件流的表示世界當前狀態(tài)的表??蚣苄枰龊帽硎竞蛠砘剞D(zhuǎn)換它們。
??如何關(guān)聯(lián)這些概念?考慮一個簡單零售商店模型。銷售的核心流是銷售產(chǎn)品,訂購新產(chǎn)品并且送達產(chǎn)品?!艾F(xiàn)有庫存”是從已經(jīng)產(chǎn)品庫存通過加減銷售和物流得到的。對于零售店兩個關(guān)鍵的流處理操作是當庫存降低是再訂購,當需求和供給改變是調(diào)整價格。一個真正的全球零售商會復雜的多,因為物流的出貨量是由整個倉庫和商店的全球網(wǎng)絡(luò)和一臺分析和庫存調(diào)整的主機管理的,但是理解如何對實時事物作為表和流建模是關(guān)鍵。
??在我們深入流處理之前,先了解表和流之間的關(guān)系。我認為 Pat Helland對數(shù)據(jù)庫和日志概括是最好的:
事物日志記錄了所有數(shù)據(jù)庫做出的改變。高速追加是對更改日志的唯一途徑。從這個角度看,數(shù)據(jù)庫保留日志中最新記錄值的緩存。事實是日志。數(shù)據(jù)庫是日志高速緩存的一個子集。緩存子集恰好是日志中每個記錄和索引的最新值。
??這是什么意思呢?其實是表和流之間關(guān)系的核心。
??先問一個問題:什么是流?這個很簡單,流是一個記錄的序列。Kafka將流模型化為一個日志,也就是永無休止的key-value對序列。
key1 => value1key2 => value2key1 => value3 . . .
??那什么是表呢?我想我們都知道,表類似下面的東西:
??value可以是非常復雜的,在這種情況下需要拆分為多個列,但是我們可以忽略細節(jié),只是考慮key/value對(增加列不會改變這里討論的任何東西)。
??但是,盡管流隨著時間新紀錄出現(xiàn)而不斷演變,只是這一個點表的快照。表如何演變?更新。表不是一個單一的東西,而更像一系列的事情。
??但是序列有許多冗余。如果我們分解出的行沒有改變,只是記錄更新,然后以另一種方式可視化表作為有序序列的更新:
put(key1, value1)put(key2, value2)put(key1, value3)...
??或者,如果我們擺脫了put,因為他是隱含的,然后我們得到:
key1 => value1key2 => value2key1 => value3...
??這就是一個流!這種特殊形式的流通常稱為更新日志。因為他表示更新的序列,以更新順序記錄每一條記錄的最新值。
??所以,表是流上的一個特殊視圖。這樣的想法似乎很奇怪,但我認為,這種形式的表是我們腦海中想象的長方形表的東西。也許實際上更自然,因為他捕獲了時間上演化的概念(想想,什么樣的數(shù)據(jù)你沒有真的改變?)。
??換句話說,正如Pat Helland指出,表其實是流中每個key的最新value的緩存。
??數(shù)據(jù)庫方面的另一種方式:一個pure流是其中變化被解釋為INSERT語句(因為沒有記錄替換所有現(xiàn)有的記錄),其中一個表是改變被解釋為UPDATE的流(因為任何現(xiàn)有的行使用相同的Key將被覆蓋)
??這種二重性構(gòu)建為Kafka,并顯示為緊密的topic。
??Okay,這就是表和流,為什么會影響流處理?事實證明,流和表之間的關(guān)系是流處理的核心。
??給出的零售的例子,產(chǎn)品發(fā)貨和銷售流影響受傷的庫存表,庫存的改變又重新觸發(fā)流程依次重新排序和改變價格。
??在本例中,表明顯不知識流處理框架創(chuàng)建的東西,他們可能已經(jīng)在數(shù)據(jù)庫中。這很好,捕獲流的改變到表中,稱之為Change Capture,這是數(shù)據(jù)庫所做的事情。更改捕獲數(shù)據(jù)流的格式正式我們描述的更新日志的格式。這種更改捕獲可以非常簡單的使用Kafka鏈接,這是轉(zhuǎn)為數(shù)據(jù)采集的框架,而且已經(jīng)加入到最新的Apache Kafka 0.9版本。
??以這種方式模型化表的概念,Kafka Stream讓你使用改變的流計算表導出的value。換句話說讓你處理數(shù)據(jù)庫更改流就像點擊流一樣。
??你能想到觸發(fā)計算的功能是基于數(shù)據(jù)庫改變作為類似觸發(fā)器和數(shù)據(jù)庫內(nèi)置的物化視圖功能,而不是被限制在單一數(shù)據(jù)庫中,只有在PL/SQL中實驗,它運行在數(shù)據(jù)中心的規(guī)模,并且能夠處理各種數(shù)據(jù)源。
??我們探索了如何使用表,轉(zhuǎn)變?yōu)镵afka的更新流(更改日志),并使用Kafka Stream計算一些東西。但是表/流二者也可以反向工作。
??比方說,我有用戶進來的點擊流,我想計算每個用戶的總點擊量。Kafka Stream能夠讓你計算這個聚合,毋庸置疑地,每個用戶一個點擊量表。
??就Kafka Stream存儲而言,這衍生出本地嵌入key-value存儲(默認是RockDB,你可以使用任何接口)。作業(yè)輸出實際上是此表的更新更改日志。更改日志用于計算的高可用,但是可以是由其他Kafka Stream處理或使用Kafka連接加載到其他系統(tǒng)消費轉(zhuǎn)換的輸出。
??從架構(gòu)上來講,支持本地存儲已經(jīng)存在于Apache Samza,在之前從系統(tǒng)結(jié)構(gòu)的角度敘述過。Kafka Stream中心的關(guān)鍵是表的概念不僅僅是一個低水平的設(shè)施。和流本身一樣是一等公民。在編程DSL中流由Kafka Stream提供的KStream類表現(xiàn),表由KTable表現(xiàn)。他們共享很多相同操作,并且可以來回轉(zhuǎn)換,和表/流二元采樣一樣,但是,例如,一個KTable上的聚合會自動處理更新到底層值。這很重要,因為計算表更新和不可變流更新的語句是完全不同的,同樣的join兩個流的語句(比如點擊和展示)和join流到表(比如點擊對用戶賬戶)的語句也是完全不同的。通過DSL模型話這兩個概念,這些細節(jié)會自動解散。
?? 窗口,時間和無序的事件是流處理的另一個棘手的問題。而事實證明,有些奇怪的是,一個非常簡單的結(jié)論是非常相同的表的概念。密切關(guān)注流處理領(lǐng)域的人可能聽說過Google Dataflow團隊激烈討論的“event time”這個想法。他們爭論的問題是如果事件無序到達如何在流上做窗口操作。無序數(shù)據(jù)的問題在大多數(shù)分布式設(shè)置是不可避免的,因為不能保證在不同數(shù)據(jù)中心或不同設(shè)備保證的數(shù)據(jù)有序。
??零售領(lǐng)域中這種窗口計算的一個例子是每10分鐘的窗口計算一個產(chǎn)品的銷量。你怎么知道一個窗口計算完成了,在這范圍中帶時間戳的銷量數(shù)據(jù)到達了并且已經(jīng)計算過了?如果你不知道這些,你怎么能對這些計算給出一個最總答案?當你選擇你的結(jié)果作為答案可能太早,并且很多時間可能晚點到達導致你原始輸出是錯的。
??Kafka Stream解決這個問題非常簡單:窗口聚合的語句例如計數(shù),代表窗口到目前為止的計數(shù)。持當新數(shù)據(jù)到達續(xù)不斷更新,并有下游接收者決定完成時間。這個更新量的概念看起來有些熟悉:只不過是其中窗口正在更新表中key。自然地,下游操作知道這個流代表一個表,當他們到達,進行處理。
??我認為它是優(yōu)雅的,允許計算數(shù)據(jù)庫變化頂端捕獲流的機制和允許處理無序數(shù)據(jù)窗口聚合機制以一樣的。表和流之間的關(guān)系不是我們發(fā)明的,在很多舊的流處理文獻中如CQL被探索,但是沒有捕獲實時系統(tǒng)–數(shù)據(jù)庫處理表,流處理系統(tǒng)處理流以及把二者的處理作為一等公民。
??還有一些我剛描述特征可能不是特別明顯。我討論了Kafka Stream如何讓你透明地維護RocksDB或其他本地數(shù)據(jù)結(jié)構(gòu)的派生表。因為這種處理并創(chuàng)建物理狀態(tài)駐留在你的應(yīng)用,這開啟了另一種令人著迷的使用途徑:允許應(yīng)用程序直接查詢此派生狀態(tài)。
??我們還沒有公開使用鉤子可以做到這一點。我們正專注于穩(wěn)定流處理的API,但是我認為對某些數(shù)據(jù)密集型的應(yīng)用是非常有前途的架構(gòu)。
??這意味著你可以構(gòu)建嵌入Kafka Stream和直接查詢由流處理操作的出本地聚合的REST服務(wù)。這種狀態(tài)服務(wù)的有點在這里討論。并不是所有領(lǐng)域都有意義,通常你只想produce你的輸出到你知道并新人的外部數(shù)據(jù)庫。但某些情況每個請求你的服務(wù)需要訪問大量數(shù)據(jù),在本地內(nèi)存或快速的本地RocksDB實例可以說是非常強大的。
??我們的首要目標是讓構(gòu)建和操作流處理應(yīng)用的過程簡單。我們相信,流處理應(yīng)該是構(gòu)建應(yīng)用程序的主流方式,相當大比例的公司工作內(nèi)容是在構(gòu)建流處理的異步領(lǐng)域。但是,為了實現(xiàn)這一點,我們需要讓他足夠簡單去依賴這種方式。操作簡單的一部分來自于擺脫外部集群的需要。
??如果你看看人們構(gòu)建流處理應(yīng)用超過框架本身,他們往往是優(yōu)秀架構(gòu)的綜合體。下面是一個典型的流處理應(yīng)用架構(gòu)圖:
- Kafka本身
- 一個Storm,Spark的流處理集群,通常是一組住進程和每個節(jié)點的守護進程
- 實際流處理任務(wù)
- 用戶查找和聚合的side-數(shù)據(jù)庫
- 通過應(yīng)用查詢和獲取流處理任務(wù)輸出的數(shù)據(jù)庫
- Hadoop集群(包含大量部件)用于再處理數(shù)據(jù)
- 服務(wù)用戶和顧客正常請求的請求/響應(yīng)應(yīng)用
??Plunk下來這樣怪異的東西不僅是不可取的,通常也是不可行的。即使你擁有所有這些,綁在一起形成以個兩個的監(jiān)督,充分實施這一切很難做到。
??關(guān)于Kafka Stream最愉快的事情是核心概念很少,而且在整個系統(tǒng)中運行。
??我們已經(jīng)談到幾個重要的方面:擺脫額外的流處理集群;讓表和狀態(tài)處理完全整合到流處理本身。Kafka Stream架構(gòu)可以縮小到如下:
- 輸入輸出都是Kafka topic
- 數(shù)據(jù)模型處處都是Kafka帶key的記錄數(shù)據(jù)
- 分區(qū)模型只是Kafka的分區(qū)模型,Kafka分區(qū)適用于流
- 管理分區(qū),分配和活躍度的組成員機制就是Kafka的組成員機制
- 表和其他帶狀態(tài)的計算只需要log緊湊的topic
- 度量在整個producer,consumer和流應(yīng)用中是統(tǒng)一的,所以只有一種類型的度量捕獲監(jiān)控
- 應(yīng)用的位置由應(yīng)用的偏移量維持,和Kafka consumer類似
- 用于窗口的時間戳在0.10版本被添加到Kafka本身, 為你提供事件-時間處理
??總之,在許多方面Kafka Stream應(yīng)用看起來和其他Kafka producer和consumer類似,但他更簡潔。
??配置參數(shù)的數(shù)量超過Kafka客戶端基本需要是非常少的。
??如果你改變你的代碼,需要用新的邏輯重新處理數(shù)據(jù),并不需要一個完全不同的系統(tǒng),你可以倒回應(yīng)用程序的Kafka偏移量,并重新處理他的輸出(你可以,用Hadoop或者其他來重新處理)。
??最初的例子架構(gòu)是一套獨立的部分,只有部分一起工作。我們希望你認為是Kafka,Kafka Connect,Kafka Stream共同努力的結(jié)果。
??由于早期版本發(fā)現(xiàn)一些我們還沒有解決的問題。下面即將完成的幾件事。
??正如早起提到的可嵌入庫和存儲分區(qū)隨機訪問表能力結(jié)合的優(yōu)勢之一是超出用于由應(yīng)用嵌入處理查詢表的能力。
??當前版本的Kafka Streaming繼承了Kafka的語句,通常被描述為“至少一次傳遞”。Kafka社區(qū)完成了許多對如何通過Kafka Connect,Kafka和Kafka Stream或其他帶有派生表或狀態(tài)計算引擎提供end-to-end的方式加強這些保證想法和探索。在未來幾個月我們會深入這個領(lǐng)域,并得到一些建議。
??關(guān)于這方法一個很好的事情是代碼的數(shù)量非常少,我們認為能夠構(gòu)建主流語言的實現(xiàn),并且讓他們感覺仍是自己生態(tài)系統(tǒng)的本地人。我們集中于讓普通客戶最先呈現(xiàn),我們會在流處理支持不久后處理這個問題。