簡(jiǎn)單之美 | Apache Flink:特性、概念歇攻、組件棧固惯、架構(gòu)及原理分析
http://shiyanjun.cn/archives/1508.html
Apache Flink是一個(gè)面向分布式數(shù)據(jù)流處理和批量數(shù)據(jù)處理的開源計(jì)算平臺(tái),它能夠基于同一個(gè)Flink運(yùn)行時(shí)(Flink Runtime)缴守,提供支持流處理和批處理兩種類型應(yīng)用的功能≡岷粒現(xiàn)有的開源計(jì)算方案,會(huì)把流處理和批處理作為兩種不同的應(yīng)用類型屡穗,因?yàn)樗麄兯鼈兯峁┑腟LA是完全不相同的:流處理一般需要支持低延遲贴捡、Exactly-once保證,而批處理需要支持高吞吐鸡捐、高效處理栈暇,所以在實(shí)現(xiàn)的時(shí)候通常是分別給出兩套實(shí)現(xiàn)方法,或者通過一個(gè)獨(dú)立的開源框架來(lái)實(shí)現(xiàn)其中每一種處理方案箍镜。例如源祈,實(shí)現(xiàn)批處理的開源方案有MapReduce、Tez色迂、Crunch香缺、Spark,實(shí)現(xiàn)流處理的開源方案有Samza歇僧、Storm图张。Flink在實(shí)現(xiàn)流處理和批處理時(shí),與傳統(tǒng)的一些方案完全不同诈悍,它從另一個(gè)視角看待流處理和批處理祸轮,將二者統(tǒng)一起來(lái):Flink是完全支持流處理,也就是說(shuō)作為流處理看待時(shí)輸入數(shù)據(jù)流是無(wú)界的侥钳;批處理被作為一種特殊的流處理适袜,只是它的輸入數(shù)據(jù)流被定義為有界的∠隙幔基于同一個(gè)Flink運(yùn)行時(shí)(Flink Runtime)苦酱,分別提供了流處理和批處理API,而這兩種API也是實(shí)現(xiàn)上層面向流處理给猾、批處理類型應(yīng)用框架的基礎(chǔ)疫萤。
基本特性
關(guān)于Flink所支持的特性,我這里只是通過分類的方式簡(jiǎn)單做一下梳理敢伸,涉及到具體的一些概念及其原理會(huì)在后面的部分做詳細(xì)說(shuō)明扯饶。
流處理特性
支持高吞吐、低延遲、高性能的流處理
支持帶有事件時(shí)間的窗口(Window)操作
支持有狀態(tài)計(jì)算的Exactly-once語(yǔ)義
支持高度靈活的窗口(Window)操作帝际,支持基于time蔓同、count、session蹲诀,以及data-driven的窗口操作
支持具有Backpressure功能的持續(xù)流模型
支持基于輕量級(jí)分布式快照(Snapshot)實(shí)現(xiàn)的容錯(cuò)
一個(gè)運(yùn)行時(shí)同時(shí)支持Batch on Streaming處理和Streaming處理
Flink在JVM內(nèi)部實(shí)現(xiàn)了自己的內(nèi)存管理
支持迭代計(jì)算
支持程序自動(dòng)優(yōu)化:避免特定情況下Shuffle斑粱、排序等昂貴操作,中間結(jié)果有必要進(jìn)行緩存
API支持
對(duì)Streaming數(shù)據(jù)類應(yīng)用脯爪,提供DataStream API
對(duì)批處理類應(yīng)用则北,提供DataSet API(支持Java/Scala)
Libraries支持
支持機(jī)器學(xué)習(xí)(FlinkML)
支持圖分析(Gelly)
支持關(guān)系數(shù)據(jù)處理(Table)
支持復(fù)雜事件處理(CEP)
整合支持
支持Flink on YARN
支持HDFS
支持來(lái)自Kafka的輸入數(shù)據(jù)
支持Apache HBase
支持Hadoop程序
支持Tachyon
支持ElasticSearch
支持RabbitMQ
支持Apache Storm
支持S3
支持XtreemFS
基本概念
Stream & Transformation & Operator
用戶實(shí)現(xiàn)的Flink程序是由Stream和Transformation這兩個(gè)基本構(gòu)建塊組成,其中Stream是一個(gè)中間結(jié)果數(shù)據(jù)痕慢,而Transformation是一個(gè)操作尚揣,它對(duì)一個(gè)或多個(gè)輸入Stream進(jìn)行計(jì)算處理,輸出一個(gè)或多個(gè)結(jié)果Stream掖举。當(dāng)一個(gè)Flink程序被執(zhí)行的時(shí)候快骗,它會(huì)被映射為Streaming Dataflow。一個(gè)Streaming Dataflow是由一組Stream和Transformation Operator組成塔次,它類似于一個(gè)DAG圖方篮,在啟動(dòng)的時(shí)候從一個(gè)或多個(gè)Source Operator開始,結(jié)束于一個(gè)或多個(gè)Sink Operator励负。下面是一個(gè)由Flink程序映射為Streaming Dataflow的示意圖藕溅,如下所示:
Parallel Dataflow
在Flink中翠忠,程序天生是并行和分布式的:一個(gè)Stream可以被分成多個(gè)Stream分區(qū)(Stream Partitions)惠猿,一個(gè)Operator可以被分成多個(gè)Operator Subtask,每一個(gè)Operator Subtask是在不同的線程中獨(dú)立執(zhí)行的负间。一個(gè)Operator的并行度,等于Operator Subtask的個(gè)數(shù)姜凄,一個(gè)Stream的并行度總是等于生成它的Operator的并行度政溃。有關(guān)Parallel Dataflow的實(shí)例,如下圖所示:
One-to-one模式
比如從Source[1]到map()[1]董虱,它保持了Source的分區(qū)特性(Partitioning)和分區(qū)內(nèi)元素處理的有序性,也就是說(shuō)map()[1]的Subtask看到數(shù)據(jù)流中記錄的順序,與Source[1]中看到的記錄順序是一致的愤诱。
Redistribution模式
這種模式改變了輸入數(shù)據(jù)流的分區(qū)云头,比如從map()[1]、map()[2]到keyBy()/window()/apply()[1]淫半、keyBy()/window()/apply()[2]溃槐,上游的Subtask向下游的多個(gè)不同的Subtask發(fā)送數(shù)據(jù),改變了數(shù)據(jù)流的分區(qū)科吭,這與實(shí)際應(yīng)用所選擇的Operator有關(guān)系昏滴。另外,Source Operator對(duì)應(yīng)2個(gè)Subtask对人,所以并行度為2谣殊,而Sink Operator的Subtask只有1個(gè),故而并行度為1牺弄。
Task & Operator Chain
在Flink分布式執(zhí)行環(huán)境中姻几,會(huì)將多個(gè)Operator Subtask串起來(lái)組成一個(gè)Operator Chain,實(shí)際上就是一個(gè)執(zhí)行鏈势告,每個(gè)執(zhí)行鏈會(huì)在TaskManager上一個(gè)獨(dú)立的線程中執(zhí)行蛇捌,如下圖所示:
Time & Window
Flink支持基于時(shí)間窗口操作盒音,也支持基于數(shù)據(jù)的窗口操作,如下圖所示:
基本架構(gòu)
Flink系統(tǒng)的架構(gòu)與Spark類似,是一個(gè)基于Master-Slave風(fēng)格的架構(gòu)挖函,如下圖所示:
JobManager
JobManager是Flink系統(tǒng)的協(xié)調(diào)者芋浮,它負(fù)責(zé)接收Flink Job,調(diào)度組成Job的多個(gè)Task的執(zhí)行壳快。同時(shí)纸巷,JobManager還負(fù)責(zé)收集Job的狀態(tài)信息,并管理Flink集群中從節(jié)點(diǎn)TaskManager眶痰。JobManager所負(fù)責(zé)的各項(xiàng)管理功能瘤旨,它接收到并處理的事件主要包括:
RegisterTaskManager
在Flink集群?jiǎn)?dòng)的時(shí)候,TaskManager會(huì)向JobManager注冊(cè)竖伯,如果注冊(cè)成功存哲,則JobManager會(huì)向TaskManager回復(fù)消息AcknowledgeRegistration。
SubmitJob
Flink程序內(nèi)部通過Client向JobManager提交Flink Job七婴,其中在消息SubmitJob中以JobGraph形式描述了Job的基本信息祟偷。
CancelJob
請(qǐng)求取消一個(gè)Flink Job的執(zhí)行,CancelJob消息中包含了Job的ID打厘,如果成功則返回消息CancellationSuccess修肠,失敗則返回消息CancellationFailure。
UpdateTaskExecutionState
TaskManager會(huì)向JobManager請(qǐng)求更新ExecutionGraph中的ExecutionVertex的狀態(tài)信息户盯,更新成功則返回true嵌施。
RequestNextInputSplit
運(yùn)行在TaskManager上面的Task,請(qǐng)求獲取下一個(gè)要處理的輸入Split先舷,成功則返回NextInputSplit艰管。
JobStatusChanged
ExecutionGraph向JobManager發(fā)送該消息,用來(lái)表示Flink Job的狀態(tài)發(fā)生的變化蒋川,例如:RUNNING牲芋、CANCELING、FINISHED等捺球。
TaskManager
TaskManager也是一個(gè)Actor缸浦,它是實(shí)際負(fù)責(zé)執(zhí)行計(jì)算的Worker,在其上執(zhí)行Flink Job的一組Task氮兵。每個(gè)TaskManager負(fù)責(zé)管理其所在節(jié)點(diǎn)上的資源信息裂逐,如內(nèi)存、磁盤泣栈、網(wǎng)絡(luò)卜高,在啟動(dòng)的時(shí)候?qū)①Y源的狀態(tài)向JobManager匯報(bào)弥姻。TaskManager端可以分成兩個(gè)階段:
注冊(cè)階段
TaskManager會(huì)向JobManager注冊(cè),發(fā)送RegisterTaskManager消息掺涛,等待JobManager返回AcknowledgeRegistration庭敦,然后TaskManager就可以進(jìn)行初始化過程。
可操作階段
該階段TaskManager可以接收并處理與Task有關(guān)的消息薪缆,如SubmitTask秧廉、CancelTask、FailTask拣帽。如果TaskManager無(wú)法連接到JobManager疼电,這是TaskManager就失去了與JobManager的聯(lián)系,會(huì)自動(dòng)進(jìn)入“注冊(cè)階段”减拭,只有完成注冊(cè)才能繼續(xù)處理Task相關(guān)的消息蔽豺。
Client
當(dāng)用戶提交一個(gè)Flink程序時(shí),會(huì)首先創(chuàng)建一個(gè)Client峡谊,該Client首先會(huì)對(duì)用戶提交的Flink程序進(jìn)行預(yù)處理茫虽,并提交到Flink集群中處理,所以Client需要從用戶提交的Flink程序配置中獲取JobManager的地址既们,并建立到JobManager的連接濒析,將Flink Job提交給JobManager。Client會(huì)將用戶提交的Flink程序組裝一個(gè)JobGraph啥纸, 并且是以JobGraph的形式提交的号杏。一個(gè)JobGraph是一個(gè)Flink Dataflow,它由多個(gè)JobVertex組成的DAG斯棒。其中盾致,一個(gè)JobGraph包含了一個(gè)Flink程序的如下信息:JobID、Job名稱荣暮、配置信息庭惜、一組JobVertex等。
組件棧
Flink是一個(gè)分層架構(gòu)的系統(tǒng)穗酥,每一層所包含的組件都提供了特定的抽象护赊,用來(lái)服務(wù)于上層組件。Flink分層的組件棧如下圖所示:
Deployment層 該層主要涉及了Flink的部署模式,F(xiàn)link支持多種部署模式:本地抽高、集群(Standalone/YARN)判耕、云(GCE/EC2)。Standalone部署模式與Spark類似翘骂,這里壁熄,我們看一下Flink on YARN的部署模式帚豪,如下圖所示:
了解YARN的話,對(duì)上圖的原理非常熟悉请毛,實(shí)際Flink也實(shí)現(xiàn)了滿足在YARN集群上運(yùn)行的各個(gè)組件:Flink YARN Client負(fù)責(zé)與YARN RM通信協(xié)商資源請(qǐng)求志鞍,F(xiàn)link JobManager和Flink TaskManager分別申請(qǐng)到Container去運(yùn)行各自的進(jìn)程。通過上圖可以看到方仿,YARN AM與Flink JobManager在同一個(gè)Container中,這樣AM可以知道Flink JobManager的地址统翩,從而AM可以申請(qǐng)Container去啟動(dòng)Flink TaskManager仙蚜。待Flink成功運(yùn)行在YARN集群上,F(xiàn)link YARN Client就可以提交Flink Job到Flink JobManager厂汗,并進(jìn)行后續(xù)的映射委粉、調(diào)度和計(jì)算處理。
Runtime層
Runtime層提供了支持Flink計(jì)算的全部核心實(shí)現(xiàn)娶桦,比如:支持分布式Stream處理贾节、JobGraph到ExecutionGraph的映射、調(diào)度等等衷畦,為上層API層提供基礎(chǔ)服務(wù)栗涂。
API層
API層主要實(shí)現(xiàn)了面向無(wú)界Stream的流處理和面向Batch的批處理API,其中面向流處理對(duì)應(yīng)DataStream API祈争,面向批處理對(duì)應(yīng)DataSet API斤程。
Libraries層
該層也可以稱為Flink應(yīng)用框架層,根據(jù)API層的劃分菩混,在API層之上構(gòu)建的滿足特定應(yīng)用的實(shí)現(xiàn)計(jì)算框架忿墅,也分別對(duì)應(yīng)于面向流處理和面向批處理兩類。面向流處理支持:CEP(復(fù)雜事件處理)沮峡、基于SQL-like的操作(基于Table的關(guān)系操作)疚脐;面向批處理支持:FlinkML(機(jī)器學(xué)習(xí)庫(kù))、Gelly(圖處理)邢疙。
內(nèi)部原理
容錯(cuò)機(jī)制
Flink基于Checkpoint機(jī)制實(shí)現(xiàn)容錯(cuò)棍弄,它的原理是不斷地生成分布式Streaming數(shù)據(jù)流Snapshot。在流處理失敗時(shí)秘症,通過這些Snapshot可以恢復(fù)數(shù)據(jù)流處理照卦。理解Flink的容錯(cuò)機(jī)制,首先需要了解一下Barrier這個(gè)概念:Stream Barrier是Flink分布式Snapshotting中的核心元素乡摹,它會(huì)作為數(shù)據(jù)流的記錄被同等看待役耕,被插入到數(shù)據(jù)流中,將數(shù)據(jù)流中記錄的進(jìn)行分組聪廉,并沿著數(shù)據(jù)流的方向向前推進(jìn)。每個(gè)Barrier會(huì)攜帶一個(gè)Snapshot ID夺巩,屬于該Snapshot的記錄會(huì)被推向該Barrier的前方盲再。因?yàn)锽arrier非常輕量,所以并不會(huì)中斷數(shù)據(jù)流察绷。帶有Barrier的數(shù)據(jù)流,如下圖所示:
出現(xiàn)一個(gè)Barrier拆撼,在該Barrier之前出現(xiàn)的記錄都屬于該Barrier對(duì)應(yīng)的Snapshot,在該Barrier之后出現(xiàn)的記錄屬于下一個(gè)Snapshot
來(lái)自不同Snapshot多個(gè)Barrier可能同時(shí)出現(xiàn)在數(shù)據(jù)流中喘沿,也就是說(shuō)同一個(gè)時(shí)刻可能并發(fā)生成多個(gè)Snapshot
當(dāng)一個(gè)中間(Intermediate)Operator接收到一個(gè)Barrier后闸度,它會(huì)發(fā)送Barrier到屬于該Barrier的Snapshot的數(shù)據(jù)流中,等到Sink Operator接收到該Barrier后會(huì)向Checkpoint Coordinator確認(rèn)該Snapshot蚜印,直到所有的Sink Operator都確認(rèn)了該Snapshot莺禁,才被認(rèn)為完成了該Snapshot 這里還需要強(qiáng)調(diào)的是,Snapshot并不僅僅是對(duì)數(shù)據(jù)流做了一個(gè)狀態(tài)的Checkpoint窄赋,它也包含了一個(gè)Operator內(nèi)部所持有的狀態(tài)哟冬,這樣才能夠在保證在流處理系統(tǒng)失敗時(shí)能夠正確地恢復(fù)數(shù)據(jù)流處理。也就是說(shuō)忆绰,如果一個(gè)Operator包含任何形式的狀態(tài)浩峡,這種狀態(tài)必須是Snapshot的一部分。Operator的狀態(tài)包含兩種:一種是系統(tǒng)狀態(tài)较木,一個(gè)Operator進(jìn)行計(jì)算處理的時(shí)候需要對(duì)數(shù)據(jù)進(jìn)行緩沖红符,所以數(shù)據(jù)緩沖區(qū)的狀態(tài)是與Operator相關(guān)聯(lián)的,以窗口操作的緩沖區(qū)為例伐债,F(xiàn)link系統(tǒng)會(huì)收集或聚合記錄數(shù)據(jù)并放到緩沖區(qū)中预侯,直到該緩沖區(qū)中的數(shù)據(jù)被處理完成;另一種是用戶自定義狀態(tài)(狀態(tài)可以通過轉(zhuǎn)換函數(shù)進(jìn)行創(chuàng)建和修改)峰锁,它可以是函數(shù)中的Java對(duì)象這樣的簡(jiǎn)單變量萎馅,也可以是與函數(shù)相關(guān)的Key/Value狀態(tài)。對(duì)于具有輕微狀態(tài)的Streaming應(yīng)用虹蒋,會(huì)生成非常輕量的Snapshot而且非常頻繁糜芳,但并不會(huì)影響數(shù)據(jù)流處理性能。Streaming應(yīng)用的狀態(tài)會(huì)被存儲(chǔ)到一個(gè)可配置的存儲(chǔ)系統(tǒng)中魄衅,例如HDFS峭竣。在一個(gè)Checkpoint執(zhí)行過程中,存儲(chǔ)的狀態(tài)信息及其交互過程晃虫,如下圖所示:
Operator從一個(gè)incoming Stream接收到Snapshot Barrier n呻惕,然后暫停處理,直到其它的incoming Stream的Barrier n(否則屬于2個(gè)Snapshot的記錄就混在一起了)到達(dá)該Operator
接收到Barrier n的Stream被臨時(shí)擱置滥比,來(lái)自這些Stream的記錄不會(huì)被處理亚脆,而是被放在一個(gè)Buffer中
一旦最后一個(gè)Stream接收到Barrier n,Operator會(huì)emit所有暫存在Buffer中的記錄盲泛,然后向Checkpoint Coordinator發(fā)送Snapshot n
繼續(xù)處理來(lái)自多個(gè)Stream的記錄
基于Stream Aligning操作能夠?qū)崿F(xiàn)Exactly Once語(yǔ)義濒持,但是也會(huì)給流處理應(yīng)用帶來(lái)延遲,因?yàn)闉榱伺帕袑?duì)齊Barrier寺滚,會(huì)暫時(shí)緩存一部分Stream的記錄到Buffer中弥喉,尤其是在數(shù)據(jù)流并行度很高的場(chǎng)景下可能更加明顯,通常以最遲對(duì)齊Barrier的一個(gè)Stream為處理Buffer中緩存記錄的時(shí)刻點(diǎn)玛迄。在Flink中,提供了一個(gè)開關(guān)棚亩,選擇是否使用Stream Aligning蓖议,如果關(guān)掉則Exactly Once會(huì)變成At least once。
調(diào)度機(jī)制
在JobManager端讥蟆,會(huì)接收到Client提交的JobGraph形式的Flink Job勒虾,JobManager會(huì)將一個(gè)JobGraph轉(zhuǎn)換映射為一個(gè)ExecutionGraph,如下圖所示:
左上子圖:有2個(gè)TaskManager唐含,每個(gè)TaskManager有3個(gè)Task Slot
左下子圖:一個(gè)Flink Job浅浮,邏輯上包含了1個(gè)data source、1個(gè)MapFunction捷枯、1個(gè)ReduceFunction滚秩,對(duì)應(yīng)一個(gè)JobGraph
左下子圖:用戶提交的Flink Job對(duì)各個(gè)Operator進(jìn)行的配置——data source的并行度設(shè)置為4,MapFunction的并行度也為4淮捆,ReduceFunction的并行度為3郁油,在JobManager端對(duì)應(yīng)于ExecutionGraph
右上子圖:TaskManager 1上,有2個(gè)并行的ExecutionVertex組成的DAG圖攀痊,它們各占用一個(gè)Task Slot
右下子圖:TaskManager 2上桐腌,也有2個(gè)并行的ExecutionVertex組成的DAG圖,它們也各占用一個(gè)Task Slot
在2個(gè)TaskManager上運(yùn)行的4個(gè)Execution是并行執(zhí)行的
迭代機(jī)制
機(jī)器學(xué)習(xí)和圖計(jì)算應(yīng)用蚕苇,都會(huì)使用到迭代計(jì)算哩掺,F(xiàn)link通過在迭代Operator中定義Step函數(shù)來(lái)實(shí)現(xiàn)迭代算法,這種迭代算法包括Iterate和Delta Iterate兩種類型涩笤,在實(shí)現(xiàn)上它們反復(fù)地在當(dāng)前迭代狀態(tài)上調(diào)用Step函數(shù)嚼吞,直到滿足給定的條件才會(huì)停止迭代。下面蹬碧,對(duì)Iterate和Delta Iterate兩種類型的迭代算法原理進(jìn)行說(shuō)明:
Iterate
Iterate Operator是一種簡(jiǎn)單的迭代形式:每一輪迭代舱禽,Step函數(shù)的輸入或者是輸入的整個(gè)數(shù)據(jù)集,或者是上一輪迭代的結(jié)果恩沽,通過該輪迭代計(jì)算出下一輪計(jì)算所需要的輸入(也稱為Next Partial Solution)誊稚,滿足迭代的終止條件后,會(huì)輸出最終迭代結(jié)果,具體執(zhí)行流程如下圖所示:
Delta Iterate
Delta Iterate Operator實(shí)現(xiàn)了增量迭代启昧,它的實(shí)現(xiàn)原理如下圖所示:
Backpressure監(jiān)控
Backpressure在流式計(jì)算系統(tǒng)中會(huì)比較受到關(guān)注,因?yàn)樵谝粋€(gè)Stream上進(jìn)行處理的多個(gè)Operator之間耗美,它們處理速度和方式可能非常不同京髓,所以就存在上游Operator如果處理速度過快,下游Operator處可能機(jī)會(huì)堆積Stream記錄商架,嚴(yán)重會(huì)造成處理延遲或下游Operator負(fù)載過重而崩潰(有些系統(tǒng)可能會(huì)丟失數(shù)據(jù))堰怨。因此,對(duì)下游Operator處理速度跟不上的情況蛇摸,如果下游Operator能夠?qū)⒆约禾幚頎顟B(tài)傳播給上游Operator备图,使得上游Operator處理速度慢下來(lái)就會(huì)緩解上述問題,比如通過告警的方式通知現(xiàn)有流處理系統(tǒng)存在的問題赶袄。Flink Web界面上提供了對(duì)運(yùn)行Job的Backpressure行為的監(jiān)控揽涮,它通過使用Sampling線程對(duì)正在運(yùn)行的Task進(jìn)行堆棧跟蹤采樣來(lái)實(shí)現(xiàn),具體實(shí)現(xiàn)方式如下圖所示:
OK: 0 <= Ratio <= 0.10
LOW: 0.10 < Ratio <= 0.5
HIGH: 0.5 < Ratio <= 1
另外嵌牺,F(xiàn)link還提供了3個(gè)參數(shù)來(lái)配置Backpressure監(jiān)控行為:
參數(shù)名稱
默認(rèn)值
說(shuō)明
jobmanager.web.backpressure.refresh-interval
60000
默認(rèn)1分鐘,表示采樣統(tǒng)計(jì)結(jié)果刷新時(shí)間間隔
jobmanager.web.backpressure.num-samples
100
評(píng)估Backpressure狀態(tài)龄糊,所使用的堆棧跟蹤調(diào)用次數(shù)
jobmanager.web.backpressure.delay-between-samples
50
默認(rèn)50毫秒逆粹,表示對(duì)一個(gè)Job的每個(gè)Task依次調(diào)用的時(shí)間間隔
通過上面?zhèn)€定義的Backpressure狀態(tài),以及調(diào)整相應(yīng)的參數(shù)炫惩,可以確定當(dāng)前運(yùn)行的Job的狀態(tài)是否正常枯饿,并且保證不影響JobManager提供服務(wù)。
參考鏈接
http://flink.apache.org/
http://flink.apache.org/features.html
https://ci.apache.org/projects/flink/flink-docs-release-1.0/internals/general_arch.html
http://data-artisans.com/high-throughput-low-latency-and-exactly-once-stream-processing-with-apache-flink/
https://ci.apache.org/projects/flink/flink-docs-release-1.0/internals/stream_checkpointing.html
https://ci.apache.org/projects/flink/flink-docs-release-1.0/internals/job_scheduling.html
https://ci.apache.org/projects/flink/flink-docs-release-1.0/apis/streaming/event_time.html
https://ci.apache.org/projects/flink/flink-docs-release-1.0/setup/yarn_setup.html
https://ci.apache.org/projects/flink/flink-docs-release-1.0/setup/jobmanager_high_availability.html
https://ci.apache.org/projects/flink/flink-docs-release-1.0/apis/streaming/libs/cep.html
https://ci.apache.org/projects/flink/flink-docs-release-1.0/apis/batch/libs/gelly.html
https://ci.apache.org/projects/flink/flink-docs-release-1.0/apis/batch/libs/ml/index.html
https://ci.apache.org/projects/flink/flink-docs-release-1.0/apis/batch/libs/table.html
https://ci.apache.org/projects/flink/flink-docs-release-1.0/apis/batch/connectors.html
http://geek.csdn.net/news/detail/56272
http://samza.apache.org/