本文由 網易雲 發佈。sql
做者:周思華數據庫
本篇文章僅限內部分享,如需轉載,請聯繫網易獲取受權。緩存
本文嘗試描述Beam模型和Stream & Table理論間的關係(前者描述於數據流模型論文、the-world-beyond-batch-streaming101和the-world-beyond-batch-streaming-102,後者被MartinKleppmann和JayKreps推廣)。事實證實,Steam & Tables理論對描述Beam模型的底層基礎觀點具備啓發性意義。此外,考慮穩健的流處理概念能被集成進SQL,清楚瞭解它們間的關係是特別有益的。考慮到完整性,本文首先會對上述文章(主要是Martin和Jay的帖子)進行一個簡要的回顧。數據結構
Steam & Tables的基本思想源於數據庫。熟悉SQL的人均可能熟悉表和表的基本屬性,大體歸納爲,表包含行和列,每行都由顯式或隱式的鍵惟一標識。 回憶下大學數據庫系統課程,可能會記得大部分數據庫底層所使用到的數據結構是一個只能進行追加寫的日誌文件。事務應用於數據庫表時,這些事務首先會記錄在這個日誌中,而後事務會順序的做用於目標表來實現更新操做。在Steam & Tables概念中,上面說起的事務日誌實際上就是流。從這個角度來看,咱們如今能夠理解如何將流轉化爲表:將流中的事務順序的執行,其執行結果便成爲了表。可是如何將錶轉化爲流?本質上是逆思想:流是表的更新日誌。數據庫系統中的物化視圖功能是一個用於說明表到流轉換的不錯案例。SQL中的物化視圖,容許你指定表的查詢語句,系統將這個查詢語句視爲另外一張表。物化視圖本質上是查詢的緩存版本,當源表內容發生變化時,系統須要確保視圖對應的內容最新。顯而易見,物化視圖是基於源表的更新日誌實現,任什麼時候刻源表發生變化都會被記錄下來,而後數據庫評估物化視圖的查詢上下文是否須要更新,並將結果更新到物化視圖上,以此來保證視圖的內容爲最新。大數據
結合以上兩點,進行概括總結,咱們能夠得出一個Steam & Tables的相對理論:spa
這是一對很是強大的概念,它們能被正確的應用到了流處理中是ApacheKafka取得巨大成功的一個重要緣由,其生態系統就是圍繞這些基本原則構建而成。然而,這些理論自己沒有足夠泛化到能夠將Steam & Tables與Beam模型中全部概念相結合。爲此,咱們必須更深刻一點。日誌
若是想將Steam & Tables理論和咱們所知道的Beam模型相結合,須要把一些零散的知識結合起來,特別是:blog
在此以前,咱們首先須要對面臨的問題有個清晰的認知。除了經過上述定義來理解Steam & Tables間的關係外,獨立定義它們的含義也頗有必要。先從簡單的角度看下Steam & Tables的定義,這對咱們將來的一些分析頗有幫助,它們以下: 索引
這並非說表的內容是不變的。幾乎全部實時表的內容都會以一些方式隨時間不斷變化。但在給定時刻,表的快照提供了數據庫總體數據中的一部分數據視圖。經過這種方式,表提供了一個供數據停下來緩存的靜態場所:隨着時間推移,在這裏數據能夠被累積計算、而且能夠被觀測。接口
表捕獲的是某一特定時間點的數據視圖,而流捕獲的是數據隨時間的變化發展。JulianHyde喜歡說流像表的求導結果,表像流的積分結果,這種使用數學思惟來理解是不錯的方式。
雖然流與表密切相關,即便在許多案例中,一方來源徹底借鑑於另外一方,但必定要記住,它們之間是存在區別的。雖然區別是微妙的,但也是重要的,咱們會在下面看到。
隨着討論的深刻,讓咱們開始總結一些零散分析。首先,咱們要解決的第一個問題是關於批處理的問題。最後,咱們將發現第二個關於流與有界和無界數據的關係的問題將天然而然地從第一個答案中獲得解決。
爲使咱們分析起來更簡單,首先咱們能夠看下Stream &Tables理論如何與傳統的MapReduce任務相結合。就像它名字所表示的那樣,MapReduce由兩個關鍵的階段組成:Map階段和Reduce階段,爲了使得咱們的分析更加清晰,這裏將其拆分紅6個子階段:
1. MapRead:消費輸入數據,將數據預處理成標準的K/V結構,爲Map階段準備;
2. Map: 不斷的消費(可能並行)前面過程預處理的單個K/V對,輸出0或者多個K/V對;
3. MapWrite: Map階段輸出的具備相同key的value在這過程會被集羣聚合在一塊兒,聚合後的數據形如(K,Iterator(V)),接着持久化這些(K, Iterator(V))數據,簡單來講,MapWrite就是基本的根據key 進行聚合而後checkpoint這些結果到存儲系統;
4. ReduceRead: 消費MapWrite階段持久化的shuffle數據(K可能做爲分桶的key,從而寫入到不一樣的磁盤上),轉變成標準的(K,List(value))結構爲Reduce階段作準備;
5. Reduce: 不斷消費一個Key對應的多條value,輸出0條或者多條記錄,這些記錄仍然對應這個key;
6. ReduceWrite:將Reduce階段的結果寫入數據存儲介質。
雖然在不少資料中,上述的MapWrite、ReduceRead階段會被統一稱爲MapReduce中的Shuffle階段,可是出於咱們的目的,這兩個階段最好單獨分開看待。將MapRead和ReduceWrite分別當作是Sources與Sinks可能更好理解。除此以外,咱們如今看看它們與Stream &Tables理論又存在哪些關係?
有一點須要說明一下,因爲在map階段中,它的輸入、輸出都是表的形式,有些人可能會天然而然的認爲,map過程當中涉及到的都是隻有表而已。畢竟對於批處理任務來講,你們都知道它是以表做爲輸入,而後再輸出結果表。若是把整個批處理過程看出是執行一段SQL語句的話,可能更好理解一些。可是map過程與表之間的關係究竟是什麼呢?難道它就真的只與表有關,與流就一點關係也沒有嗎?下面讓咱們一步步深刻的進行說明?
首先,MapRead消費一張表,而後產生結果數據,這些結果數據又被下一步Map階段做爲輸入數據,想要理解的更透徹些,能夠看下Map階段的API,JAVA接口以下:
voidmap(KI key, VI value, Emit);
每消費一條input表中的k/v對,都將調用一次map方法,若是你發現這裏輸入表的記錄數據像流同樣被處理,那麼恭喜你,你是對的。稍後咱們將更進一步的去看錶是如何轉化爲流,可是如今,咱們已經瞭解到MapRead階段會迭代消費輸入表中的數據,同時使這些數據以流的形式供Map階段消費。
下一步,Map階段消費流,而後幹什麼呢?因爲map執行的是對一個元素的轉化操做,所以它不會作任何阻止數據流動的事情,經過過濾一些元素或者拆分一些元素成爲多個元素,它能夠有效改變流中的數據,可是map階段結束之後,這些元素彼此相互獨立。所以能夠說,map階段消費流同時產出流。
一旦map階段結束之後,就進入了MapWrite階段,我上面提到,MapWrite根據key聚合記錄,而後以這種數據結構持久化到存儲介質中。這裏存儲到持久化存儲其實不是嚴格必須的,也能夠存儲到其餘地方(假如上一節點流被存儲了,中間結果再失敗的時候就能夠經過從新計算上個節點獲得,相似spark的的RDD方法),最重要的是在這一步中記錄被聚合到了一塊兒,並被存儲在存儲介質上,多是內存、磁盤、其餘可以存儲的介質。這個重要的緣由是,聚合操做致使的結果是,那些先前在流中一條一條流動的數據經過key被放到同一位置,所以可以針對每一個key後的分組數據進行聚合處理,注意這裏是否是和前面提到定義流到表的轉換很像呢?隨着時間推移,更新流的聚合結果進而產生表,MapWrite以key來將流中的數據進行分組,將分組數據再寫入下一級,所以將流又轉化爲了表。
到此爲止咱們已經討論了MapReduce過程的上半部分(Map部分),來看下咱們目前爲止看到了什麼?(在圖1中)
經過三個操做完成了從表到流再到表的轉換過程,MapRead將錶轉換成流,map階段又將該流轉變成了新流,最後這個新流通過 MapWrite又轉表回到表,接下來將會發現Reduce階段的三個操做和這三個操做很相似,儘管如此在接下來對Reduce階段進行說明的過程當中,我仍然會指出一個重要的細節出來。
在瞭解了MapWrite之後,ReduceRead自己相對無趣,由於它基本上與MapRead相同,除了讀取的是list形式的數據而不是單個值,由於MapWrite存儲的數據是k/list(v)對。 可是,它仍然只是迭代計算一個表的快照,將其轉換爲流,這裏沒什麼新鮮的。
Reduce實際上只是一個Map階段的變形,接收每一個鍵的值列表而不是單個值。所以,它仍然只是將單個(複合,(K,List(V)))記錄映射到零個或多個新記錄。ReduceWrite這裏是值得注意的一個過程,咱們都知道這個過程會將流轉變成表,由於上面的Reduce過程產生流而最終的 ReduceWrite輸出倒是表。這個是如何作的?其實這個就像前面的MapWrite階段同樣,對前一個階段的輸出的流按照key進行分組,而後將結果持久化到存儲介質。假如你記得我前面提到的指定key對於reduce過程是一個可選的特徵,使用這個特徵,ReduceWrite和MapWrite基本相同,若是reduce的輸出沒有指定key,那麼數據到達下游之後會發生什麼呢?
再回想下經典sql表的執行語義將有助於理解將會發生什麼,儘管在sql表中推薦使用主鍵,可是sql表並非嚴格須要主鍵來區分每行數據的,若是表中沒有主鍵,插入到表中的每條數據都被視爲新的獨立的一行,儘管表中可能存在一條或者多條相同的數據,這裏大部分是經過爲表增長自動遞增的列做爲數據的key來實現的。在這些場景下這些key可能僅僅是一些物理塊的位置索引,不會當作邏輯標識符去處理或者暴露出去。這個隱含的key,正是ReduceWrite中處理無Key數據狀況的應對方法。 從概念上講,這仍然是按key分組的操做,可是因爲缺乏用戶提供的key,ReduceWrite認爲每條數據都是新的,每條數據都擁有一個惟一的key,而後根據它進行分組(結果是每組僅有一條數據),最後將結果流傳到下游。
如今讓咱們回顧下流/表的轉換的整個流程,能夠發現它是「表 -> 流 -> 流 -> 表 -> 流-> 流 -> 表」的序列。儘管咱們處理的是有界數據,儘管咱們使用的是傳統的批處理思想,但其實本質仍然是流和表的轉化。
圖2:從流/表的角度來看MapReduce的Map和Rdeuce
經過這些分析,除了前面提到的兩個問題外還有哪些問題呢?
Question:批處理是如何適配到Stream & Tables理論中的?
Question:流與有界和無界數據的有什麼關聯嗎?
Answer:咱們能夠經過MapReduce例子看出,不管是對於有界仍是無界的數據,流只是數據的動態形式。
經過這些分析,很容易發現Stream & Tables理論與有界數據的批處理理論差別並不大,事實上這更加支持我以前提出的批處理與流處理兩者並沒有差別的想法,有了這些分析,咱們能夠很好的總結出一個通用的Stream & Tables理論,可是要把這些東西理清楚,咱們最後要解決what/where/when/how這個四個問題,找出它們之間的聯繫。
網易有數:企業級大數據可視化分析平臺。面向業務人員的自助式敏捷分析平臺,採用PPT模式的報告製做,更加易學易用,具有強大的探索分析功能,真正幫助用戶洞察數據發現價值。可點擊這裏免費試用。
瞭解 網易雲 :
網易雲官網:https://www.163yun.com/
新用戶大禮包:https://www.163yun.com/gift
網易雲社區:https://sq.163yun.com/