2021-02-18 分類: 網(wǎng)站建設(shè)
導(dǎo)讀:本文整理自 Flink 創(chuàng)始公司 dataArtisans(現(xiàn)在為Ververica) 聯(lián)合創(chuàng)始人兼 CTO Stephan Ewen 在 Flink Forward China 2018 上的演講《Stream Processing takes on Everything》。這個(gè)演講主題看似比較激進(jìn):流處理解決所有問題。很多人對于 Flink 可能還停留在最初的認(rèn)知,覺得 Flink 是一個(gè)流處理引擎,實(shí)際上 Flink 可以做很多其他的工作,比如批處理、應(yīng)用程序。在這個(gè)演講中,Stephan 首先會(huì)簡單說明他對 Flink 功能的觀點(diǎn),然后深入介紹一個(gè)特定領(lǐng)域的應(yīng)用和事件處理場景。這個(gè)場景乍看起來不是一個(gè)流處理的使用場景,但是在 Stephan 看來,它實(shí)際上就是一個(gè)很有趣的流處理使用場景。
注意,文末有福利~
上圖對為什么流處理可以處理一切作出詮釋,將數(shù)據(jù)看做流是一個(gè)自然而又十分強(qiáng)大的想法。大部分?jǐn)?shù)據(jù)的產(chǎn)生過程都是隨時(shí)間生成的流,比如一個(gè) Petabyte 的數(shù)據(jù)不會(huì)憑空產(chǎn)生。這些數(shù)據(jù)通常都是一些事件的積累,比如支付、將商品放入購物車,網(wǎng)頁瀏覽,傳感器采樣輸出,
基于數(shù)據(jù)是流的想法,我們對數(shù)據(jù)處理可以有相應(yīng)的理解。比如將過去的歷史數(shù)據(jù)看做是一個(gè)截止到某一時(shí)刻的有限的流,或是將一個(gè)實(shí)時(shí)處理應(yīng)用看成是從某一個(gè)時(shí)刻開始處理未來到達(dá)的數(shù)據(jù)??赡茉谖磥砟硞€(gè)時(shí)刻它會(huì)停止,那么它就變成了處理從開始時(shí)刻到停止時(shí)刻的有限數(shù)據(jù)的批處理。當(dāng)然,它也有可能一直運(yùn)行下去,不斷處理新到達(dá)的數(shù)據(jù)。這個(gè)對數(shù)據(jù)的重要理解方式非常強(qiáng)大,基于這一理解,F(xiàn)link 可以支持整個(gè)數(shù)據(jù)處理范疇內(nèi)的所有場景。
最廣為人知的 Flink 使用場景是流分析、連續(xù)處理(或者說漸進(jìn)式處理),這些場景中 Flink 實(shí)時(shí)或者近實(shí)時(shí)的處理數(shù)據(jù),或者采集之前提到的歷史數(shù)據(jù)并且連續(xù)的對這些事件進(jìn)行計(jì)算。曉偉在之前的演講中提到一個(gè)非常好的例子來說明怎么樣通過對 Flink 進(jìn)行一些優(yōu)化,進(jìn)而可以針對有限數(shù)據(jù)集做一些特別的處理,這使得 Flink 能夠很好的支持批處理的場景,從性能上來說能夠與先進(jìn)的批處理引擎相媲美。而在這根軸的另一頭,是我今天的演講將要說明的場景 – 事件驅(qū)動(dòng)的應(yīng)用。這類應(yīng)用普遍存在于任何服務(wù)或者微服務(wù)的架構(gòu)中。這類應(yīng)用接收各類事件(可能是 RPC 調(diào)用、HTTP 請求),并且對這些事件作出一些響應(yīng),比如把商品放進(jìn)購物車,或者加入社交網(wǎng)絡(luò)中的某個(gè)群組。
在我進(jìn)一步展開今天的演講之前,我想先對社區(qū)在 Flink 的傳統(tǒng)領(lǐng)域(實(shí)時(shí)分析、連續(xù)處理)近期所做的工作做一個(gè)介紹。Flink 1.7 在 2018 年 11 月 30 日已經(jīng)發(fā)布。在 Flink 1.7 中為典型的流處理場景加入了一些非常有趣的功能。比如我個(gè)人非常感興趣的在流式 SQL 中帶時(shí)間版本的 Join。一個(gè)基本想法是有兩個(gè)不同的流,其中一個(gè)流被定義為隨時(shí)間變化的參照表,另一個(gè)是與參照表進(jìn)行 Join 的事件流。比如事件流是一個(gè)訂單流,參照表是不斷被更新的匯率,而每個(gè)訂單需要使用最新的匯率來進(jìn)行換算,并將換算的結(jié)果輸出到結(jié)果表。這個(gè)例子在標(biāo)準(zhǔn)的 SQL 當(dāng)中實(shí)際上并不容易表達(dá),但在我們對 Streaming SQL 做了一點(diǎn)小的擴(kuò)展以后,這個(gè)邏輯表達(dá)變得非常簡單,我們發(fā)現(xiàn)這樣的表達(dá)有非常多的應(yīng)用場景。
另一個(gè)在流處理領(lǐng)域十分強(qiáng)大的新功能是將復(fù)雜事件處理(CEP)和 SQL 相結(jié)合。CEP 應(yīng)用觀察事件模式。比如某個(gè) CEP 應(yīng)用觀察股市,當(dāng)有兩個(gè)上漲后緊跟一個(gè)下跌時(shí),這個(gè)應(yīng)用可能做些交易。再比如一個(gè)觀察溫度計(jì)的應(yīng)用,當(dāng)它發(fā)現(xiàn)有溫度計(jì)在兩個(gè)超過 90 攝氏度的讀數(shù)之后的兩分鐘里沒有任何操作,可能會(huì)進(jìn)行一些操作。與 SQL 的結(jié)合使這類邏輯的表達(dá)也變得非常簡單。
第三個(gè) Flink 1.7 中做了很多工作的功能是 Schema 升級(jí)。這個(gè)功能和基于流的應(yīng)用緊密相關(guān)。就像你可以對數(shù)據(jù)庫進(jìn)行數(shù)據(jù) Schema 升級(jí)一樣,你可以修改 Flink 表中列的類型或者重新寫一個(gè)列,
另外我想簡單介紹的是流處理技術(shù)不僅僅是簡單對數(shù)據(jù)進(jìn)行計(jì)算,這還包括了很多與外部系統(tǒng)進(jìn)行事務(wù)交互。流處理引擎需要在采用不同協(xié)議的系統(tǒng)之間以事務(wù)的方式移動(dòng)數(shù)據(jù),并保證計(jì)算過程和數(shù)據(jù)的一致性。這一部分功能也是在 Flink 1.7 中得到了增強(qiáng)。
以上我對 Flink 1.7 的新功能向大家做了簡單總結(jié)。下面讓我們來看看今天我演講的主要部分,也就是利用 Flink 來搭建應(yīng)用和服務(wù)。我將說明為什么流處理是一個(gè)搭建應(yīng)用和服務(wù)或者微服務(wù)的有趣技術(shù)。
我將從左邊這個(gè)高度簡化的圖說起,我們一會(huì)兒將聊一些其中的細(xì)節(jié)。首先我們來看一個(gè)理解應(yīng)用簡單的視角。如左圖所示,一個(gè)應(yīng)用可以是一個(gè) Container,一個(gè) Spring 應(yīng)用,或者 Java 應(yīng)用、Ruby 應(yīng)用,等等。這個(gè)應(yīng)用從諸如 RPC,HTTP 等渠道接收請求,然后依據(jù)請求進(jìn)行數(shù)據(jù)庫變更。這個(gè)應(yīng)用也可能調(diào)用另一個(gè)微服務(wù)并進(jìn)行下一步的處理。我們可以非常自然的想到進(jìn)入到應(yīng)用的這些請求可以看做是個(gè)事件組成的序列,所以我們可以把它們看做是事件流。可能這些事件被緩存在消息隊(duì)列中,而應(yīng)用會(huì)從消息隊(duì)列中消費(fèi)這些事件進(jìn)行處理,當(dāng)應(yīng)用需要響應(yīng)一個(gè)請求時(shí),它將結(jié)果輸出到另一個(gè)消息隊(duì)列,而請求發(fā)送方可以從這個(gè)消息隊(duì)列中消費(fèi)得到所發(fā)送請求的響應(yīng)。在這張圖中我們已經(jīng)可以看到一些有趣的不同。
第一個(gè)不同是在這張圖中應(yīng)用和數(shù)據(jù)庫不再是分開的兩個(gè)實(shí)體,而是被一個(gè)有狀態(tài)的流處理應(yīng)用所代替。所以在流處理應(yīng)用的架構(gòu)中,不再有應(yīng)用和數(shù)據(jù)庫的連接了,它們被放到了一起。這個(gè)做法有利有弊,但其中有些好處是非常重要的。首先是性能上的好處是明顯的,因?yàn)閼?yīng)用不再需要和數(shù)據(jù)庫進(jìn)行交互,處理可以基于內(nèi)存中的變量進(jìn)行。其次這種做法有很好并且很簡單的一致性。
這張圖被簡化了很多,實(shí)際上我們通常會(huì)有很多個(gè)應(yīng)用,而不是一個(gè)被隔離的應(yīng)用,很多情況下你的應(yīng)用會(huì)更符合這張圖。系統(tǒng)中有個(gè)接收請求的接口,然后請求被發(fā)送到第一個(gè)應(yīng)用,可能會(huì)再被發(fā)到另一個(gè)應(yīng)用,然后得到相應(yīng)。在圖中有些應(yīng)用會(huì)消費(fèi)中間結(jié)果的流。這張圖已經(jīng)展示了為什么流處理是更適合比較復(fù)雜的微服務(wù)場景的技術(shù)。因?yàn)楹芏鄷r(shí)候系統(tǒng)中不會(huì)有一個(gè)直接接收用戶請求并直接響應(yīng)的服務(wù),通常來說一個(gè)微服務(wù)需要跟其他微服務(wù)通信。這正如在流處理的架構(gòu)中不同應(yīng)用在創(chuàng)建輸出流,同時(shí)基于衍生出的流再創(chuàng)建并輸出新的流。
到目前為止,我們看到的內(nèi)容多少還比較直觀。而對基于流處理技術(shù)的微服務(wù)架構(gòu)而言,人們最常問的一個(gè)問題是如何保證事務(wù)性?如果系統(tǒng)中使用的是數(shù)據(jù)庫,通常來說都會(huì)有非常成熟復(fù)雜的數(shù)據(jù)校驗(yàn)和事務(wù)模型。這也是數(shù)據(jù)庫在過去許多年中十分成功的原因。開始一個(gè)事務(wù),對數(shù)據(jù)做一些操作,提交或者撤銷一個(gè)事務(wù)。這個(gè)機(jī)制使得數(shù)據(jù)完整性得到了保證(一致性,持久性等等)。
那么在流處理中我們怎么做到同樣的事情呢?作為一個(gè)優(yōu)秀的流處理引擎,F(xiàn)link 支持了恰好一次語義,保證了每個(gè)事件只會(huì)被處理一遍。但是這依然對某些操作有限制,這也成為了使用流處理應(yīng)用的一個(gè)障礙。我們通過一個(gè)非常簡單流處理應(yīng)用例子來看我們可以做一些什么擴(kuò)展來解決這個(gè)問題。我們會(huì)看到,解決辦法其實(shí)出奇的簡單。
讓我們以這個(gè)教科書式的事務(wù)為例子來看一下事務(wù)性應(yīng)用的過程。這個(gè)系統(tǒng)維護(hù)了賬戶和其中存款余額的信息。這樣的信息可能是銀行或者在線支付系統(tǒng)的場景中用到的。假設(shè)我們想要處理類似下面的事務(wù):如果賬戶 A 中的余額大于 100,那么從賬戶 A 中轉(zhuǎn)賬 50 元到賬戶 B。這是個(gè)非常簡單的兩個(gè)賬戶之間進(jìn)行轉(zhuǎn)賬的例子。
數(shù)據(jù)庫對于這樣的事務(wù)已經(jīng)有了一個(gè)核心的范式,也就是原子性,一致性,隔離性和持久性(ACID)。這是能夠讓用戶放心使用事務(wù)的幾個(gè)基本保證。有了他們,用戶不用擔(dān)心錢在轉(zhuǎn)賬過程中會(huì)丟失或者其他問題。讓我們用這個(gè)例子來放到流處理應(yīng)用中,來讓流處理應(yīng)用也能提供和數(shù)據(jù)相同的 ACID 支持:
原子性要求一個(gè)轉(zhuǎn)賬要不就完全完成,也就是說轉(zhuǎn)賬金額從一個(gè)賬戶減少,并增加到另一個(gè)賬戶,要不就兩個(gè)賬戶的余額都沒有變化。而不會(huì)只有一個(gè)賬戶余額改變。否則的話錢就會(huì)憑空減少或者憑空增加。
一致性和隔離性是說如果有很多用戶同時(shí)想要進(jìn)行轉(zhuǎn)賬,那么這些轉(zhuǎn)賬行為之間應(yīng)該互不干擾,每個(gè)轉(zhuǎn)賬行為應(yīng)該被獨(dú)立的完成,并且完成后每個(gè)賬戶的余額應(yīng)該是正確的。也就是說如果兩個(gè)用戶同時(shí)操作同一個(gè)賬戶,系統(tǒng)不應(yīng)該出錯(cuò)。
持久性指的是如果一個(gè)操作已經(jīng)完成,那么這個(gè)操作的結(jié)果會(huì)被妥善的保存而不會(huì)丟失。
我們假設(shè)持久性已經(jīng)被滿足。一個(gè)流處理器有狀態(tài),這個(gè)狀態(tài)會(huì)被 checkpoint,所以流處理器的狀態(tài)是可恢復(fù)的。也就是說只要我們完成了一個(gè)修改,并且這個(gè)修改被 checkpoint 了,那么這個(gè)修改就是持久化的。
讓我們來看看另外三個(gè)例子。設(shè)想一下,如果我們用流處理應(yīng)用來實(shí)現(xiàn)這樣一個(gè)轉(zhuǎn)賬系統(tǒng)會(huì)發(fā)生什么。我們先把問題簡化一些,假設(shè)轉(zhuǎn)賬不需要有條件,僅僅是將 50 元從賬戶 A 轉(zhuǎn)到賬戶,也就是說賬戶 A 的余額減少 50 元而賬戶 B 的余額增加 50 元。我們的系統(tǒng)是一個(gè)分布式的并行系統(tǒng),而不是一個(gè)單機(jī)系統(tǒng)。簡單起見我們假設(shè)系統(tǒng)中只有兩臺(tái)機(jī)器,這兩臺(tái)機(jī)器可以是不同的物理機(jī)或者是在 YARN 或者 Kubernetes 上不同的容器??傊鼈兪莾蓚€(gè)不同的流處理器實(shí)例,數(shù)據(jù)分布在這兩個(gè)流處理器上。我們假設(shè)賬戶 A 的數(shù)據(jù)由其中一臺(tái)機(jī)器維護(hù),而賬戶 B 的數(shù)據(jù)有另一臺(tái)機(jī)器維護(hù)。
現(xiàn)在我們要做個(gè)轉(zhuǎn)賬,將 50 元從賬戶 A 轉(zhuǎn)移到賬戶 B,我們把這個(gè)請求放進(jìn)隊(duì)列中,然后這個(gè)轉(zhuǎn)賬請求被分解為對賬戶 A 和 B 分別進(jìn)行操作,并且根據(jù)鍵將這兩個(gè)操作路由到維護(hù)賬戶 A 和維護(hù)賬戶 B 的這兩臺(tái)機(jī)器上,這兩臺(tái)機(jī)器分別根據(jù)要求對賬戶 A 和賬戶 B 的余額進(jìn)行改動(dòng)。這并不是事務(wù)操作,而只是兩個(gè)獨(dú)立無意義的改動(dòng)。一旦我們將轉(zhuǎn)賬的請求改的稍微復(fù)雜一些就會(huì)發(fā)現(xiàn)問題。
下面我們假設(shè)轉(zhuǎn)賬是有條件的,我們只想在賬戶 A 的余額足夠的情況下才進(jìn)行轉(zhuǎn)賬,這樣就已經(jīng)有些不太對了。如果我們還是像之前那樣操作,將這個(gè)轉(zhuǎn)賬請求分別發(fā)送給維護(hù)賬戶 A 和 B 的兩臺(tái)機(jī)器,如果 A 沒有足夠的余額,那么 A 的余額不會(huì)發(fā)生變化,而 B 的余額可能已經(jīng)被改動(dòng)了。我們就違反了一致性的要求。
我們看到我們需要首先以某種方式統(tǒng)一做出是否需要更改余額的決定,如果這個(gè)統(tǒng)一的決定中余額需要被修改,我們再進(jìn)行修改余額的操作。所以我們先給維護(hù) A 的余額的機(jī)器發(fā)送一個(gè)請求,讓它查看 A 的余額。我們也可以對 B 做同樣的事情,但是這個(gè)例子里面我們不關(guān)心 B 的余額。然后我們把所有這樣的條件檢查的請求匯總起來去檢驗(yàn)條件是否滿足。因?yàn)?Flink 這樣的流處理器支持迭代,如果滿足轉(zhuǎn)賬條件,我們可以把這個(gè)余額改動(dòng)的操作放進(jìn)迭代的反饋流當(dāng)中來告訴對應(yīng)的節(jié)點(diǎn)來進(jìn)行余額修改。反之如果條件不滿足,那么余額改動(dòng)的操作將不會(huì)被放進(jìn)反饋流。這個(gè)例子里面,通過這種方式我們可以正確的進(jìn)行轉(zhuǎn)賬操作。從某種角度上來說我們實(shí)現(xiàn)了原子性,基于一個(gè)條件我們可以進(jìn)行全部的余額修改,或者不進(jìn)行任何余額修改。這部分依然還是比較直觀的,更大的困難是在于如何做到并發(fā)請求的隔離性。
假設(shè)我們的系統(tǒng)沒有變,但是系統(tǒng)中有多個(gè)并發(fā)的請求。我們在之前的演講中已經(jīng)知道,這樣的并發(fā)可能達(dá)到每秒鐘幾十億條。如圖,我們的系統(tǒng)可能從兩個(gè)流中同時(shí)接受請求。如果這兩個(gè)請求同時(shí)到達(dá),我們像之前那樣將每個(gè)請求拆分成多個(gè)請求,首先檢查余額條件,然后進(jìn)行余額操作。然而我們發(fā)現(xiàn)這會(huì)帶來問題。管理賬戶 A 的機(jī)器會(huì)首先檢查 A 的余額是否大于 50,然后又會(huì)檢查 A 的余額是否大于 100,因?yàn)閮蓚€(gè)條件都滿足,所以兩筆轉(zhuǎn)賬操作都會(huì)進(jìn)行,但實(shí)際上賬戶 A 上的余額可能無法同時(shí)完成兩筆轉(zhuǎn)賬,而只能完成 50 元或者 100 元的轉(zhuǎn)賬中的一筆。這里我們需要進(jìn)一步思考怎么樣來處理并發(fā)的請求,我們不能只是簡單地并發(fā)處理請求,這會(huì)違反事務(wù)的保證。從某種角度來說,這是整個(gè)數(shù)據(jù)庫事務(wù)的核心。數(shù)據(jù)庫的專家們花了一些時(shí)間提供了不同解決方案,有的方案比較簡單,有的則很復(fù)雜。但所有的方案都不是那么容易,尤其是在分布式系統(tǒng)當(dāng)中。
在流處理中怎么解決這個(gè)問題呢?直覺上講,如果我們能夠讓所有的事務(wù)都按照順序依次發(fā)生,那么問題就解決了,這也被成為可序列化的特性。但是我們當(dāng)然不希望所有的請求都被依次順序處理,這與我們使用分布式系統(tǒng)的初衷相違背。所以我們需要保證這些請求最后的產(chǎn)生的影響看起來是按照順序發(fā)生的,也就是一個(gè)請求產(chǎn)生的影響是基于前一個(gè)請求產(chǎn)生影響的基礎(chǔ)之上的。換句話說也就是一個(gè)事務(wù)的修改需要在前一個(gè)事務(wù)的所有修改都完成后才能進(jìn)行。這種希望一件事在另一件事之后發(fā)生的要求看起來很熟悉,這似乎是我們以前在流處理中曾經(jīng)遇到過的問題。是的,這聽上去像是事件時(shí)間。用高度簡化的方式來解釋,如果所有的請求都在不同的事件時(shí)間產(chǎn)生,即使由于種種原因他們到達(dá)處理器的時(shí)間是亂序的,流處理器依然會(huì)根據(jù)他們的事件時(shí)間來對他們進(jìn)行處理。流處理器會(huì)使得所有的事件的影響看上去都是按順序發(fā)生的。按事件時(shí)間處理是 Flink 已經(jīng)支持的功能。
那么詳細(xì)說來,我們到底怎么解決這個(gè)一致性問題呢?假設(shè)我們有并行的請求輸入并行的事務(wù)請求,這些請求讀取某些表中的記錄,然后修改某些表中的記錄。我們首先需要做的是把這些事務(wù)請求根據(jù)事件時(shí)間順序擺放。這些請求的事務(wù)時(shí)間不能夠相同,但是他們之間的時(shí)間也需要足夠接近,這是因?yàn)樵谑录r(shí)間的處理過程中會(huì)引入一定的延遲,我們需要保證所處理的事件時(shí)間在向前推進(jìn)。因此第一步是定義事務(wù)執(zhí)行的順序,也就是說需要有一個(gè)聰明的算法來為每個(gè)事務(wù)制定事件時(shí)間。
在圖上,假設(shè)這三個(gè)事務(wù)的事件時(shí)間分別是 T+2, T 和 T+1。那么第二個(gè)事務(wù)的影響需要在第一和第三個(gè)事務(wù)之前。不同的事務(wù)所做的修改是不同的,每個(gè)事務(wù)都會(huì)產(chǎn)生不同的操作請求來修改狀態(tài)。我們現(xiàn)在需要將對訪問每個(gè)行和狀態(tài)的事件進(jìn)行排序,保證他們的訪問是符合事件時(shí)間順序的。這也意味著那些相互之間沒有關(guān)系的事務(wù)之間自然也沒有了任何影響。比如這里的第三個(gè)事務(wù)請求,它與前兩個(gè)事務(wù)之間沒有訪問共同的狀態(tài),所以它的事件時(shí)間排序與前兩個(gè)事務(wù)也相互獨(dú)立。而當(dāng)前兩個(gè)事務(wù)之間的操作的到達(dá)順序與事件時(shí)間不符時(shí),F(xiàn)link 則會(huì)依據(jù)它們的事件時(shí)間進(jìn)行排序后再處理。
必須承認(rèn),這樣說還是進(jìn)行了一些簡化,我們還需要做一些事情來保證高效執(zhí)行,但是總體原則上來說,這就是全部的設(shè)計(jì)。除此之外我們并不需要更多其他東西。
為了實(shí)現(xiàn)這個(gè)設(shè)計(jì),我們引入了一種聰明的分布式事件時(shí)間分配機(jī)制。這里的事件時(shí)間是邏輯時(shí)間,它并不需要有什么現(xiàn)實(shí)意義,比如它不需要是真實(shí)的時(shí)鐘。使用 Flink 的亂序處理能力,并且使用 Flink 迭代計(jì)算的功能來進(jìn)行某些前提條件的檢查。這些就是我們構(gòu)建一個(gè)支持事務(wù)的流處理器的要素。
我們實(shí)際上已經(jīng)完成了這個(gè)工作,稱之為流式賬簿(Streaming Ledger),這是個(gè)在 Apache Flink 上很小的庫。它基于流處理器做到了滿足 ACID 的多鍵事務(wù)性操作。我相信這是個(gè)非常有趣的進(jìn)化。流處理器一開始基本上沒有任何保障,然后類似 Storm 的系統(tǒng)增加了至少一次的保證。但顯然至少一次依然不夠好。然后我們看到了恰好一次的語義,這是一個(gè)大的進(jìn)步,但這只是對于單行操作的恰好一次語義,這與鍵值庫很類似。而支持多行一次或者多行事務(wù)操作將流處理器提升到了一個(gè)可以解決傳統(tǒng)意義上關(guān)系型數(shù)據(jù)庫所應(yīng)用場景的階段。
Streaming Ledger 的實(shí)現(xiàn)方式是允許用戶定義一些表和對這些表進(jìn)行修改的函數(shù)。
Streaming Ledger 會(huì)運(yùn)行這些函數(shù)和表,所有的這些一起編譯成一個(gè) Apache Flink 的有向無環(huán)圖(DAG)。Streaming Ledger 會(huì)注入所有事務(wù)時(shí)間分配的邏輯,以此來保證所有事務(wù)的一致性。
搭建這樣一個(gè)庫并不難,難的是讓它高性能的運(yùn)行。讓我們來看看它的性能。這些性能測試是幾個(gè)月之前的,我們并沒有做什么特別的優(yōu)化,我們只是想看看一些最簡單的方法能夠有什么樣的性能表現(xiàn)。而實(shí)際性能表現(xiàn)看起來相當(dāng)不錯(cuò)。如果你看這些性能條形成的階梯跨度,隨著流處理器數(shù)量的增長,性能的增長相當(dāng)線性。
在事務(wù)設(shè)計(jì)中,沒有任何協(xié)同或者鎖參與其中。這只是流處理,將事件流推入系統(tǒng),緩存一小段時(shí)間來做一些亂序處理,然后做一些本地狀態(tài)更新。在這個(gè)方案中,沒有什么特別代價(jià)高昂的操作。在圖中性能增長似乎超過了線性,我想這主要是因?yàn)?JAVA 的 JVM 當(dāng)中 GC 的工作原因?qū)е碌?。?32 個(gè)節(jié)點(diǎn)的情況下我們每秒可以處理大約兩百萬個(gè)事務(wù)。為了與數(shù)據(jù)庫性能測試進(jìn)行對比,通常當(dāng)你看數(shù)據(jù)庫的性能測試時(shí),你會(huì)看到類似讀寫操作比的說明,比如 10% 的更新操作。而我們的測試使用的是 100% 的更新操作,而每個(gè)寫操作至少更新在不同分區(qū)上的 4 行數(shù)據(jù),我們的表的大小大約是兩億行。即便沒有任何優(yōu)化,這個(gè)方案的性能也非常不錯(cuò)。
另一個(gè)在事務(wù)性能中有趣的問題是當(dāng)更新的操作對象是一個(gè)比較小的集合時(shí)的性能。如果事務(wù)之間沒有沖突,并發(fā)的事務(wù)處理是一個(gè)容易的事情。如果所有的事務(wù)都獨(dú)立進(jìn)行而互不干擾,那這個(gè)不是什么難題,任何系統(tǒng)應(yīng)該都能很好的解決這樣的問題。
當(dāng)所有的事務(wù)都開始操作同一些行時(shí),事情開始變得更有趣了,你需要隔離不同的修改來保證一致性。所以我們開始比較一個(gè)只讀的程序、一個(gè)又讀又寫但是沒有寫沖突的程序和一個(gè)又讀又寫并有中等程度寫沖突的程序這三者之間的性能。你可以看到性能表現(xiàn)相當(dāng)穩(wěn)定。這就像是一個(gè)樂觀的并發(fā)沖突控制,表現(xiàn)很不錯(cuò)。那如果我們真的想要針對這類系統(tǒng)的阿喀琉斯之踵進(jìn)行考驗(yàn),也就是反復(fù)的更新同一個(gè)小集合中的鍵。
在傳統(tǒng)數(shù)據(jù)庫中,這種情況下可能會(huì)出現(xiàn)反復(fù)重試,反復(fù)失敗再重試,這是一種我們總想避免的糟糕情況。是的,我們的確需要付出性能代價(jià),這很自然,因?yàn)槿绻愕谋碇杏袔仔袛?shù)據(jù)每個(gè)人都想更新,那么你的系統(tǒng)就失去了并發(fā)性,這本身就是個(gè)問題。但是這種情況下,系統(tǒng)并沒崩潰,它仍然在穩(wěn)定的處理請求,雖然失去了一些并發(fā)性,但是請求依然能夠被處理。這是因?yàn)槲覀儧]有沖突重試的機(jī)制,你可以認(rèn)為我們有一個(gè)基于亂序處理天然的沖突避免的機(jī)制,這是一種非常穩(wěn)定和強(qiáng)大的技術(shù)。
我們還嘗試了在跨地域分布的情況下的性能表現(xiàn)。比如我們在美國、巴西,歐洲,日本和澳大利亞各設(shè)置了一個(gè) Flink 集群。也就是說我們有個(gè)全球分布的系統(tǒng)。如果你在使用一個(gè)關(guān)系型數(shù)據(jù)庫,那么你會(huì)付出相當(dāng)高昂的性能代價(jià),因?yàn)橥ㄐ诺难舆t變得相當(dāng)高??绱笾薜男畔⒔换ケ仍谕粋€(gè)數(shù)據(jù)中心甚至同一個(gè)機(jī)架上的信息交互要產(chǎn)生大得多的延遲。
但是有趣的是,流處理的方式對延遲并不是十分敏感,延遲對性能有所影響,但是相比其它很多方案,延遲對流處理的影響要小得多。所以,在這樣的全球分布式環(huán)境中執(zhí)行分布式程序,的確會(huì)有更差的性能,部分原因也是因?yàn)榭绱笾薜耐ㄐ艓挷蝗缃y(tǒng)一數(shù)據(jù)中心里的帶寬,但是性能表現(xiàn)依然不差。
實(shí)際上,你可以拿它當(dāng)做一個(gè)跨地域的數(shù)據(jù)庫,同時(shí)仍然能夠在一個(gè)大概 10 個(gè)節(jié)點(diǎn)的集群上獲得每秒幾十萬條事務(wù)的處理能力。在這個(gè)測試中我們只用了 10 個(gè)節(jié)點(diǎn),每個(gè)大洲兩個(gè)節(jié)點(diǎn)。所以 10 個(gè)節(jié)點(diǎn)可以帶來全球分布的每秒 20 萬事務(wù)的處理能力。我認(rèn)為這是很有趣的結(jié)果,這是因?yàn)檫@個(gè)方案對延遲并不敏感。
我已經(jīng)說了很多利用流處理來實(shí)現(xiàn)事務(wù)性的應(yīng)用。可能聽起來這是個(gè)很自然的想法,從某種角度上來說的確是這樣。但是它的確需要一些很復(fù)雜的機(jī)制來作為支撐。它需要一個(gè)連續(xù)處理而非微批處理的能力,需要能夠做迭代,需要復(fù)雜的基于事件時(shí)間處理亂序處理。為了更好地性能,它需要靈活的狀態(tài)抽象和異步 checkpoint 機(jī)制。這些是真正困難的事情。這些不是由 Ledger Streaming 庫實(shí)現(xiàn)的,而是 Apache Flink 實(shí)現(xiàn)的,所以即使對這類事務(wù)性的應(yīng)用而言,Apache Flink 也是真正的中流砥柱。
至此,我們可以說流處理不僅僅支持連續(xù)處理、流式分析、批處理或者事件驅(qū)動(dòng)的處理,你也可以用它做事務(wù)性的處理。當(dāng)然,前提是你有一個(gè)足夠強(qiáng)大的流處理引擎。這就是我演講的全部內(nèi)容。
福 利
最近的一份市場調(diào)查報(bào)告顯示,Apache Flink 是 2018 年開源大數(shù)據(jù)生態(tài)中發(fā)展“最快”的引擎,和 2017 年相比增長了 125% 。近日,阿里巴巴最新一期Flink電子月刊《重新定義計(jì)算:Apache Flink 實(shí)踐》正式發(fā)布,該月刊融合了 Apache Flink 在國內(nèi)各大互聯(lián)網(wǎng)公司的大規(guī)模實(shí)踐和Flink Forward China峰會(huì)上的精彩演講內(nèi)容,希望對大家有所幫助。
下載鏈接:
https://pan.baidu.com/s/1toyqHfi8UGk8mQeOAWfLOw
溫馨提醒:
1、此本書約35M,請耐心等待。
2、若打開很慢,可將地址復(fù)制到PC瀏覽器下載。
點(diǎn)擊下方圖片即可閱讀
996.ICU,全世界都聽到了中國程序員的吶喊與彷徨
會(huì)議推薦
阿里業(yè)務(wù)出海東南亞,運(yùn)用多語種 NLP 技術(shù),讓機(jī)器理解小語種混合使用的場景。阿里小蜜是如何構(gòu)建多語言機(jī)器人的?如何適應(yīng)不同國家的語言文化?來 7 月 ArchSummit 架構(gòu)師峰會(huì)上一探究竟。
網(wǎng)頁標(biāo)題:為什么說流處理即未來?
路徑分享:http://www.rwnh.cn/news21/101671.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供商城網(wǎng)站、企業(yè)建站、動(dòng)態(tài)網(wǎng)站、Google、全網(wǎng)營銷推廣、云服務(wù)器
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容