一文讀懂Apache Flink技術(shù)
本文是先介紹 Flink,再說 Flink的過去和現(xiàn)在
一、Flink介紹
Flink是一款分布式的計(jì)算引擎,它可以用來做批處理,即處理靜態(tài)的數(shù)據(jù)集、歷史的數(shù)據(jù)集;也可以用來做流處理,即實(shí)時(shí)地處理一些實(shí)時(shí)數(shù)據(jù)流,實(shí)時(shí)地產(chǎn)生數(shù)據(jù)的結(jié)果;也可以用來做一些基于事件的應(yīng)用,比如說滴滴通過Flink CEP實(shí)現(xiàn)實(shí)時(shí)監(jiān)測(cè)用戶及司機(jī)的行為流來判斷用戶或司機(jī)的行為是否正當(dāng)。
總而言之,F(xiàn)link是一個(gè)Stateful Computations Over Streams,即數(shù)據(jù)流上的有狀態(tài)的計(jì)算。這里面有兩個(gè)關(guān)鍵字,一個(gè)是Streams,F(xiàn)link認(rèn)為有界數(shù)據(jù)集是無界數(shù)據(jù)流的一種特例,所以說有界數(shù)據(jù)集也是一種數(shù)據(jù)流,事件流也是一種數(shù)據(jù)流。Everything is streams,即Flink可以用來處理任何的數(shù)據(jù),可以支持批處理、流處理、AI、MachineLearning等等。
另外一個(gè)關(guān)鍵詞是Stateful,即有狀態(tài)計(jì)算。有狀態(tài)計(jì)算是最近幾年來越來越被用戶需求的一個(gè)功能。舉例說明狀態(tài)的含義,比如說一個(gè)網(wǎng)站一天內(nèi)訪問UV數(shù),那么這個(gè)UV數(shù)便為狀態(tài)。Flink提供了內(nèi)置的對(duì)狀態(tài)的一致性的處理,即如果任務(wù)發(fā)生了Failover,其狀態(tài)不會(huì)丟失、不會(huì)被多算少算,同時(shí)提供了非常高的性能。
那Flink的受歡迎離不開它身上還有很多的標(biāo)簽,其中包括性能優(yōu)秀(尤其在流計(jì)算領(lǐng)域)、高可擴(kuò)展性、支持容錯(cuò),是一種純內(nèi)存式的一個(gè)計(jì)算引擎,做了內(nèi)存管理方面的大量優(yōu)化,另外也支持eventime的處理、支持超大狀態(tài)的Job(在阿里巴巴中作業(yè)的state大小超過TB的是非常常見的)、支持exactly-once的處理。
1.1 Flink基石
Flink之所以能這么流行,離不開它最重要的四個(gè)基石:Checkpoint、State、Time、Window。
首先是Checkpoint機(jī)制,這是Flink最重要的一個(gè)特性。Flink基于Chandy-Lamport算法實(shí)現(xiàn)了一個(gè)分布式的一致性的快照,從而提供了一致性的語義。Chandy-Lamport算法實(shí)際上在1985年的時(shí)候已經(jīng)被提出來,但并沒有被很廣泛的應(yīng)用,而Flink則把這個(gè)算法發(fā)揚(yáng)光大了。Spark最近在實(shí)現(xiàn)Continue streaming,Continue streaming的目的是為了降低它處理的延時(shí),其也需要提供這種一致性的語義,最終采用Chandy-Lamport這個(gè)算法,說明Chandy-Lamport算法在業(yè)界得到了一定的肯定。
提供了一致性的語義之后,F(xiàn)link為了讓用戶在編程時(shí)能夠更輕松、更容易地去管理狀態(tài),還提供了一套非常簡單明了的State API,包括里面的有ValueState、ListState、MapState,近期添加了BroadcastState,使用State API能夠自動(dòng)享受到這種一致性的語義。
除此之外,F(xiàn)link還實(shí)現(xiàn)了Watermark的機(jī)制,能夠支持基于事件的時(shí)間的處理,或者說基于系統(tǒng)時(shí)間的處理,能夠容忍數(shù)據(jù)的延時(shí)、容忍數(shù)據(jù)的遲到、容忍亂序的數(shù)據(jù)。
另外流計(jì)算中一般在對(duì)流數(shù)據(jù)進(jìn)行操作之前都會(huì)先進(jìn)行開窗,即基于一個(gè)什么樣的窗口上做這個(gè)計(jì)算。Flink提供了開箱即用的各種窗口,比如滑動(dòng)窗口、滾動(dòng)窗口、會(huì)話窗口以及非常靈活的自定義的窗口。
1.2 Flink API
Flink分層API主要有三層,如下圖:
最底層是ProcessFunction,它能夠提供非常靈活的功能,它能夠訪問各種各樣的State,用來注冊(cè)一些timer,利用timer回調(diào)的機(jī)制能夠?qū)崿F(xiàn)一些基于事件驅(qū)動(dòng)的一些應(yīng)用。
之上是DataStream API,最上層是SQL/Table API的一種High-level API。
1.3 Flink的用途
Flink能用來做什么?回顧一下Flink up前幾站的分享,有非常多的嘉賓分享了他們?cè)谧约汗纠锩婊贔link做的一些實(shí)踐,包括攜程、唯品會(huì)、餓了么、滴滴、頭條等等。他們的應(yīng)用場(chǎng)景包括實(shí)時(shí)的機(jī)器學(xué)習(xí),實(shí)時(shí)的統(tǒng)計(jì)分析,實(shí)時(shí)的異常監(jiān)測(cè)等等。這些實(shí)踐案例的共同點(diǎn)就是都用來做實(shí)時(shí)性的任務(wù)。
1.4 Flink Title的變化
早期Flink是這樣介紹自己的:“我是一個(gè)開源的流批統(tǒng)一的計(jì)算引擎”,當(dāng)時(shí)跟Spark有點(diǎn)類似。后來Spark改成了一長串的文字,里面有各種各樣的形容詞:“我是一個(gè)分布式的、高性能的、高可用的、高精確的流計(jì)算系統(tǒng)”。最近Spark又進(jìn)行了修改:“我是一個(gè)數(shù)據(jù)流上的有狀態(tài)的計(jì)算”。
通過觀察這個(gè)變化,可以發(fā)現(xiàn)Flink社區(qū)重心的變遷,即社區(qū)現(xiàn)在主要精力是放在打造它的流計(jì)算引擎上。先在流計(jì)算領(lǐng)域扎根,領(lǐng)先其他對(duì)手幾年,然后借助社區(qū)的力量壯大社區(qū),再借助社區(qū)的力量擴(kuò)展它的生態(tài)。
阿里巴巴Flink是這樣介紹自己的:“Flink是一個(gè)大數(shù)據(jù)量處理的統(tǒng)一的引擎”。這個(gè)“統(tǒng)一的引擎”包括流處理、批處理、AI、MachineLearning、圖計(jì)算等等。
二、Flink過去與現(xiàn)在
2.1 Flink High-Level API的歷史變遷
在Flink 1.0.0時(shí)期,Table API和CEP這兩個(gè)框架被首次加入到倉庫里面,同時(shí)社區(qū)對(duì)于SQL的需求很大。SQL和Table API非常相近,都是一種處理結(jié)構(gòu)化數(shù)據(jù)的一種High-Level語言,實(shí)現(xiàn)上可以共用很多內(nèi)容。所以在1.1.0里面,社區(qū)基于Apache Calcite對(duì)整個(gè)非Table的Module做了重大的重構(gòu),使得Table API和SQL共用了大部分的代碼,同時(shí)進(jìn)行了支持。
在Flink 1.2.0時(shí)期,在Table API和SQL上支持Tumbling Window、Sliding Window、Session Window這些窗口。
在Flink 1.3.0時(shí)期,首次引用了Dynamic Table這個(gè)概念,借助Dynamic Table,流和批之間是可以相互進(jìn)行轉(zhuǎn)換的。流可以是一張表,表也可以是一張流,這是流批統(tǒng)一的基礎(chǔ)之一。Retraction機(jī)制是Dynamic Table最重要的一個(gè)功能,基于Retraction才能夠正確地實(shí)現(xiàn)多級(jí)Application、多級(jí)Join,才能夠保證語意與結(jié)果的一個(gè)正確性。同時(shí)該版本支持了CEP算子的可控性。
在Flink 1.5.0時(shí)期,支持了Join操作,包括window Join以及非window Join,還添加了SQL CLI支持。SQL CLI提供了一個(gè)類似shell命令的對(duì)話框,可以交互式執(zhí)行查詢。
2.2 Flink API的歷史變遷
- 在Flink 1.0.0時(shí)期,加入了State API,即ValueState、ReducingState、ListState等等。State API主要方便了DataStream用戶,使其能夠更加容易地管理狀態(tài)。
- 在Flink 1.1.0時(shí)期,提供了對(duì)SessionWindow以及遲到數(shù)據(jù)處理的支持。
- 在Flink 1.2.0時(shí)期,提供了ProcessFunction,一個(gè)Low-level的API?;赑rocessFunction用戶可以比較靈活地實(shí)現(xiàn)基于事件的一些應(yīng)用。
- 在Flink 1.3.0時(shí)期,提供了Side outputs功能。一般算子的輸出只有一種輸出的類型,但是有些時(shí)候可能需要輸出另外的類型,比如把一些異常數(shù)據(jù)、遲到數(shù)據(jù)以側(cè)邊流的形式進(jìn)行輸出,并交給異常節(jié)點(diǎn)進(jìn)行下一步處理,這就是Side outputs。
- 在Flink 1.5.0時(shí)期,加入了BroadcastState。BroadcastState用來存儲(chǔ)上游被廣播過來的數(shù)據(jù),這個(gè)節(jié)點(diǎn)上的很多N個(gè)并發(fā)上存在的BroadcastState里面的數(shù)據(jù)都是一模一樣的,因?yàn)樗菑纳嫌螐V播來的?;谶@種State可以比較好地去解決不等值Join這種場(chǎng)景。比如一個(gè)Query里面寫的“SLECECT * FROM L JOIN R WHERE L.a > R.b”,也就是說我們需要把左表和右表里面所有A大于B的數(shù)據(jù)都關(guān)聯(lián)輸出出來。
在以前的實(shí)現(xiàn)中,由于沒有Join等值條件,就無法按照等值條件來做KeyBy的Shuffle,只能夠?qū)⑺械臄?shù)據(jù)全部匯集到一個(gè)節(jié)點(diǎn)上,一個(gè)單并發(fā)的節(jié)點(diǎn)上進(jìn)行處理,而這個(gè)單并發(fā)的節(jié)點(diǎn)就會(huì)成為整個(gè)Job的瓶頸。
而有了BroadcastState以后就可以做一些優(yōu)化:因?yàn)樽蟊頂?shù)據(jù)量比較大,右表數(shù)據(jù)量比較小,所以選擇把右表進(jìn)行廣播,把左表按照它某一個(gè)進(jìn)行均勻分布的key,做keyby shuffle,shuffle到下游的N個(gè)Join的節(jié)點(diǎn),Join的節(jié)點(diǎn)里面會(huì)存兩份State,左邊state和右邊state,左邊state用來存左邊數(shù)據(jù)流的state,是一個(gè)keyedState,因?yàn)樗前此骋粋€(gè)key做keyby分發(fā)下來的。右邊State是一個(gè)BroadcastState,所有的Join節(jié)點(diǎn)里面的BroadcastState里面存的數(shù)據(jù)都是一模一樣的,因?yàn)榫鶠閺纳嫌螐V播而來。
所有keyedState進(jìn)行并發(fā)處理,之后將keyedState集合進(jìn)行合并便等于左邊數(shù)據(jù)流的全集處理結(jié)果。于是便實(shí)現(xiàn)了這個(gè)Join節(jié)點(diǎn)的可擴(kuò)充,通過增加join節(jié)點(diǎn)的并發(fā),可以比較好地提升Job處理能力。除了不等值Join場(chǎng)景,BroadcastState還可以比較有效地解決像CAP上的動(dòng)態(tài)規(guī)則。
在Flink 1.6.0時(shí)期,提供了State TTL參數(shù)、DataStream Interval Join功能。State TTL實(shí)現(xiàn)了在申請(qǐng)某個(gè)State時(shí)候可以在指定一個(gè)TTL參數(shù),指定該state過了多久之后需要被系統(tǒng)自動(dòng)清除。在這個(gè)版本之前,如果用戶想要實(shí)現(xiàn)這種狀態(tài)清理操作需要使用ProcessFunction注冊(cè)一個(gè)Timer,然后利用Timer的回調(diào)手動(dòng)把這個(gè)State清除。從該版本開始,F(xiàn)link框架可以基于TTL原生地解決這件事情。DataStream Interval Join功能即含有區(qū)間間隔的Join,比如說左流Join右流前后幾分鐘之內(nèi)的數(shù)據(jù),這種叫做Interval Join。
2.3 Flink Checkpoint & Recovery的歷史變遷
Checkpoint機(jī)制在Flink很早期的時(shí)候就已經(jīng)支持,是Flink一個(gè)很核心的功能,F(xiàn)link社區(qū)也一直致力于努力把Checkpoint效率提升,以及換成FailOver之后它的Recallable效率的提升。
在Flink 1.0.0時(shí)期,提供了RocksDB的支持,這個(gè)版本之前所有的狀態(tài)都只能存在進(jìn)程的內(nèi)存里面,這個(gè)內(nèi)存總有存不下的一天,如果存不下則會(huì)發(fā)生OOM。如果想要存更多數(shù)據(jù)、更大量State就要用到RocksDB。RocksDB是一款基于文件的嵌入式數(shù)據(jù)庫,它會(huì)把數(shù)據(jù)存到磁盤,但是同時(shí)它又提供高效讀寫能力。所以使用RocksDB不會(huì)發(fā)生OOM這種事情。在Flink1.1.0里面,提供了純異步化的RocksDB的snapshot。以前版本在做RocksDB的snapshot時(shí)它會(huì)同步阻塞主數(shù)據(jù)流的處理,很影響吞吐量,即每當(dāng)checkpoint時(shí)主數(shù)據(jù)流就會(huì)卡住。純異步化處理之后不會(huì)卡住數(shù)據(jù)流,于是吞吐量也得到了提升。
在Flink 1.2.0時(shí)期,引入了Rescalable keys和operate state的概念,它支持了一個(gè)Key State的可擴(kuò)充以及operator state的可擴(kuò)充。
在Flink 1.3.0時(shí)期,引入了增量的checkpoint這個(gè)比較重要的功能。只有基于增量的checkpoint才能更好地支持含有超大State的Job。在阿里內(nèi)部,這種上TB的State是非常常見。如果每一次都把全量上TB的State都刷到遠(yuǎn)程的HDFS上那么這個(gè)效率是很低下的。而增量checkpoint只是把checkpoint間隔新增的那些狀態(tài)發(fā)到遠(yuǎn)程做存儲(chǔ),每一次checkpoint發(fā)的數(shù)據(jù)就少了很多,效率得到提高。在這個(gè)版本里面還引入了一個(gè)細(xì)粒度的recovery,細(xì)粒度的recovery在做恢復(fù)的時(shí)候,有時(shí)不需要對(duì)整個(gè)Job做恢復(fù),可能只需要恢復(fù)這個(gè)Job中的某一個(gè)子圖,這樣便能夠提高恢復(fù)效率。
在Flink 1.5.0時(shí)期,引入了Task local 的State的recovery。因?yàn)榛赾heckpoint機(jī)制,會(huì)把State持久化地存儲(chǔ)到某一個(gè)遠(yuǎn)程存儲(chǔ),比如HDFS,當(dāng)發(fā)生Failover的時(shí)候需要重新把這個(gè)數(shù)據(jù)從遠(yuǎn)程HDFS再download下來,如果這個(gè)狀態(tài)特別大那么該download操作的過程就會(huì)很漫長,導(dǎo)致Failover恢復(fù)所花的時(shí)間會(huì)很長。Task local state recovery提供的機(jī)制是當(dāng)Job發(fā)生Failover之后,能夠保證該Job狀態(tài)在本地不會(huì)丟失,進(jìn)行恢復(fù)時(shí)只需在本地直接恢復(fù),不需從遠(yuǎn)程HDFS重新把狀態(tài)download下來,于是就提升了Failover recovery的效率。
2.4 Flink Runtime的歷史變遷
Runtime的變遷歷史是非常重要的。
在Flink 1.2.0時(shí)期,提供了Async I/O功能。如果任務(wù)內(nèi)部需要頻繁地跟外部存儲(chǔ)做查詢?cè)L問,比如說查詢一個(gè)HBase表,在該版本之前每次查詢的操作都是阻塞的,會(huì)頻繁地被I/O的請(qǐng)求卡住。當(dāng)加入異步I/O之后就可以同時(shí)地發(fā)起N個(gè)異步查詢的請(qǐng)求,這樣便提升了整個(gè)job的吞吐量,同時(shí)Async I/O又能夠保證該job的Async語義。
在Flink 1.3.0時(shí)期,引入了HistoryServer的模塊。HistoryServer主要功能是當(dāng)job結(jié)束以后,它會(huì)把job的狀態(tài)以及信息都進(jìn)行歸檔,方便后續(xù)開發(fā)人員做一些深入排查。
在Flink 1.4.0時(shí)期,提供了端到端的exactly once的語義保證,F(xiàn)link中所謂exactly once一般是指Flink引擎本身的exactly once。如果要做到從輸入到處理再到輸出,整個(gè)端到端整體的exactly once的話,它需要輸出組件具備commit功能。在kafka老版本中不存在commit功能,從最近的1.1開始有了這個(gè)功能,于是Flink很快便實(shí)現(xiàn)了端到端exactly once。
在Flink 1.5.0時(shí)期,F(xiàn)link首次對(duì)外正式地提到新的部署模型和處理模型。新的模型開發(fā)工作已經(jīng)持續(xù)了很久,在阿里巴巴內(nèi)部這個(gè)新的處理模型也已經(jīng)運(yùn)行了有兩年以上,該模型的實(shí)現(xiàn)對(duì)Flink內(nèi)部代碼改動(dòng)量特別大,可以說是自Flink項(xiàng)目建立以來,Runtime改動(dòng)最大的一個(gè)改進(jìn)。簡而言之,它的一個(gè)特性就是它可以使得在使用YARN、Mesos這種調(diào)度系統(tǒng)時(shí),可以更加更好地動(dòng)態(tài)分配資源、動(dòng)態(tài)釋放資源、提高資源利用性,還有提供更好的jobs之間的隔離。最后是在這個(gè)版本中,F(xiàn)link對(duì)其網(wǎng)絡(luò)站進(jìn)行了一個(gè)基本重構(gòu)。
2.5 Flink 網(wǎng)絡(luò)棧重構(gòu)
在流計(jì)算中有兩個(gè)用來衡量性能的指標(biāo):延遲和吞吐。
一般來講如果想要更高吞吐就要犧牲一些延遲,如果想要更低的延遲就要犧牲一定的吞吐。但是網(wǎng)絡(luò)棧的重構(gòu)卻實(shí)現(xiàn)了延遲和吞吐的同時(shí)提升,這主要得益于它兩方面的工作:第一個(gè)是基于信用的流控,另一個(gè)是基于事件的I/O。一個(gè)用來提高它的吞吐,另一個(gè)用來降低它的延遲。
在介紹流控之前需要先介紹一下現(xiàn)有的網(wǎng)絡(luò)棧。Flink中TaskManager就是用來管理各個(gè)task的角色,它是以進(jìn)程為單位;task用來執(zhí)行用戶代碼,以線程為單位。當(dāng)tasks之間有數(shù)據(jù)傳輸?shù)慕换サ臅r(shí)候就要建立網(wǎng)絡(luò)的連接,如果2秒之間都建立一個(gè)TCP連接的話,那么這個(gè)TCP連接會(huì)被嚴(yán)重浪費(fèi),所以Flink在兩個(gè)TaskManager之間建立一個(gè)TCP連接,即兩個(gè)進(jìn)程之間只存在一個(gè)連接。各個(gè)task之間以TCP channel的方式來共享TCP的連接,這樣整個(gè)job中就不會(huì)有太多的TCP連接。
2.6 Flink 反壓
反壓的意思是當(dāng)某一個(gè)task的處理性能跟不上輸入速率的時(shí)候,其輸入端的Buffer就會(huì)被填滿,當(dāng)輸入端Buffer被填滿的時(shí)候就會(huì)導(dǎo)致TCP的讀取被暫停。TCP的讀取被暫停之后,就會(huì)導(dǎo)致上游輸出端的Buffer池越積越多,因?yàn)橄掠未藭r(shí)已經(jīng)不再進(jìn)行消費(fèi)。
當(dāng)上游輸出端的Buffer池也堆滿的時(shí)候, TCP通道就會(huì)被關(guān)閉,其內(nèi)部所有的TCP channel也會(huì)被關(guān)閉。從而上游task就會(huì)逐級(jí)的向上游進(jìn)行反壓,這是整體的反壓流程,所以說Flink以前的反壓機(jī)制是比較原生態(tài)、比較粗暴的,因?yàn)槠淇刂屏Χ群艽?,整個(gè)TCP中一旦某一個(gè)Task性能跟不上,就會(huì)把整個(gè)TCP連接關(guān)掉。如下圖所示:
右下角的task雖然處理跟不上了,但上面的task仍然可以繼續(xù)進(jìn)行處理。左邊這些上游數(shù)據(jù)可以繼續(xù)發(fā)給右上角的task進(jìn)行處理。但是由于現(xiàn)在整個(gè)的TCP連接都被關(guān)閉,導(dǎo)致右上角task同樣收不到數(shù)據(jù),整體吞吐量實(shí)際上是下降的趨勢(shì)。為了優(yōu)化這個(gè)功能就需要做到更加細(xì)密度的流控,目前是關(guān)閉整個(gè)TCP連接,優(yōu)化措施就是需要對(duì)TCP channel進(jìn)行控制,當(dāng)某個(gè)task處理不過來時(shí)只需要該Task對(duì)應(yīng)的TCP channel,其它TCP channel不受影響。優(yōu)化實(shí)現(xiàn)方式就是基于信用的流控。
基于信用的流控的核心思想就是基于信用額度的消費(fèi)。比如銀行做貸款,為了防止壞賬太多,它會(huì)對(duì)每一個(gè)人評(píng)估其信用額度,當(dāng)發(fā)放貸款時(shí)貸款不會(huì)超過這個(gè)人能承受的額度。基于這種方式,它能夠一方面不會(huì)產(chǎn)生太多壞賬,另一方面可以充分地把銀行的資金利用起來。基于信用的流控就是基于這種思想,F(xiàn)link中所謂的信用額度,就是指這個(gè)下游消費(fèi)端的可用的Buffer數(shù)。如下圖:
該圖左邊是指發(fā)送端,有四個(gè)輸出的隊(duì)列,每個(gè)隊(duì)列里面的方塊代表輸出Buffer,即準(zhǔn)備丟給下游處理的Buffer。右邊是消費(fèi)端,消費(fèi)端也有四個(gè)隊(duì)列,這四個(gè)隊(duì)列里面也有一些Buffer塊,這些Buffer塊是空閑的Buffer,準(zhǔn)備用來接收上游發(fā)給自己的數(shù)據(jù)。
上面提到基于數(shù)據(jù)的流控中所謂的信用就是指這個(gè)消費(fèi)端它可用的Buffer數(shù),代表當(dāng)前還能夠消費(fèi)多少數(shù)據(jù),消費(fèi)端首先會(huì)向上游反饋當(dāng)前的信用是多少, producer端只會(huì)向信用額度大于0的下游進(jìn)行發(fā)送,對(duì)于信用額度如果為0的就不再發(fā)送數(shù)據(jù)。這樣整個(gè)網(wǎng)絡(luò)的利用率便得到了很大的提升,不會(huì)發(fā)生某些Buffer被長時(shí)間的停留在網(wǎng)絡(luò)的鏈路上的情況。
基于信用的流控主要有以下兩方面的優(yōu)化提升:
- 一個(gè)是當(dāng)某一個(gè)task發(fā)生反壓處理跟不上的時(shí)候,不會(huì)發(fā)生所有的task都卡住,這種做法使吞吐量得到了很大的提升,在阿里內(nèi)部用雙11大屏作業(yè)進(jìn)行測(cè)試,這種新的流控算法會(huì)得到20%的提升;
- 另一個(gè)是基于事件的I/O,F(xiàn)link在網(wǎng)絡(luò)端寫數(shù)據(jù)時(shí)會(huì)先往一個(gè)Buffer塊里面寫數(shù)據(jù),這個(gè)Buffer塊是一個(gè)32K的長度的單位,即32K的大小,當(dāng)這個(gè)Buffer塊被填滿的時(shí)候就會(huì)輸出到網(wǎng)絡(luò)里面,或者如果數(shù)據(jù)流比較慢,沒辦法很快填滿的話,那么會(huì)等待一個(gè)超時(shí),默認(rèn)一個(gè)100毫秒,即如果100毫秒內(nèi)還沒被填滿那么這個(gè)Buffer也會(huì)被輸出到網(wǎng)絡(luò)里面。此時(shí)若是在以前版本中Flink延遲可能是在100毫秒以內(nèi),最差的情況下是到100毫秒,因?yàn)樾枰?00毫秒等這個(gè)Buffer發(fā)出去。
如果要得到更低的延時(shí),現(xiàn)在的做法就會(huì)將這個(gè)Buffer直接加入到輸出的隊(duì)列,但是還是保持繼續(xù)往這個(gè)Buffer塊里面寫數(shù)據(jù),當(dāng)網(wǎng)絡(luò)里面有容量時(shí)這個(gè)Buffer塊便會(huì)立刻被發(fā)出去,如果網(wǎng)絡(luò)現(xiàn)在也比較繁忙,那就繼續(xù)填充這個(gè)Buffer,這樣吞吐也會(huì)比較好一點(diǎn)?;谶@種算法,F(xiàn)link的延時(shí)幾乎是完美的,可以看到它的曲線基本上是低于10毫秒的,這也充分利用了網(wǎng)絡(luò)的容量,幾乎對(duì)吞吐沒有影響。