開發與維運

Stream is the new file

作者 | 滕昱(戴爾科技集團 軟件開發總監)

隨著5G 網絡、容器雲、高性能存儲硬件水平的不斷提高,流處理正在擁有越來越廣泛的市場前景。

各種各樣的設備傳感器、監控攝像頭、移動終端設備等等無時無刻不在產生著大量的流式數據。針對不同的場景,流式數據也許會有各式各樣不同的特點,但是對於這些流式數據的處理,往往都有實時或者接近於實時的、無邊界連續不斷的、低延時的共性要求。而這些要求,恰恰就是流處理的基本特點。

image.png

僅僅從這些基本特點看,好像流處理早已經被實現了。不管是70年代開始興起的規則引擎,還是基於傳統的關係型數據庫的複雜海量數據處理,貌似都符合要求,甚至在編程語言裡都既有了對這些處理系統的支持。但是Stonebraker,Çetintemel和Zdonik在2005年的論文《The 8 Requirements of Real-Time Stream Processing》中指出,現有的這些系統其實還不能真正滿足流處理的要求,流處理技術還需要進一步的發展。

image.png

這也是為什麼現階段包含Flink在內的流批一體的大數據技術棧持續在不停發展的原因。IDC報告指出,未來的3~5年整個實時數據會以驚人的速度增長。那麼不管是針對實時數據的流處理,還是針對歷史數據的批處理,也都需要同步的發展來滿足時代的要求。

image.png

這些流批一體的大數據技術棧的發展,不光包含Flink等處理引擎的進化,也包括存儲領域。那麼在存儲領域,針對現代流處理,又有哪些進化和發展呢?

image.png

傳統來說,數據往往以文件的形式組織,用文件系統加以管理。

image.png

但是,文件接口抽象真的能很好的處理流式的連續數據麼?讓我們來看一看。

image.png

首先,假設我們用文件和文件系統來做一個流存儲。把傳感器、用戶日誌、用戶輸入這些數據注入一個文件中,貌似並沒有什麼問題。但是被寫入文件的數據必須被持續不斷的讀取出來。也就是說,持續不斷被寫入文件的數據,必須不停的被讀取出來用以處理,這是文件接口和針對連續數據流處理最根本的區別。

image.png

其次,當數據量變大的時候,併發是必須的。我們當然可以利用多個文件實現併發寫。但這也意味著讀端的應用程序必須追蹤多文件讀。為增加併發而帶來的多文件讀取的協調和追蹤並沒有包含在文件接口的抽象裡,所以這對讀應用程序來說,並不是透明的。

image.png

第三,如果進一步考慮動態擴展呢?動態擴展意味著在程序讀取的過程中再動態生成新的文件或者合併已有文件以適應新的併發度。在這種情況下,讀端應用程序需要自己監測在讀文件的新增和減少,這是除應用程序本身業務邏輯之外額外的工作。

image.png

第四,數據是連續無邊界的,需要一種標記來記錄當前數據的讀取位置。橫跨多個文件去設計邏輯上全局一致的位置點,進一步增加了應用程序的複雜性。

image.png

第五,IOT場景往往需要維護針對同一設備號的數據序列。如果把設備數據當作文件,把設備號當作key,那麼注入端需要key到文件的映射處理並維護在同一key命名空間下的per-key order。同時,讀取端還得做到多文件讀取的負載均衡。這些都是文件和文件系統抽象不能完成,所有的工作都推向了上層應用程序。

image.png

第六,對於流處理來說,數據的清除往往是從流數據的頭開始刪除,先寫入的先刪。文件接口抽象並不能很好的處理這點。

image.png

近些年來,業界其實是廣泛應用了一箇中間解決方案,通過messaging系統(比如Kafka)+文件系統的混合抽象方案注入。這解決了部分問題,比如說動態擴展、注入端的並行問題。但是這不是一個完整的端到端解決方案。實時流計算是走了messaging接口規避了文件接口的一些問題,但是針對歷史數據的批處理還是需要文件接口,這實際上是針對同一數據的兩種系統。

image.png

所以,對於連續的流式數據的存儲層抽象,我們需要的既不是原來的基於傳統數據庫的實現,也不是基於messaging系統的轉化,而是從頭設計一個完整的流存儲系統。

image.png

那麼,這種流存儲的抽象能給上層的計算單元帶來什麼樣的好處呢?讓我們來具體看一下。

image.png

首先,對於之前提到的messaging系統+文件系統,數據需要用stream接口進入messaging系統,但是可能以文件接口方式讀出,在接口抽象上並不一致。我們需要的流存儲抽象,不管是注入端還是讀取端,都是stream接口,給應用程序統一的抽象。

image.png

其次,流存儲抽象需要提供動態擴展功能。在應用程序看來,它只需要往一個stream裡寫入數據。至於這個stream抽象怎麼基於注入量進行動態擴展,或者在多路併發下怎麼保證per-key的order,由抽象層內部解決,對應用程序完全透明。

image.png

第三,在所有情況下,哪怕是動態擴展過程中,從流存儲抽象層讀出的數據,具有per-key的order保證。

image.png

第四,流存儲抽象能夠在邏輯上提供基於時間的全局一致的位置點,我們稱之為Stream Cut。應用程序依賴於此能夠回放到任意一個位置點,回放或重試業務邏輯。

image.png

計算引擎例如Flink能夠利用流存儲抽象提供的Stream Cut,基於流存儲系統處理的checkpointing功能,實現端到端的exactly-once保證。這在文件抽象接口上,是很難做到的。

image.png

除此之外,還有很多其他針對streaming典型場景的的好處,例如原子讀寫,低延時的tail read、事務支持、歷史數據truncation等等。

image.png

那麼,假設有了這個很好的流存儲抽象出現,它能做什麼?

我們能夠基於這層抽象,建造更簡單、更清楚的大數據的流水線。

image.png

海量的連續流式數據注入這個流水線,被保存到流存儲中。以Flink為代表的流批一體的處理單元用流存儲提供的統一接口,包括針對流處理的低延遲的tail read,以及針對批處理的高吞吐的historical read,針對同一份數據,提供支持exactly-once語義的數據處理。一種抽象一套處理,簡化流程。

image.png

當然實際中流水線會更加複雜一些。數據往往是被寫入Edge端,進行on-the-fly的實時計算處理,比如監控攝像頭拍下的圖片圖像的預處理。同時,數據也可以被髮送到數據中心的私有云或者是公有云上,作更大規模的準實時的一個計算。這樣的方式,讓大數據流水線的開發變得非常的清楚和簡潔。

image.png

Pravega(梵語:high speed)就是在流存儲抽象的需求背景下應運而生的系統,具有前面提到的流存儲抽象的所有特點。Pravega是2016年創建開源項目Apache2 License,近期已被加入CNCF。

image.png

下面我們就來看看,Pravega是怎麼提供以上提到的流存儲抽象的這些屬性的。

首先,對於近期寫入的數據,Pravega提供低延遲的tail read。同時,Pravega底層由可擴展的軟件定義存儲實現,可以支持無限歷史數據存儲。並且這些歷史數據同樣通過streaming接口讀取,以實現針對歷史數據的流處理。其次,Pravega支持動態擴展。根據前端流量的大小,Pravega能夠動態調整partition的數量以適應前端流量,對客戶端透明。再次,Pravega提供StreamCut方便客戶獲取基於時間的數據分片,用來實現數據會放處理功能等。當然,Pravega還支持以streaming接口truncate數據,從頭讀取歷史數據等等。基本上之前提到的相關特點在Pravega裡都能找到相應的功能支持。

image.png

那Pravega具體是怎麼實現的呢?

當創建一個stream的時候,和其他可擴展系統不同,用戶並不需要指定併發的個數。在Pravega內部,segment是真正的數據存儲單元。一個stream可以擁有一個或多個segment(s)。Pravega通過動態調整segment的個數實現動態擴展。

所有寫入stream的數據都被當作是一串append only的bytes最終寫入segment中。可以是一行log,可以是一張圖片,通過serializer/deserializer決定語義,沒有格式的限制,也沒有必須是小文件的限制。

image.png

當stream擁有多個segment的時候,數據會併發寫入這多個segment中。這多個segment將namespace分成同等數量的key space,寫入的數據可以通過綁定routing key,決定自己寫入哪個key space(segment)中。相同routing key的數據會被寫入同一個segment中,獲得order保證。比如,傳感器產生的連續數據都可以使用傳感器的設備號作為routing key,以保證同一傳感器產生的數據擁有相同的routing key而被寫入同一個segment,以保證讀取時的時序性。實際上,Pravega的transaction,exactly-once等特性正是基於此實現的。

image.png

講了那麼多動態擴展,下面給大家一個具體的例子看看它的實現。假設系統中創建了一個stream,開始的時候他只有兩個segment。

image.png

當注入流量翻倍的時候,Pravega能夠檢測到這點,並且將segment的個數從2個擴展成4個。這點不需要用戶的任何干預,不需要改變配置、擴展節點、起停服務等等,所有的都無縫發生在Pravega內部,對用戶透明。

image.png

同樣,當注入流量減少時,Pravega也能相應的合併segment,去除不必要的併發節省資源使用。

image.png

Pravega的這種動態擴展機制,結合container化的部署方式,讓Pravega真正實現了cloud-native的分佈式可擴展的流存儲系統。

下面是Pravega的架構圖。左邊是一個非常抽象的stream,用戶通過Event Stream Writer/Reader通過streaming接口讀寫數據。右邊可以分成兩部分,控制面板和數據面板。控制面板負責管理和維護stream和segment,比如stream的創建, segment的分配部署,以及segment的動態擴展等。數據面板以segment為單位管理數據。寫入segment的數據首先會被寫入Durable Log實現數據的持久化保護。同時數據也會緩存在Streaming Cache中,提供高性能的讀取。所有寫入的數據在積攢後會通過優化算法打包寫入底層可擴展的Long-term Storage,通過分級存儲保存歷史數據。這層Storage只做數據存儲功能,對於歷史數據的讀取依然通過Pravega的streaming接口提供。數據面板除了通過segment來管理用戶數據外,也通過Table segment管理自己的metadata數據。它同樣支持動態擴展,避免了很多系統用zookeeper存放metadata是遇到的擴展問題。

image.png

好,到此為止,我們應該瞭解到Pravega確實是符合流存儲抽象的實現。那麼隨後的一個問題是,支持了這麼多靈活的功能,實現應該很複雜吧。這樣的一個流存儲系統,運行起來到底性能會怎麼樣呢?畢竟對於實時性要求比較高的流處理來說,性能是至關重要的。

image.png

為了驗證這點,我們把Pravega 0.8部署在AWS標準服務商,用業界標準的OpenMessaging Benchmark系統,對Pravega的性能進行了測試和取樣。完整的結果在《When speeding makes sense — Fast, consistent, durable and scalable streaming data with Pravega》(https://blog.pravega.io/2020/10/01/when-speeding-makes-sense-fast-consistent-durable-and-scalable-streaming-data-with-pravega/)這篇博客上可以找到。

這裡我們截取了其中的一些對Pravega的性能進行一些介紹。

下面這張圖顯示了Pravega在1個segment和16個segment下,隨著注入量的不斷增加,Pravega的性能表現。我們可以看到,Pravega性能針對不同segment並沒有太大區別,都能夠做到低延時高吞吐。隨著注入量的增大,性能成穩定線性變化。足以說明Pravega在性能方面的亮眼穩定表現。

image.png

此外,我們還和messaging系統(Pulsar)對比了分級存儲的性能。測試中,對於同樣部署在AWS上Pravega和Pulsar,我們用OpenMessaging對兩套系統用相同的注入速度持續寫入15分鐘,以使兩套系統上有大約100GB的歷史數據。然後同時打開讀端讀取數據,考驗兩套系統對於歷史數據讀取的表現。從圖上我們可以看到,Pravega在短短幾分鐘內就能夠讀取並消化掉之前的歷史數據,追趕上前端新的寫入。而Pulsar花費80分鐘依然沒有做到。這也正是Pravega作為一個流存儲系統而不是messaging系統必須具備的優勢,對歷史數據的存儲和讀寫同樣重要。

image.png

對於Pravega引以為傲的動態擴展機制,我們也給出了相關測試。在下面的圖示中,測試stream剛開始只有1個segment。在高注入量的持續注入下,圖示可以看到stream的segment每隔大約10分鐘自動擴展一次,隨著每次擴展,系統延遲降低一次。整個過程完全自動,最終系統會針對注入的數據量,達到最佳性能平衡。完美的設計!

image.png

那是不是segment越多越好呢?我們都有類似的經驗,segment越多,資源競爭越激烈,系統會出現超負載的情況,性能反而會更糟。那Pravega是這樣的情況麼?

我們也做了和Kafka的對比圖。當segment個數從1漲到10的時候,確實,對於兩套系統來說,segment個數越多,吞吐率越高。但是顯然,10是峰值,超過以後Kafka如經驗預料的一樣,性能開始有了顯著下降。但是Pravega依舊能夠維持峰值的高性能不變。足以說明Pravega的性能在擴展時的穩定性。

image.png

由上所有的架構介紹和性能分析,我們可以看到,Pravega確實是一個合格的企業級的cloud-native分佈式可擴展流式存儲系統。

有了這樣一個系統,建造企業級的流處理系統變得相對簡單。我們就基於Pravega建造了一個可擴展的流批一體的流式搜索系統:Pravega Search。

image.png

可以把Pravega Search看作是類似於Elasticsearch或者Splunk產品類似的搜索系統。它同樣可以針對注入數據創建索引,通過索引查詢提供搜索結果。但是,Pravega Search考慮流處理的特點,支持針對流數據的continuous query。在連續數據的不斷注入時,同時給出實時的計算結果。這是Elasticsearch所沒有的。

image.png

這就是基於流存儲系統Pravega構建流處理應用的便捷和優勢。在批流一體的流水線上,Pravega stream作為數據管道,把上層一個個的計算單元耦合起來。比如圖中所示,用戶數據流入Pravega stream後,流入continuous query進行計算,計算結果數據又重新流回Pravega stream不斷套接。同時,不管是針對流處理的continuous query還是基於歷史數據的傳統批處理,數據只存儲了一份,避免了現在批流一體的大數據處理流水線上數據在多個不同集群之間重複復置存儲的問題。

image.png

綜上所述,隨著流處理的不斷髮展,流存儲系統也從早期的基於傳統數據庫,到現在的新型架構體系不斷髮展,並且依然擁有廣闊的發展前景。

在未來流存儲系統的發展藍圖裡,message系統已經不能完全滿足技術發展對於流存儲系統的所有幻想。Pravega應流存儲系統需求而生,提供純粹的流存儲抽象,旨在促進批流一體的大數據流處理系統的發展。

作為CNCF的大數據流處理生態中的一員,Pravega和其他開源流處理系統例如Flink,必將給大數據流處理領域發展帶來新的色彩,讓我們拭目以待!

image.png

活動推薦:

僅需99元即可體驗阿里雲基於 Apache Flink 構建的企業級產品-實時計算 Flink 版!點擊下方鏈接瞭解活動詳情:https://www.aliyun.com/product/bigdata/sc?utm_content=g_1000250506

社區二維碼.jpg

Leave a Reply

Your email address will not be published. Required fields are marked *