此文已由做者嶽猛受權網易雲社區發佈。
html
歡迎訪問網易雲社區,瞭解更多網易技術產品運營經驗。java
基因而spark core的spark streaming架構。算法
Spark Streaming是將流式計算分解成一系列短小的批處理做業。這裏的批處理引擎是Spark,也就是把Spark Streaming的輸入數據按照batch size(如1秒)分紅一段一段的數據(Discretized Stream),每一段數據都轉換成Spark中的RDD(Resilient Distributed Dataset),而後將Spark Streaming中對DStream的Transformation操做變爲針對Spark中對RDD的Transformation操做,將RDD經 過操做變成中間結果保存在內存中。整個流式計算根據業務的需求能夠對中間的結果進行疊加,或者存儲到外部設備。數據庫
簡而言之,Spark Streaming把實時輸入數據流以時間片Δt (如1秒)爲單位切分紅塊,Spark Streaming會把每塊數據做爲一個RDD,並使用RDD操做處理每一小塊數據。每一個塊都會生成一個Spark Job處理,而後分批次提交job到集羣中去運行,運行每一個job的過程和真正的spark 任務沒有任何區別。apache
負責job的調度編程
JobScheduler是SparkStreaming 全部Job調度的中心, JobScheduler的啓動會致使ReceiverTracker和JobGenerator的啓動。ReceiverTracker的啓動致使運行在Executor端的Receiver啓動而且接收數據,ReceiverTracker會記錄Receiver接收到的數據meta信息。JobGenerator的啓動致使每隔BatchDuration,就調用DStreamGraph生成RDD Graph,並生成Job。JobScheduler中的線程池來提交封裝的JobSet對象(時間值,Job,數據源的meta)。Job中封裝了業務邏輯,致使最後一個RDD的action被觸發,被DAGScheduler真正調度在Spark集羣上執行該Job。安全
負責Job的生成服務器
經過定時器每隔一段時間根據Dstream的依賴關係生一個一個DAG圖。網絡
負責數據的接收,管理和分配架構
ReceiverTracker在啓動Receiver的時候他有ReceiverSupervisor,其實現是ReceiverSupervisorImpl, ReceiverSupervisor自己啓動的時候會啓動Receiver,Receiver不斷的接收數據,經過BlockGenerator將數據轉換成Block。定時器會不斷的把Block數據經過BlockManager或者WAL進行存儲,數據存儲以後ReceiverSupervisorImpl會把存儲後的數據的元數據Metadate彙報給ReceiverTracker,實際上是彙報給ReceiverTracker中的RPC實體ReceiverTrackerEndpoint,主要。
上圖爲spark on yarn 的cluster模式,Spark on Yarn啓動後,由Spark AppMaster中的driver(在AM的裏面會啓動driver,主要是StreamingContext對象)把Receiver做爲一個Task提交給某一個Spark Executor;Receive啓動後輸入數據,生成數據塊,而後通知Spark AppMaster;Spark AppMaster會根據數據塊生成相應的Job,並把Job的Task提交給空閒Spark Executor 執行。圖中藍色的粗箭頭顯示被處理的數據流,輸入數據流能夠是磁盤、網絡和HDFS等,輸出能夠是HDFS,數據庫等。對比Flink和spark streaming的cluster模式能夠發現,都是AM裏面的組件(Flink是JM,spark streaming是Driver)承載了task的分配和調度,其餘container承載了任務的執行(Flink是TM,spark streaming是Executor),不一樣的是spark streaming每一個批次都要與driver進行通訊來進行從新調度,這樣延遲性遠低於Flink。
圖2.1 Spark Streaming程序轉換爲DStream Graph
圖2.2 DStream Graph轉換爲RDD的Graph
Spark Core處理的每一步都是基於RDD的,RDD之間有依賴關係。下圖中的RDD的DAG顯示的是有3個Action,會觸發3個job,RDD自下向上依 賴,RDD產生job就會具體的執行。從DSteam Graph中能夠看到,DStream的邏輯與RDD基本一致,它就是在RDD的基礎上加上了時間的依賴。RDD的DAG又能夠叫空間維度,也就是說整個 Spark Streaming多了一個時間維度,也能夠成爲時空維度,使用Spark Streaming編寫的程序與編寫Spark程序很是類似,在Spark程序中,主要經過操做RDD(Resilient Distributed Datasets彈性分佈式數據集)提供的接口,如map、reduce、filter等,實現數據的批處理。而在Spark Streaming中,則經過操做DStream(表示數據流的RDD序列)提供的接口,這些接口和RDD提供的接口相似。Spark Streaming把程序中對DStream的操做轉換爲DStream Graph,圖2.1中,對於每一個時間片,DStream Graph都會產生一個RDD Graph;針對每一個輸出操做(如print、foreach等),Spark Streaming都會建立一個Spark action;對於每一個Spark action,Spark Streaming都會產生一個相應的Spark job,並交給JobScheduler。JobScheduler中維護着一個Jobs隊列, Spark job存儲在這個隊列中,JobScheduler把Spark job提交給Spark Scheduler,Spark Scheduler負責調度Task到相應的Spark Executor上執行,最後造成spark的job。
圖2.3時間維度生成RDD的DAG
Y軸就是對RDD的操做,RDD的依賴關係構成了整個job的邏輯,而X軸就是時間。隨着時間的流逝,固定的時間間隔(Batch Interval)就會生成一個job實例,進而在集羣中運行。
基於spark 1.5的spark streaming源代碼解讀,基本架構是沒怎麼變化的。
支持從多種數據源獲取數據,包括Kafk、Flume、Twitter、ZeroMQ、Kinesis 以及TCP sockets,從數據源獲取數據以後,可使用諸如map、reduce、join和window等高級函數進行復雜算法的處理。最後還能夠將處理結果 存儲到文件系統,數據庫和現場儀表盤。在「One Stack rule them all」的基礎上,還可使用Spark的其餘子框架,如集羣學習、圖計算等,對流數據進行處理。
Spark目前在EC2上已可以線性擴展到100個節點(每一個節點4Core),能夠以數秒的延遲處理6GB/s的數據量(60M records/s),其吞吐量也比流行的Storm高2~5倍,圖4是Berkeley利用WordCount和Grep兩個用例所作的測試,在 Grep這個測試中,Spark Streaming中的每一個節點的吞吐量是670k records/s,而Storm是115k records/s。
Spark Streaming將流式計算分解成多個Spark Job,對於每一段數據的處理都會通過Spark DAG圖分解,以及Spark的任務集的調度過程,其最小的Batch Size的選取在0.5~2秒鐘之間(Storm目前最小的延遲是100ms左右),因此Spark Streaming可以知足除對實時性要求很是高(如高頻實時交易)以外的全部流式準實時計算場景。
更加穩定的exactly-once語義支持。
Spark Streaming 從v1.5開始引入反壓機制(back-pressure),經過動態控制數據接收速率來適配集羣數據處理能力.
簡單來講,反壓機制須要調節系統接受數據速率或處理數據速率,然而系統處理數據的速率是無法簡單的調節。所以,只能估計當前系統處理數據的速率,調節系統接受數據的速率來與之相匹配。
嚴格來講,Flink無需進行反壓,由於系統接收數據的速率和處理數據的速率是天然匹配的。系統接收數據的前提是接收數據的Task必須有空閒可用的Buffer,該數據被繼續處理的前提是下游Task也有空閒可用的Buffer。所以,不存在系統接受了過多的數據,致使超過了系統處理的能力。
由此看出,Spark的micro-batch模型致使了它須要單獨引入反壓機制。
反壓一般產生於這樣的場景:短時負載高峯致使系統接收數據的速率遠高於它處理數據的速率。
可是,系統可以承受多高的負載是系統數據處理能力決定的,反壓機制並非提升系統處理數據的能力,而是系統所面臨負載高於承受能力時如何調節系統接收數據的速率。
Driver和executor採用預寫日誌(WAL)方式去保存狀態,同時結合RDD自己的血統的容錯機制。
Spark 2.0中引入告終構化數據流,統一了SQL和Streaming的API,採用DataFrame做爲統一入口,可以像編寫普通Batch程序或者直接像操做SQL同樣操做Streaming,易於編程。
除了能夠讀取HDFS, Flume, Kafka, Twitter andZeroMQ數據源之外,咱們本身也能夠定義數據源,支持運行在Yarn,Standalone及EC2上,可以經過Zookeeper,HDFS保證高可用性,處理結果能夠直接寫到HDFS
依賴java環境,只要應用可以加載到spark相關的jar包便可。
Storm集羣採用主從架構方式,主節點是Nimbus,從節點是Supervisor,有關調度相關的信息存儲到ZooKeeper集羣中。架構以下:
Storm集羣的Master節點,負責分發用戶代碼,指派給具體的Supervisor節點上的Worker節點,去運行Topology對應的組件(Spout/Bolt)的Task。
Storm集羣的從節點,負責管理運行在Supervisor節點上的每個Worker進程的啓動和終止。經過Storm的配置文件中的supervisor.slots.ports配置項,能夠指定在一個Supervisor上最大容許多少個Slot,每一個Slot經過端口號來惟一標識,一個端口號對應一個Worker進程(若是該Worker進程被啓動)。
用來協調Nimbus和Supervisor,若是Supervisor因故障出現問題而沒法運行Topology,Nimbus會第一時間感知到,並從新分配Topology到其它可用的Supervisor上運行。
運行流程
1)戶端提交拓撲到nimbus。
2) Nimbus針對該拓撲創建本地的目錄根據topology的配置計算task,分配task,在zookeeper上創建assignments節點存儲task和supervisor機器節點中woker的對應關係;
在zookeeper上建立taskbeats節點來監控task的心跳;啓動topology。
3) Supervisor去zookeeper上獲取分配的tasks,啓動多個woker進行,每一個woker生成task,一個task一個線程;根據topology信息初始化創建task之間的鏈接;Task和Task之間是經過zeroMQ管理的;後整個拓撲運行起來。
在YARN上開發一個應用程序,一般只須要開發兩個組件,分別是客戶端和ApplicationMaster,其中客戶端主要做用是提交應用程序到YARN上,並和YARN和ApplicationMaster進行交互,完成用戶發送的一些指令;而ApplicationMaster則負責向YARN申請資源,並與NodeManager通訊,啓動任務。
不修改任何Storm源代碼便可將其運行在YARN之上,最簡單的實現方法是將Storm的各個服務組件(包括Nimbus和Supervisor)做爲單獨的任務運行在YARN上,而Zookeeper做爲一個公共的服務運行在YARN集羣以外的幾個節點上。
1)經過YARN-Storm Client將Storm Application提交到YARN的RM上;
2)RM爲YARN-Storm ApplicationMaster申請資源,並將其運行在一個節點上(Nimbus);
3)YARN-Storm ApplicationMaster 在本身內部啓動Nimbus和UI服務;
4)YARN-Storm ApplicationMaster 根據用戶配置向RM申請資源,並在申請到的Container中啓動Supervisor服務;
5)與向普通Storm集羣提交Topology同樣,用戶直接與運行在Nimbus交互,提交Topology。
相似於MapReduce下降了並行批處理複雜性,Storm下降了進行實時處理的複雜性。
一個服務框架,支持熱部署,即時上線或下線App.
你能夠在Storm之上使用各類編程語言。默認支持Clojure、Java、Ruby和Python。要增長對其餘語言的支持,只需實現一個簡單的Storm通訊協議便可。
Storm會管理工做進程和節點的故障。
計算是在多個線程、進程和服務器之間並行進行的。
Storm保證每一個消息至少能獲得一次完整處理。任務失敗時,它會負責從消息源重試消息。
系統的設計保證了消息能獲得快速的處理,使用ZeroMQ做爲其底層消息隊列。
Storm有一個「本地模式」,能夠在處理過程當中徹底模擬Storm集羣。這讓你能夠快速進行開發和單元測試。
依賴於Zookeeper進行任務狀態的維護,必須首先部署Zookeeper。
Apache |
Flink |
SparkStreaming |
Storm |
架構 |
架構介於spark和storm之間,主從結構與spark streaming類似,DataFlow Grpah與Storm類似,數據流能夠被表示爲一個有向圖。 每一個頂點是一個用戶定義的運算,每向邊表示數據的流動。 Native |
架構依賴spark,主從模式,每一個Batch處理都依賴主(driver),能夠理解爲時間維度上的spark DAG。
Micro-Batch |
主從模式,且依賴ZK,處理過程當中對主的依賴不大。
Native |
容錯 |
基於Chandy-Lamport distributed snapshots checkpoint機制 Medium |
WAL及RDD 血統機制
High |
Records ACK
Medium |
處理模型與延遲 |
單條事件處理 亞秒級低延遲 |
一個事件窗口內的全部事件。 秒級高延遲 |
每次傳入的一個事件 亞秒級低延遲 |
吞吐量 |
High |
High |
Low |
數據處理保證 |
exactly once
High |
exactly once(實現採用Chandy-Lamport 算法,即marker-checkpoint )
High |
at least once(實現採用record-level acknowledgments),Trident能夠支持storm 提供exactly once語義。 Medium |
高級API |
Flink 棧中提供了提供了不少具備高級 API 和知足不一樣場景的類庫:機器學習、圖分析、關係式數據處理 High |
可以很容易的對接Spark生態棧裏面的組件,同時可以對接主流的消息傳輸組件及存儲系統。
|
應用須要按照特定的storm定義的規則編寫。
Low |
易用性 |
支持SQL Steaming,Batch和STREAMING採用統一編程框架
High |
支持SQL Steaming Batch和STREAMING採用統一編程框架。 High |
不支持SQL Steaming
Low |
成熟性 |
新興項目,處於發展階段。 Low |
已經發展一段時間 Medium |
相對較早的流系統,比較穩定。 High |
社區活躍度 |
212 contributor,活躍度呈上升趨勢。 Medium |
937 contirbutor
High |
216 contributors,活躍度比較穩定。 Medium |
部署性 |
部署相對簡單,只依賴JRE環境 Low |
部署相對簡單,只依賴JRE環境 Low |
依賴JRE環境和Zookeeper High |
若是對延遲要求不高的狀況下,建議使用Spark Streaming,豐富的高級API,使用簡單,自然對接Spark生態棧中的其餘組件,吞吐量大,部署簡單,UI界面也作的更加智能,社區活躍度較高,有問題響應速度也是比較快的,比較適合作流式的ETL,並且Spark的發展勢頭也是有目共睹的,相信將來性能和功能將會更加完善。
若是對延遲性要求比較高的話,建議能夠嘗試下Flink,Flink是目前發展比較火的一個流系統,採用原生的流處理系統,保證了低延遲性,在API和容錯上也是作的比較完善,使用起來相對來講也是比較簡單的,部署容易,並且發展勢頭也愈來愈好,相信後面社區問題的響應速度應該也是比較快的。
我的對Flink是比較看好的,由於原生的流處理理念,在保證了低延遲的前提下,性能仍是比較好的,且愈來愈易用,社區也在不斷髮展。
更多網易技術、產品、運營經驗分享請點擊。
相關文章:
【推薦】 關於Runtime.getRuntime().exec()產生阻塞的2個陷阱