轉自:https://www.iteblog.com/archives/2430.htmlhtml
本文翻譯自《Streaming System》最後一章《The Evolution of Large-Scale Data Processing》,在探討流式系統方面本書是市面上可貴一見的深度書籍,很是值得學習。前端
大數據若是從 Google 對外發布 MapReduce 論文算起,已經先後跨越十五年,我打算在本文和你走馬觀花般一塊兒瀏覽下大數據的發展史,咱們從最開始 MapReduce 計算模型開始,一路蜻蜓點水看看大數據這十五年關鍵發展變化,同時也順便會講解流式處理這個領域是如何發展到今天的這幅模樣。這其中我也會加入一些我對一些業界知名大數據處理系統 (可能裏面有些也不那麼出名) 的觀察和評論,同時考慮到我頗有可能簡化、低估甚至於忽略了不少重要的大數據處理系統,我也會附帶一些參考材料幫助你們學習更多更詳細的知識。web
另外,咱們僅僅討論了大數據處理中偏 MapReduce/Hadoop 系統及其派系分支的大數據處理。我沒有討論任何 SQL 引擎 [1],咱們一樣也沒有討論 HPC 或者超級計算機。儘管我這章的標題聽上去領域覆蓋很是普遍,但實際上我僅僅會討論一個相對比較垂直的大數據領域。算法
一樣須要提醒的一件事情是,我在本文裏面或多或少會提到一些 Google 的技術,不用說這塊是由於與我在谷歌工做了十多年的經歷有關。 但還有另外兩個緣由:1)大數據對谷歌來講一直很重要,所以在那裏創造了許多有價值的東西值得詳細討論,2)個人經驗一直是 谷歌之外的人彷佛更喜歡學習 Google 所作的事情,由於 Google 公司在這方面一直有點守口如瓶。 因此,當我過度關注咱們一直在"閉門造車"的東西時,姑且容忍下我吧。數據庫
爲了使咱們這一次大數據旅行顯得更加具體有條理,咱們設計了圖 10-1 的時間表,這張時間表歸納地展現了不一樣系統的誕生日期。apache
在每個系統介紹過程當中,我會盡量說明清楚該系統的簡要歷史,而且我會嘗試從流式處理系統的演化角度來闡釋該系統對演化過程的貢獻。最後,咱們將回顧以上系統全部的貢獻,從而全面瞭解上述系統如何演化並構建出現代流式處理系統的。編程
文章目錄api
咱們從 MapReduce 開始咱們的旅程。安全
我認爲咱們能夠很肯定地說,今天咱們討論的大規模數據處理系統都源自於 2003 年 MapReduce。當時,谷歌的工程師正在構建各類定製化系統,以解決互聯網時代下大數據處理難題。當他們這樣嘗試去解決這些問題時候,發現有三個難以逾越的坎兒:性能優化
在多種應用場景中都嘗試解決了上述三個問題以後,Google 的工程師們開始注意到各自構建的定製化系統之間很有類似之處。最終,Google 工程師悟出來一個道理: 若是他們可以構建一個能夠解決上述問題二和問題三的框架,那麼工程師就將能夠徹底放下問題二和三,從而集中精力解決每一個業務都須要解決的問題一。因而,MapReduce 框架誕生了。
MapReduce 的基本思想是提供一套很是簡潔的數據處理 API,這套 API 來自於函數式編程領域的兩個很是易於理解的操做:map 和 reduce(圖 10-3)。使用該 API 構建的底層數據流將在這套分佈式系統框架上執行,框架負責處理全部繁瑣的可擴展性和容錯性問題。可擴展性和容錯性問題對於分佈式底層工程師來講無疑是很是有挑戰的課題,但對於咱們普通工程師而言,無益因而災難。
咱們已經在第 6 章詳細討論了 MapReduce 的語義,因此咱們在此再也不贅述。僅僅簡單地回想一下,咱們將處理過程分解爲六個離散階段(MapRead,Map,MapWrite,ReduceRead,Reduce,ReduceWrite)做爲對於流或者表進行分析的幾個步驟。咱們能夠看到,總體上 Map 和 Reduce 階段之間差別其實也不大 ; 更高層次來看,他們都作了如下事情:
隨後,Google 內部將 MapReduce 投入生產使用並獲得了很是普遍的業務應用,Google 認爲應該和公司外的同行分享咱們的研究成果,最終咱們將 MapReduce 論文發表於 OSDI 2004(見圖 10-4)。
論文中,Google 詳細描述了 MapReduce 項目的歷史,API 的設計和實現,以及有關使用了 MapReduce 框架的許多不一樣生產案例的詳細信息。固然,Google 沒有提供任何實際的源代碼,以致於最終 Google 之外的人都認爲:「是的,這套系統確實牛啊!」,而後立馬回頭去模仿 MapReduce 去構建他們的定製化系統。
在隨後這十年的過程當中,MapReduce 繼續在谷歌內部進行大量開發,投入大量時間將這套系統規模推動到史無前例的水平。若是讀者朋友但願瞭解一些更加深刻更加詳細的 MapReduce 說明,我推薦由咱們的 MapReduce 團隊中負責擴展性、性能優化的大牛 Marián Dvorský撰寫的文章《History of massive-scale sorting experiments at Google》(圖 10-5)
我這裏但願強調的是,這麼多年來看,其餘任何的分佈式架構最終都沒有達到 MapReduce 的集羣規模,甚至在 Google 內部也沒有。從 MapReduce 誕生起到如今已經跨越十載之久,都未能看到真正可以超越 MapReduce 系統規模的另一套系統,足見 MapReduce 系統之成功。14 年的光陰看似不長,對於互聯網行業已然永久。
從流式處理系統來看,我想爲讀者朋友強調的是 MapReduce 的簡單性和可擴展性。 MapReduce 給咱們的啓發是:MapReduce 系統的設計很是敢於創新,它提供一套簡便且直接的 API,用於構建業務複雜但可靠健壯的底層分佈式數據 Pipeline,並足夠將這套分佈式數據 Pipeline 運行在廉價普通的商用服務器集羣之上。
咱們大數據旅程的下一站是 Hadoop(圖 10-6)。須要着重說明的是:我爲了保證咱們討論的重心不至於偏離太多,而壓縮簡化討論 Hadoop 的內容。但必須認可的是,Hadoop 對咱們的行業甚至整個世界的影響不容小覷,它帶來的影響遠遠超出了我在此書討論的範圍。
Hadoop 於 2005 年問世,當時 Doug Cutting 和 Mike Cafarella 認爲 MapReduce 論文中的想法太棒了,他們在構建 Nutch webcrawler 的分佈式版本正好須要這套分佈式理論基礎。在這以前,他們已經實現了本身版本的 Google 分佈式文件系統(最初稱爲 Nutch 分佈式文件系統的 NDFS,後來更名爲 HDFS 或 Hadoop 分佈式文件系統)。所以下一步,天然而然的,基於 HDFS 之上添加 MapReduce 計算層。他們稱 MapReduce 這一層爲 Hadoop。
Hadoop 和 MapReduce 之間的主要區別在於 Cutting 和 Cafarella 經過開源(以及 HDFS 的源代碼)確保 Hadoop 的源代碼與世界各地能夠共享,最終成爲 Apache Hadoop 項目的一部分。雅虎聘請 Cutting 來幫助將雅虎網絡爬蟲項目升級爲所有基於 Hadoop 架構,這個項目使得 Hadoop 有效提高了生產可用性以及工程效率。自那之後,整個開源生態的大數據處理工具生態系統獲得了蓬勃發展。與 MapReduce 同樣,相信其餘人已經可以比我更好地講述了 Hadoop 的歷史。我推薦一個特別好的講解是 Marko Bonaci 的《The history of Hadoop》,它自己也是一本已經出版的紙質書籍(圖 10-7)。
在 Hadoop 這部分,我指望讀者朋友可以瞭解到圍繞 Hadoop 的開源生態系統對整個行業產生的巨大影響。經過建立一個開放的社區,工程師能夠從早期的 GFS 和 MapReduce 論文中改進和擴展這些想法,這直接促進生態系統的蓬勃發展,並基於此之上產生了許多有用的工具,如 Pig,Hive,HBase,Crunch 等等。這種開放性是致使咱們整個行業現有思想多樣性的關鍵,同時 Hadoop 開放性生態亦是直接促進流計算系統發展。
咱們如今再回到 Google,討論 Google 公司中 MapReduce 的官方繼承者:Flume([圖 10-8],有時也稱爲 FlumeJava,這個名字起源於最初 Flume 的 Java 版本。須要注意的是,這裏的 Flume 不要與 Apache Flume 混淆,這部分是面向不一樣領域的東西,只是剛好有一樣的名字)。
Flume 項目由 Craig Chambers 在 2007 年穀歌西雅圖辦事處成立時發起。Flume 最初打算是但願解決 MapReduce 的一些固有缺點,這些缺點即便在 MapReduce 最初大紅大紫的階段已經很是明顯。其中許多缺點都與 MapReduce 徹底限定的 Map→Shuffle→Reduce 編程模型相關 ; 這個編程模型雖然簡單,但它帶來了一些缺點:
Beam主要的抽象模型,即 PCollection 和 PTransform 概念,如圖 10-9 所示。
這些數據處理 Pipeline 在做業啓動時將經過優化器生成,優化器將以最佳效率生成 MapReduce 做業,而後交由框架編排執行。整個編譯執行原理圖能夠在圖 10-10 中看到。
也許 Flume 在自動優化方面最重要的案例就是是合併(Reuven 在第 5 章中討論了這個主題),其中兩個邏輯上獨立的階段能夠在同一個做業中順序地(消費者 - 生產者融合)執行或者並行執行(兄弟融合),如圖 10-11 所示。
將兩個階段融合在一塊兒消除了序列化 / 反序列化和網絡開銷,這在處理大量數據的底層 Pipeline 中很是重要。
另外一種類型的自動優化是 combiner lifting(見圖 10-12),當咱們討論增量合併時,咱們已經在第 7 章中討論了這些機制。combiner lifting 只是咱們在該章討論的多級組合邏輯的編譯器自動優化:以求和操做爲例,求和的合併邏輯原本應該運算在分組 (譯者注: 即 Group-By) 操做後,因爲優化的緣由,被提早到在 group-by-key 以前作局部求和(根據 group-by-key 的語義,通過 group-by-key 操做須要跨網絡進行大量數據 Shuffle)。在出現數據熱點狀況下,將這個操做提早能夠大大減小經過網絡 Shuffle 的數據量,而且還能夠在多臺機器上分散掉最終聚合的機器負載。
因爲其更清晰的 API 定義和自動優化機制,在 2009 年初 Google 內部推出後 FlumeJava 當即受到巨大歡迎。以後,該團隊發表了題爲《Flume Java: Easy, Efficient Data-Parallel Pipelines》(https://storage.googleapis.com/pub-tools-public-publication-data/pdf/35650.pdf) 的論文(參見圖 10-13),這篇論文自己就是一個很好的學習 FlumeJava 的資料。
Flume C++ 版本很快於 2011 年發佈。以後 2012 年初,Flume 被引入爲 Google 的全部新工程師提供的 Noogler6 培訓內容。MapReduce 框架因而最終被走向被替換的命運。
從那時起,Flume 已經遷移到再也不使用 MapReduce 做爲執行引擎 ; 相反,Flume 底層基於一個名爲 Dax 的內置自定義執行引擎。 工做自己。不只讓 Flume 更加靈活選擇執行計劃而沒必要拘泥於 Map→Shuffle→Reduce MapReduce 的模型,Dax 還啓用了新的優化,例如 Eugene Kirpi-chov 和 Malo Denielou 的《No shard left behind》博客文章(https://cloud.google.com/blog/products/gcp/no-shard-left-behind-dynamic-work-rebalancing-in-google-cloud-dataflow) 中描述的動態負載均衡(圖 10-14)。
儘管那篇博客主要是基於 Google DataFlow 框架下討論問題,但動態負載均衡(或液態分片,Google 內部更習慣這樣叫)可讓部分已經完成工做的 Worker 可以從另一些繁忙的 Worker 手中分配一些額外的工做。在 Job 運行過程當中,經過不斷的動態調整負載分配能夠將系統運行效率趨近最優,這種算法將比傳統方法下有經驗工程師手工設置的初始參數性能更好。Flume 甚至爲 Worker 池變化進行了適配,一個拖慢整個做業進度的 Worker 會將其任務轉移到其餘更加高效的 Worker 上面進行執行。Flume 的這些優化手段,在 Google 內部爲公司節省了大量資源。
最後一點,Flume 後來也被擴展爲支持流語義。除 Dax 做爲一個批處理系統引擎外,Flume 還擴展爲可以在 MillWheel 流處理系統上執行做業(稍後討論)。在 Google 內部,以前本書中討論過的大多數高級流處理語義概念首先被整合到 Flume 中,而後才進入 Cloud Dataflow 並最終進入 Apache Beam。
總而言之,本節咱們主要強調的是 Flume 產品給人引入高級管道概念,這使得可以讓用戶編寫清晰易懂且自動優化的分佈式大數據處理邏輯,從而讓建立更大型更復雜的分佈式大數據任務成爲了可能,Flume 讓咱們業務代碼在保持代碼清晰邏輯乾淨的同時,自動具有編譯器優化能力。
接下來是 Apache Storm(圖 10-15),這是咱們研究的第一個真正的流式系統。 Storm 確定不是業界使用最先的流式處理系統,但我認爲這是整個行業真正普遍採用的第一個流式處理系統,所以咱們在這裏須要仔細研究一下。
Storm 是 Nathan Marz 的心血結晶,Nathan Marz 後來在一篇題爲《History of Apache Storm and lessons learned》的博客文章(http://nathanmarz.com/blog/history-of-apache-storm-and-lessons-learned.html) 中記錄了其創做歷史(圖 10-16)。 這篇冗長的博客講述了 BackType 這家創業公司一直在本身經過消息隊列和自定義代碼去處理 Twitter 信息流。Nathan 和十幾年前 Google 裏面設計 MapReduce 相關工程師有相同的認識:實際的業務處理的代碼僅僅是系統代碼很小一部分,若是有個統一的流式實時處理框架負責處理各種分佈式系統底層問題,那麼基於之上構建咱們的實時大數據處理將會輕鬆得多。基於此,Nathan 團隊完成了 Storm 的設計和開發。
值得一提的是,Storm 的設計原則和其餘系統截然不同,Storm 更多考慮到實時流計算的處理時延而非數據的一致性保證。後者是其餘大數據系統必備基礎產品特徵之一。Storm 針對每條流式數據進行計算處理,並提供至多一次或者至少一次的語義保證;同時不提供任何狀態存儲能力。相比於 Batch 批處理系統可以提供一致性語義保證,Storm 系統可以提供更低的數據處理延遲。對於某些數據處理業務場景來講,這確實也是一個很是合理的取捨。
不幸的是,人們很快就清楚地知道他們想要什麼樣的流式處理系統。他們不只但願快速獲得業務結果,同時但願系統具備低延遲和準確性,但僅憑 Storm 架構實際上不可能作到這一點。針對這個狀況,Nathan 後面又提出了 Lambda 架構。
鑑於 Storm 的侷限性,聰明的工程師結合弱一致語義的 Storm 流處理以及強一致語義的 Hadoop 批處理。前者產生了低延遲,但不精確的結果,然後者產生了高延遲,但精確的結果,雙劍合璧,整合兩套系統總體提供的低延遲但最終一致的輸出結果。咱們在第 1 章中瞭解到,Lambda 架構是 Marz 的另外一個創意,詳見他的文章《「如何擊敗 CAP 定理」》(http://nathanmarz.com/blog/how-to-beat-the-cap-theorem.html) (圖 10-17)。
我已經花了至關多的時間來分析 Lambda 架構的缺點,以致於我不會在這裏囉嗦這些問題。但我要重申一下:儘管它帶來了大量成本問題,Lambda 架構當前仍是很是受歡迎,僅僅是由於它知足了許多企業一個關鍵需求:系統提供低延遲但不許確的數據,後續經過批處理系統糾正以前數據,最終給出一致性的結果。從流處理系統演變的角度來看,Storm 確實爲普羅大衆帶來低延遲的流式實時數據處理能力。然而,它是以犧牲數據強一致性爲代價的,這反過來又帶來了 Lambda 架構的興起,致使接下來多年基於兩套系統架構之上的數據處理帶來無盡的麻煩和成本。
撇開其餘問題先不說,Storm 是行業首次大規模嘗試低延遲數據處理的系統,其影響反映在當前線上大量部署和應用各種流式處理系統。在咱們要放下 Storm 開始聊其餘系統以前,我以爲仍是頗有必要去說說 Heron 這個系統。在 2015 年,Twitter 做爲 Storm 項目孵化公司以及世界上已知最大的 Storm 用戶,忽然宣佈放棄 Storm 引擎,宣稱正在研發另一套稱之爲 Heron 的流式處理框架。Heron 旨在解決困擾 Storm 的一系列性能和維護問題,同時向 Storm 保持 API 兼容,詳見題爲《Twitter Heron:Stream Processing at scale》的論文(https://www.semanticscholar.org/paper/Twitter-Heron%3A-Stream-Processing-at-Scale-Kulkarni-Bhagat/e847c3ec130da57328db79a7fea794b07dbccdd9) (圖 10-18)。
Heron 自己也是開源產品(但開源不在 Apache 項目中)。鑑於 Storm 仍然在社區中持續發展,如今又冒出一套和 Storm 競爭的軟件,最終兩邊系統鹿死誰手,咱們只能拭目以待了。
繼續走起,咱們如今來到 Apache Spark(圖 10-19)。再次,我又將大量簡化 Spark 系統對行業的整體影響探討,僅僅關注咱們的流處理領域部分。
Spark 在 2009 年左右誕生於加州大學伯克利分校的著名 AMPLab。最初推進 Spark 成名的緣由是它可以常常在內存執行大量的計算工做,直到做業的最後一步才寫入磁盤。工程師經過彈性分佈式數據集(RDD)理念實現了這一目標,在底層 Pipeline 中可以獲取每一個階段數據結果的全部派生關係,而且容許在機器故障時根據須要從新計算中間結果,固然,這些都基於一些假設 a)輸入是老是可重放的,b)計算是肯定性的。對於許多案例來講,這些先決條件是真實的,或者看上去足夠真實,至少用戶確實在 Spark 享受到了巨大的性能提高。從那時起,Spark 逐漸創建起其做爲 Hadoop 事實上的繼任產品定位。
在 Spark 建立幾年後,當時 AMPLab 的研究生 Tathagata Das 開始意識到:嘿,咱們有這個快速的批處理引擎,若是咱們將多個批次的任務串接起來,用它可否來處理流數據?因而乎,Spark Streaming 誕生了。
關於 Spark Streaming 的真正精彩之處在於:強大的批處理引擎解決了太多底層麻煩的問題,若是基於此構建流式處理引擎則整個流處理系統將簡單不少,因而世界又多一個流處理引擎,並且是能夠獨自提供一致性語義保障的流式處理系統。換句話說,給定正確的用例,你能夠不用 Lambda 架構系統直接使用 Spark Streaming 便可知足數據一致性需求。爲 Spark Streaming 手工點贊!
這裏的一個主要問題是「正確的用例」部分。早期版本的 Spark Streaming(1.x 版本)的一大缺點是它僅支持特定的流處理語義:即,處理時間窗口。所以,任何須要使用事件時間,須要處理延遲數據等等案例都沒法讓用戶使用 Spark 開箱即用解決業務。這意味着 Spark Streaming 最適合於有序數據或事件時間無關的計算。並且,正如我在本書中重申的那樣,在處理當今常見的大規模、以用戶爲中心的數據集時,這些先決條件看上去並非那麼常見。
圍繞 Spark Streaming 的另外一個有趣的爭議是「microbatch 和 true streaming」爭論。因爲 Spark Streaming 創建在批處理引擎的重複運行的基礎之上,所以批評者聲稱 Spark Streaming 不是真正的流式引擎,由於整個系統的處理基於全局的數據切分規則。這個或多或少是實情。儘管流處理引擎幾乎老是爲了吞吐量而使用某種批處理或者相似的加大吞吐的系統策略,但它們能夠靈活地在更精細的級別上進行處理,一直能夠細化到某個 key。但基於微批處理模型的系統在基於全局切分方式處理數據包,這意味着同時具有低延遲和高吞吐是不可能的。確實咱們看到許多基準測試代表這說法或多或少有點正確。固然,做業可以作到幾分鐘或幾秒鐘的延遲已經至關不錯了,實際上生產中不多有用例須要嚴格數據正確性和低延遲保證。因此從某種意義上說,Spark 瞄準最初目標客戶羣體打法是很是到位的,由於大多數業務場景均屬於這一類。但這並未阻止其競爭對手將此做爲該平臺的巨大劣勢。就我的而言,在大多數狀況下,我認爲這只是一個很小問題。
撇開缺點不說,Spark Streaming 是流處理的分水嶺:第一個普遍使用的大規模流處理引擎,它也能夠提供批處理系統的正確性保證。 固然,正如前面提到的,流式系統只是 Spark 總體成功故事的一小部分,Spark 在迭代處理和機器學習領域作出了重要貢獻,其原生 SQL 集成以及上述快如閃電般的內存計算,都是很是值得大書特書的產品特性。
若是您想了解有關原始 Spark 1.x 架構細節的更多信息,我強烈推薦 Matei Zaharia 關於該主題的論文《 「An Architecture for Fast and General Data Processing on Large Clusters》(圖 10-20)。 這是 113 頁的 Spark 核心講解論文,很是值得一讀。
時至今日,Spark 的 2.x 版本極大地擴展了 Spark Streaming 的語義功能,其中已經包含了本書中描述流式處理模型的許多部分,同時試圖簡化一些更復雜的設計。 Spark 甚至推出了一種全新的、真正面向流式處理的架構,用以規避掉微批架構的種種問題。可是曾經,當 Spark 第一次出現時,它帶來的重要貢獻是它是第一個公開可用的流處理引擎,具備數據處理的強一致性語義,儘管這個特性只能用在有序數據或使用處理時間計算的場景。
接下來咱們討論 MillWheel,這是我在 2008 年加入 Google 後的花 20%時間兼職參與的項目,後來在 2010 年全職加入該團隊(圖 10-21)。
MillWheel 是 Google 最先的通用流處理架構,該項目由 Paul Nordstrom 在 Google 西雅圖辦事處開業時發起。 MillWheel 在 Google 內的成功與長期以來一直致力於爲無序數據提供低延遲,強一致的處理能力不無關係。
有點使人驚訝的是,MillWheel 項目最開始並未關注數據正確性。保羅最初的想法更接近於 Storm 的設計理論:具備弱一致性的低延遲數據處理。這是最初的 MillWheel 客戶,一個關於基於用戶搜索數據構建會話和另外一個對搜索查詢執行異常檢測(來自 MillWheel 論文的 Zeitgeist 示例),這兩家客戶迫使項目走向了正確的方向。二者都很是須要強一致的數據結果:會話用於推斷用戶行爲,異常檢測用於推斷搜索查詢的趨勢 ; 若是他們提供的數據不靠譜,二者效果都會顯着降低。最終,幸運的是,MillWheel 的設計被客戶需求導向追求數據強一致性的結果。
支持亂序數據處理,這是現代流式處理系統的另外一個核心功能。這個核心功能一般也被認爲是被 MillWheel 引入到流式處理領域,和數據準確性同樣,這個功能也是被客戶需求推進最終加入到咱們系統。 Zeitgeist 項目的大數據處理過程,一般被咱們拿來用做一個真正的流式處理案例來討論。Zeitgeist 項目但願檢測識別搜索查詢流量中的異常,而且須要捕獲異常流量。對於這個大數據項目數據消費者來講,流計算將全部計算結果產出並讓用戶輪詢全部 key 用來識別異常顯然不太現實,數據用戶要求系統直接計算某個 key 出現異常的數據結果,而不須要上層再來輪詢。對於異常峯值(即查詢流量的增長),這還相對來講比較簡單好解決:當給定查詢的計數超過查詢的預期值時,系統發出異常信號。可是對於異常降低(即查詢流量減小),問題有點棘手。僅僅看到給定搜索詞的查詢數量減小是不夠的,由於在任什麼時候間段內,計算結果老是從零開始。在這些狀況下你必須確保你的數據輸入真的可以表明當前這段時間真實業務流量,而後纔將計算結果和預設模型進行比較。
真正的流式處理
「真正的流式處理用例」須要一些額外解釋。流式系統的一個新的演化趨勢是,捨棄掉部分產品需求以簡化編程模型,從而使整個系統簡單易用。例如,在撰寫本文時,Spark Structured Streaming 和 Apache Kafka Streams 都將系統提供的功能限制在第 8 章中稱爲「物化視圖語義」範圍內,本質上對最終一致性的輸出表不停作數據更新。當您想要將上述輸出表做爲結果查詢使用時,物化視圖語義很是匹配你的需求:任什麼時候候咱們只需查找該表中的值而且 (譯者注: 儘管結果數據一直在不停被更新和改變) 以當前查詢時間請求到查詢結果就是最新的結果。但在一些須要真正流式處理的場景,例如異常檢測,上述物化視圖並不可以很好地解決這類問題。
接下來咱們會討論到,異常檢測的某些需求使其不適合純物化視圖語義(即,依次針對單條記錄處理),特別當須要完整的數據集纔可以識別業務異常,而這些異常剛好是因爲數據的缺失或者不完整致使的。另外,不停輪詢結果表以查看是否有異常其實並非一個擴展性很好的辦法。真正的流式用戶場景是推進 watermark 等功能的原始需求來源。(Watermark 所表明的時間有先有後,咱們須要最低的 Watermark 追蹤數據的完整性,而最高的 Watermark 在數據時間發生傾斜時候很是容易致使丟數據的狀況發生,相似 Spark Structured Streaming 的用法)。省略相似 Watermark 等功能的系統看上去簡單很多,但換來代價是功能受限。在不少狀況下,這些功能實際上有很是重要的業務價值。但若是這樣的系統聲稱這些簡化的功能會帶來系統更多的普適性,不要聽他們忽悠。試問一句,功能需求大量被砍掉,如何保證系統的普適性呢?
Zeitgeist 項目首先嚐試經過在計算邏輯以前插入處理時間的延遲數值來解決數據延遲問題。當數據按順序到達時,這個思路處理邏輯正常。但業務人員隨後發現數據有時可能會延遲很大,從而致使數據無序進入流式處理系統。一旦出現這個狀況,系統僅僅採用處理時間的延遲是不夠的,由於底層數據處理會由於數據亂序緣由被錯誤判斷爲異常。最終,咱們須要一種等待數據到齊的機制。
以後 Watermark 被設計出來用以解決數據亂序的問題。正如 Slava 在第 3 章中所描述的那樣,基本思想是跟蹤系統輸入數據的當前進度,對於每一個給定的數據源,構建一個數據輸入進度用來表徵輸入數據的完整性。對於一些簡單的數據源,例如一個帶分區的 Kafka Topic,每一個 Topic 下屬的分區被寫入的是業務時間持續遞增的數據(例如經過 Web 前端實時記錄的日誌事件),這種狀況下咱們能夠計算產生一個很是完美的 Watermark。但對於一些很是複雜的數據輸入,例如動態的輸入日誌集,一個啓發式算法多是咱們可以設計出來最能解決業務問題的 Watermark 生成算法了。但不管哪一種方式,Watermark 都是解決輸入事件完整性最佳方式。以前咱們嘗試使用處理時間來解決事件輸入完整性,有點驢頭不及馬嘴的感受。
得益於客戶的需求推進,MillWheel 最終成爲可以支持無序數據的強大流處理引擎。所以,題爲《MillWheel: Fault-Tolerant Stream Processing at Internet Scale》(圖 10-22)的論文花費大部分時間來討論在這樣的系統中提供正確性的各類問題,一致性保證、Watermark。若是您對這個主題感興趣,那值得花時間去讀讀這篇論文。
MillWheel 論文發表後不久,MillWheel 就成爲 Flume 底層提供支撐的流式處理引擎,咱們稱之爲 Streaming Flume。今天在谷歌內部,MillWheel 被下一代理論更爲領先的系統所替換: Windmill(這套系統同時也爲 DataFlow 提供了執行引擎),這是一套基於 MillWheel 之上,博採衆家之長的大數據處理系統,包括提供更好的調度和分發策略、更清晰的框架和業務代碼解耦。
MillWheel 給咱們帶來最大的價值是以前列出的四個概念(數據精確一次性處理,持久化的狀態存儲,Watermark,持久定時器)爲流式計算提供了工業級生產保障:即便在不可靠的商用硬件上,也能夠對無序數據進行穩定的、低延遲的處理。
咱們開始討論 Kafka(圖 10-23)。 Kafka 在本章討論的系統中是獨一無二的,由於它不是數據計算框架,而是數據傳輸和存儲的工具。可是,毫無疑問,Kafka 在咱們正在討論的全部系統中扮演了推進流處理的最有影響力的角色之一。
若是你不熟悉它,咱們能夠簡單描述爲: Kafka 本質上是一個持久的流式數據傳輸和存儲工具,底層系統實現爲一組帶有分區結構的日誌型存儲。它最初是由 Neha Narkhede 和 Jay Kreps 等業界大牛在 LinkedIn 公司內部開發的,其卓越的特性有:
在這些特性中,有兩個對我來講最爲突出。第一個是流數據的持久化和可重放性的應用。在 Kafka 以前,大多數流處理系統使用某種臨時、短暫的消息系統,如 Rabbit MQ 甚至是普通的 TCP 套接字來發送數據。數據處理的一致性每每經過生產者數據冗餘備份來實現(即,若是下游數據消費者出現故障,則上游生產者將數據進行從新發送),可是上游數據的備份一般也是臨時保存一下。大多數系統設計徹底忽略在開發和測試中須要從新拉取數據從新計算的需求。但 Kafka 的出現改變了這一切。從數據庫持久日誌概念獲得啓發並將其應用於流處理領域,Kafka 讓咱們享受到了如同 Batch 數據源同樣的安全性和可靠性。憑藉持久化和可重放的特色,流計算在健壯性和可靠性上面又邁出關鍵的一步,爲後續替代批處理系統打下基礎。
做爲一個流式系統開發人員,Kafka 的持久化和可重放功能對業界產生一個更有意思的變化就是: 當今大量流處理引擎依賴源頭數據可重放來提供端到端精確一次的計算保障。可重放的特色是 Apex,Flink,Kafka Streams,Spark 和 Storm 的端到端精確一次保證的基礎。當以精確一次模式執行時,每一個系統都假設 / 要求輸入數據源可以重放以前的部分數據 (從最近 Checkpoint 到故障發生時的數據)。當流式處理系統與不具有重放能力的輸入源一塊兒使用時(哪怕是源頭數據可以保證可靠的一致性數據投遞,但不能提供重放功能),這種狀況下沒法保證端到端的徹底一次語義。這種對可重放(以及持久化等其餘特色)的普遍依賴是 Kafka 在整個行業中產生巨大影響的間接證實。
Kafka 系統中第二個值得注意的重點是流和表理論的普及。咱們花了整個第 6 章以及第 8 章、第 9 章來討論流和表,能夠說流和表構成了數據處理的基礎,不管是 MapReduce 及其演化系統,SQL 數據庫系統,仍是其餘分支的數據處理系統。並非全部的數據處理方法都直接基於流或者表來進行抽象,但從概念或者理論上說,表和流的理論就是這些系統的運做方式。做爲這些系統的用戶和開發人員,理解咱們全部系統構建的核心基礎概念意義重大。咱們都很是感謝 Kafka 社區的開發者,他們幫助咱們更普遍更加深刻地瞭解到批流理論。
若是您想了解更多關於 Kafka 及其理論核心,JackKreps 的《I❤Logs》(O'Reilly; 圖 10-24)是一個很好的學習資料。另外,正如第 6 章中引用的那樣,Kreps 和 Martin Kleppmann 有兩篇文章(圖 10-25),我強烈建議您閱讀一下關於流和表相關理論。
Kafka 爲流處理領域作出了巨大貢獻,能夠說比其餘任何單一系統都要多。特別是,對輸入和輸出流的持久性和可重放的設計,幫助將流計算從近似工具的小衆領域發展到在大數據領域婦孺皆知的程度起了很大做用。此外,Kafka 社區推廣的流和表理論對於數據處理引起了咱們深刻思考。
Cloud Dataflow(圖 10-26)是 Google 徹底託管的、基於雲架構的數據處理服務。 Dataflow 於 2015 年 8 月推向全球。DataFlow 將 MapReduce,Flume 和 MillWheel 的十多年經驗融入其中,並將其打包成 Serverless 的雲體驗。
雖然 Google 的 Dataflow 的 Serverless 特色多是從系統角度來看最具技術挑戰性以及有別於其餘雲廠商產品的重要因素,但我想在此討論主要是其批流統一的編程模型。編程模型包括咱們在本書的大部份內容中所討論的轉換,窗口,水印,觸發器和聚合計算。固然,全部這些討論都包含了思考問題的 what、where、when、how。
DataFlow 模型首先誕生於 Flume,由於咱們但願將 MillWheel 中強大的無序數據計算能力整合到 Flume 提供的更高級別的編程模型中。這個方式可讓 Google 員工在內部使用 Flume 進行統一的批處理和流處理編程。
關於統一模型的核心關鍵思考在於,儘管在當時咱們也沒有深入意識到,批流處理模型本質上沒有區別: 僅僅是在表和流的處理上有些小變化而已。正如咱們在第 6 章中所討論到的,主要的區別僅僅是在將表上增量的變化轉換爲流,其餘一切在概念上是相同的。經過利用批處理和流處理二者大量的共性需求,能夠提供一套引擎,適配於兩套不一樣處理方式,這讓流計算系統更加易於使用。
除了利用批處理和流處理之間的系統共性以外,咱們還仔細查看了多年來咱們在 Google 中遇到的各類案例,並使用這些案例來研究統一模型下系統各個部分。咱們研究主要內容以下:
總之,這些平衡了靈活性,正確性,延遲和成本之間的關係,將 DataFlow 的模型應用於大量用戶業務案例之中。
考慮到咱們以前整本書都在討論 DataFlow 和 Beam 模型的各種問題,我在此處從新給你們講述這些概念純屬畫蛇添足。可是,若是你正在尋找稍微更具學術性的內容以及一些應用案例,我推薦你看下 2015 年發表的《DataFlow 論文..》(圖 10-27)。
DataFlow 還有很多能夠大書特書的功能特色,但在這章內容構成來看,我認爲 DataFlow 最重要的是構建了一套批流統一的大數據處理模型。DataFlow 爲咱們提供了一套全面的處理無界且無序數據集的能力,同時這套系統很好的平衡了正確性、延遲、成本之間的相互關係。
Flink(圖 10-28)在 2015 年忽然出如今大數據舞臺,而後彷佛在一晚上之間從一個無人所知的系統迅速轉變爲人人皆知的流式處理引擎。
在我看來,Flink 崛起有兩個主要緣由:
Reuven 在第 5 章中簡要介紹了 Flink 的一致性機制,這裏在重申一下,其基本思想是在系統中的 Worker 之間沿着數據傳播路徑上產生週期性 Barrier。這些 Barrier 充當了在不一樣 Worker 之間傳輸數據時的對齊機制。當一個 Worker 在其全部上游算子輸入來源(即來自其全部上游一層的 Worker)上接收到所有 Barrier 時,Worker 會將當前全部 key 對應的狀態寫入一個持久化存儲。這個過程意味着將這個 Barrier 以前的全部數據都作了持久化。
經過調整 Barrier 的生成頻率,能夠間接調整 Checkpoint 的執行頻率,從而下降時延並最終獲取更高的吞吐(其緣由是作 Checkpoint 過程當中涉及到對外進行持久化數據,所以會有必定的 IO 致使延時)。
Flink 既可以支持精確一次的語義處理保證,同時又可以提供支持事件時間的處理能力,這讓 Flink 獲取的巨大的成功。接着, Jamie Grier 發表他的題爲「《Extending the Yahoo! Streaming Benchmark》「(圖 10-30)的文章,文章中描述了 Flink 性能具體的測試數據。在那篇文章中,傑米描述了兩個使人印象深入的特色:
從那時起,許多其餘流式處理項目(特別是 Storm 和 Apex)都採用了相似算法的數據處理一致性機制。
經過快照機制,Flink 得到了端到端數據一致性。Flink 更進了一步,利用其快照的全局特性,提供了從過去的任何一點重啓整個管道的能力,這一功能稱爲 SavePoint(在 Fabian Hueske 和 Michael Winters 的帖子 [《Savepoints: Turning Back Time》(https://data-artisans.com/blog/turning-back-time-savepoints)] 中有所描述,[圖 10-31])。Savepoints 功能參考了 Kafka 應用於流式傳輸層的持久化和可重放特性,並將其擴展應用到整個底層 Pipeline。流式處理仍然遺留大量開放性問題有待優化和提高,但 Flink 的 Savepoints 功能是朝着正確方向邁出的第一步,也是整個行業很是有特色的一步。 若是您有興趣瞭解有關 Flink 快照和保存點的系統構造的更多信息,請參閱《State Management in Apache Flink》(圖 10-32),論文詳細討論了相關的實現。
除了保存點以外,Flink 社區還在不斷創新,包括將第一個實用流式 SQL API 推向大規模分佈式流處理引擎的領域,正如咱們在第 8 章中所討論的那樣。 總之,Flink 的迅速崛起成爲流計算領軍角色主要歸功於三個特色:
另外,全部這些改進都是在開源社區中完成的,咱們能夠看到爲何 Flink 一直在不斷提升整個行業的流計算處理標準。
咱們今天談到的最後一個系統是 Apache Beam(圖 10-33)。 Beam 與本章中的大多數其餘系統的不一樣之處在於,它主要是編程模型,API 設計和可移植層,而不是帶有執行引擎的完整系統棧。但這正是我想強調的重點:正如 SQL 做爲聲明性數據處理的通用語言同樣,Beam 的目標是成爲程序化數據處理的通用語言。
具體而言,Beam 由許多組件組成:
Beam 的核心願景是實現一套可移植接口層,最引人注目的功能之一是它計劃支持完整的跨語言可移植性。儘管最終目標還沒有徹底完成(但即將面市),讓 Beam 在 SDK 和引擎適配之間提供足夠高效的抽象層,從而實現 SDK 和引擎適配之間的任意切換。咱們暢想的是,用 JavaScript SDK 編寫的數據 Pipeline 能夠在用 Haskell 編寫的引擎適配層上無縫地執行,即便 Haskell 編寫的引擎適配自己沒有執行 JavaScript 代碼的能力。
做爲一個抽象層,Beam 如何定位本身和底層引擎關係,對於確保 Beam 實際爲社區帶來價值相當重要,咱們也不但願看到 Beam 引入一個沒必要要的抽象層。這裏的關鍵點是,Beam 的目標永遠不只僅是其全部底層引擎功能的交集(相似最小公分母)或超集(相似廚房水槽)。相反,它旨在爲整個社區大數據計算引擎提供最佳的想法指導。這裏面有兩個創新的角度:
Beam 自己的創新
Beam 將會提出一些 API,這些 API 須要底層 runtime 改造支持,並不是全部底層引擎最初都支持這些功能。這不要緊,隨着時間的推移,咱們但願許多底層引擎將這些功能融入將來版本中 ; 對於那些須要這些功能的業務案例來講,具有這些功能的引擎一般會被業務方選擇。
這裏舉一個 Beam 裏面關於 SplittableDoFn 的 API 例子,這個 API 能夠用來實現一個可組合的,可擴展的數據源。(具體參看 Eugene Kirpichov 在他的文章《 「Powerful and modular I/O connectors with Splittable DoFn in Apache Beam》中描述 [圖 10-34])。它設計確實頗有特色且功能強大,目前咱們尚未看到全部底層引擎對動態負載均衡等一些更具創新性功能進行普遍支持。然而,咱們預計這些功能將隨着時間的推移而持續加入底層引擎支持的範圍。
底層引擎的創新
底層引擎適配可能會引入底層引擎所獨特的功能,而 Beam 最初可能並未提供 API 支持。這不要緊,隨着時間的推移,已證實其有用性的引擎功能將在 Beam API 逐步實現。
這裏的一個例子是 Flink 中的狀態快照機制,或者咱們以前討論過的 Savepoints。 Flink 仍然是惟一一個以這種方式支持快照的公開流處理系統,可是 Beam 提出了一個圍繞快照的 API 建議,由於咱們相信數據 Pipeline 運行時優雅更新對於整個行業都相當重要。若是咱們今天推出這樣的 API,Flink 將是惟一支持它的底層引擎系統。但一樣不要緊,這裏的重點是隨着時間的推移,整個行業將開始迎頭遇上,由於這些功能的價值會逐步爲人所知。這些變化對每一個人來講都是一件好事。
經過鼓勵 Beam 自己以及引擎的創新,咱們但願推動整個行業快速演化,而不用再接受功能妥協。 經過實現跨執行引擎的可移植性承諾,咱們但願將 Beam 創建爲表達程序化數據處理流水線的通用語言,相似於當今 SQL 做爲聲明性數據處理的通用處理方式。這是一個雄心勃勃的目標,咱們並無徹底實現這個計劃,到目前爲止咱們還有很長的路要走。
咱們對數據處理技術的十五年發展進行了走馬觀花般的回顧,重點關注那些推進流式計算髮展的關鍵系統和關鍵思想。來,最後,咱們再作一次總結:
MapReduce:可擴展性和簡單性 經過在強大且可擴展的執行引擎之上提供一組簡單的數據處理抽象,MapReduce 讓咱們的數據工程師專一於他們的數據處理需求的業務邏輯,而不是去構建可以適應在一大堆普通商用服務器上的大規模分佈式處理程序。
Hadoop:開源生態系統 經過構建一個關於 MapReduce 的開源平臺,無心中建立了一個蓬勃發展的生態系統,其影響力所及的範圍遠遠超出了其最初 Hadoop 的範圍,每一年有大量的創新性想法在 Hadoop 社區蓬勃發展。
Flume:管道及優化 經過將邏輯流水線操做的高級概念與智能優化器相結合,Flume 能夠編寫簡潔且可維護的 Pipeline,其功能突破了 MapReduce 的 Map→Shuffle→Reduce 的限制,而不會犧牲性能。
Storm:弱一致性,低延遲 經過犧牲結果的正確性以減小延遲,Storm 爲大衆帶來了流計算,並開創了 Lambda 架構的時代,其中弱一致的流處理引擎與強大一致的批處理系統一塊兒運行,以實現真正的業務目標低延遲,最終一致型的結果。
Spark: 強一致性 經過利用強大一致的批處理引擎的重複運行來提供無界數據集的連續處理,Spark Streaming 證實至少對於有序數據集的狀況,能夠同時具備正確性和低延遲結果。
MillWheel:亂序處理 經過將強一致性、精確一次處理與用於推測時間的工具(如水印和定時器)相結合,MillWheel 作到了無序數據進行準確的流式處理。
Kafka: 持久化的流式存儲,流和表對偶性 經過將持久化數據日誌的概念應用於流傳輸問題,Kafka 支持了流式數據可重放功能。經過對流和表理論的概念進行推廣,闡明數據處理的概念基礎。
Cloud Dataflow:統一批流處理引擎 經過將 MillWheel 的無序流式處理與高階抽象、自動優化的 Flume 相結合,Cloud Dataflow 爲批流數據處理提供了統一模型,而且靈活地平衡正確性、計算延遲、成本的關係。
Flink:開源流處理創新者 經過快速將無序流式數據處理的強大功能帶到開源世界,並將其與分佈式快照及保存點功能等自身創新相結合,Flink 提升了開源流處理的業界標準並引領了當前流式處理創新趨勢。
Beam: 可移植性 經過提供整合行業最佳創意的強大抽象層,Beam 提供了一個可移植 API 抽象,其定位爲與 SQL 提供的聲明性通用語言等效的程序接口,同時也鼓勵在整個行業中推動創新。
能夠確定的說,我在這裏強調的這 10 個項目及其成就的說明並無超出當前大數據的歷史發展。可是,它們對我來講是一系列重要且值得注意的大數據發展里程碑,它共同描繪了過去十五年中流處理演變的時間軸。自最先的 MapReduce 系統開始,儘管沿途有許多起伏波折,但不知不覺咱們已經走出來很長一段征程。即使如此,在流式系統領域,將來咱們仍然面臨着一系列的問題亟待解決。正所謂:路漫漫其修遠兮,吾將上下而求索。