本發(fā)明涉及信息技術(shù)領(lǐng)域,具體涉及一種流式計(jì)算環(huán)境下的并行數(shù)據(jù)回流方法。
背景技術(shù):
從社交網(wǎng)絡(luò)資訊(以提供熱門話題或?qū)崟r(shí)搜索)到廣告處理數(shù)據(jù)引擎,實(shí)時(shí)流計(jì)算在當(dāng)今工業(yè)中被廣泛地使用,如apahestorm,twitter’sheron,apacheflink,sparkstreaming,samza等。在這些系統(tǒng)中,數(shù)據(jù)的產(chǎn)生完全由數(shù)據(jù)源確定,數(shù)據(jù)源的動(dòng)態(tài)變化及狀態(tài)不統(tǒng)一導(dǎo)致數(shù)據(jù)流的速率呈現(xiàn)出了突發(fā)性的特征,而數(shù)據(jù)流的突發(fā)性特征常常導(dǎo)致過載的發(fā)生,發(fā)生過載還有以下幾個(gè)原因:網(wǎng)絡(luò)擁塞,資源利用率高,干擾,異質(zhì)性,io高頻阻塞等。因此,在實(shí)時(shí)流計(jì)算中,過載是常見且難以避免的。
實(shí)時(shí)流計(jì)算已被許多知名企業(yè)應(yīng)用于大數(shù)據(jù)計(jì)算領(lǐng)域,如淘寶實(shí)時(shí)分析、阿里云galaxy實(shí)時(shí)計(jì)算、攜程網(wǎng)站性能監(jiān)控等。對于實(shí)時(shí)性系統(tǒng),系統(tǒng)的響應(yīng)性和穩(wěn)定性是關(guān)注的重點(diǎn)。響應(yīng)意味著降低處理數(shù)據(jù)的延遲,即數(shù)據(jù)計(jì)算延遲,例如,數(shù)據(jù)從它輸入至系統(tǒng)中到其結(jié)果反映給用戶所經(jīng)過的時(shí)間;穩(wěn)定性意味著系統(tǒng)能夠穩(wěn)定持久地在集群中運(yùn)行。而過載的發(fā)生極易導(dǎo)致系統(tǒng)整體的數(shù)據(jù)計(jì)算延遲增加和不穩(wěn)定甚至不可用。
在實(shí)時(shí)流計(jì)算系統(tǒng)中,計(jì)算結(jié)構(gòu)是一個(gè)有向無環(huán)圖(dag),稱為拓?fù)?topology),拓?fù)溆蓴?shù)據(jù)流(steam),數(shù)據(jù)流的生成者組件(spout)和運(yùn)算組件(bolt)組成。task是拓?fù)渲衧pout或bolt在運(yùn)行時(shí)的實(shí)例,執(zhí)行task的進(jìn)程稱為執(zhí)行器(executor),執(zhí)行器所在的服務(wù)器稱為工作節(jié)點(diǎn)(workernode)。stream由一連串tuple序列組成,tuple是在topology中流動(dòng)的數(shù)據(jù)對象。
tuple丟失或tuple處理時(shí)間超過topology規(guī)定的處理時(shí)間都會(huì)導(dǎo)致tuple重放,而tuple的頻繁重放是topology過載的主要原因之一。此外,為了保證數(shù)據(jù)的容錯(cuò)性,實(shí)時(shí)流計(jì)算通常會(huì)在spout中維護(hù)一個(gè)待發(fā)送隊(duì)列,隊(duì)列中的一條tuple被發(fā)送出去之后不會(huì)被立即刪除,而是維持一個(gè)“掛起”狀態(tài),直到該tuple被topology處理完成的信號(hào)到達(dá)。若數(shù)據(jù)在計(jì)算過程中失敗,topology可以重發(fā)處于“掛起”狀態(tài)的數(shù)據(jù),以實(shí)現(xiàn)數(shù)據(jù)的容錯(cuò)。但在大規(guī)模實(shí)時(shí)流計(jì)算中維護(hù)大量數(shù)據(jù)的狀態(tài)無疑會(huì)增加系統(tǒng)的負(fù)載和復(fù)雜性。
數(shù)據(jù)容錯(cuò)是大數(shù)據(jù)計(jì)算中不可或缺的關(guān)鍵技術(shù),由于進(jìn)行大數(shù)據(jù)計(jì)算的分布式集群往往包含成千上萬個(gè)節(jié)點(diǎn),龐大的節(jié)點(diǎn)數(shù)量使得節(jié)點(diǎn)失效成為常態(tài)。wang.y提出了一種數(shù)據(jù)復(fù)制技術(shù),它是一種多副本的數(shù)據(jù)容錯(cuò)技術(shù)。plank.j.s提出了一種可擴(kuò)展的數(shù)據(jù)容錯(cuò)技術(shù),它是一種糾錯(cuò)碼數(shù)據(jù)容錯(cuò)技術(shù)。隨著數(shù)據(jù)規(guī)模的持續(xù)擴(kuò)大,容錯(cuò)能力強(qiáng)且成本低的數(shù)據(jù)容錯(cuò)方法已成為研究的熱點(diǎn)。
技術(shù)實(shí)現(xiàn)要素:
為了克服現(xiàn)有的實(shí)時(shí)流計(jì)算中為解決數(shù)據(jù)容錯(cuò)而實(shí)現(xiàn)的有狀態(tài)的數(shù)據(jù)處理方式增加了系統(tǒng)的復(fù)雜性的不足,此外,在topology過載時(shí),tuple表現(xiàn)出頻繁重放,這種有狀態(tài)的解決方法無疑會(huì)增加系統(tǒng)的負(fù)載,而在大規(guī)模的分布式系統(tǒng)上,性能的任何改進(jìn)都意味著基礎(chǔ)設(shè)施成本的顯著降低,以及最終用戶的生產(chǎn)力的顯著提高。本發(fā)明提出了一種容錯(cuò)的、數(shù)據(jù)無狀態(tài)的并行數(shù)據(jù)回流方法,此方法是一種面向?qū)崟r(shí)流計(jì)算的數(shù)據(jù)重放方式。
本發(fā)明提供如下的技術(shù)方案:
一種面向?qū)崟r(shí)流計(jì)算的并行數(shù)據(jù)回流方法,所述回流方法包括以下步驟:
步驟(1)初始化三個(gè)隊(duì)列,分別為eden隊(duì)列、from隊(duì)列和to隊(duì)列,它們分別由三個(gè)指針edenp、fromp和top來標(biāo)識(shí);若topology需要從外部數(shù)據(jù)源獲取數(shù)據(jù),則外部數(shù)據(jù)源的數(shù)據(jù)會(huì)先存入eden隊(duì)列;
步驟(2)初始化一個(gè)管道dataqueue,dataqueue負(fù)責(zé)從eden隊(duì)列、from隊(duì)列和to隊(duì)列中讀取數(shù)據(jù)到topology中,dataqueue通過指針(edenp、fromp、top)來選擇讀取的隊(duì)列;
步驟(3)topology的spout向dataqueue發(fā)起讀請求;
步驟(4)dataqueue讀取三個(gè)隊(duì)列中的數(shù)據(jù),供spout使用;
步驟(5)判斷top指向的隊(duì)列是否為空,若是,進(jìn)行步驟(6);若否,進(jìn)行步驟(7);
步驟(6)將from隊(duì)列中的數(shù)據(jù)復(fù)制到to隊(duì)列中,并清空from隊(duì)列;
步驟(7)topology獲取dataqueue中的數(shù)據(jù),當(dāng)前task向下游發(fā)送一個(gè)tuple;
步驟(8)當(dāng)前task等待發(fā)送tuple的反饋,若發(fā)送失敗或超時(shí)未反饋,則選擇回流該tuple,最長等待時(shí)間不超過ttl,ttl是task之間消息傳遞的最長往返時(shí)間;
步驟(9)判斷topology是否可以停止,若否,則回到步驟(4),否則,結(jié)束。
進(jìn)一步,所述步驟(4)中,dataqueue讀取三個(gè)隊(duì)列中的數(shù)據(jù)的過程如下:
4.1)判斷top指向的隊(duì)列是否為空,若非空,進(jìn)行步驟4.2,否則進(jìn)行步驟4.3;
4.2)讀取top指向的隊(duì)列中的數(shù)據(jù),進(jìn)行步驟(5);
4.3)讀取edenp指向的隊(duì)列。
再進(jìn)一步,所述步驟(6)中,將from隊(duì)列中的數(shù)據(jù)復(fù)制到to隊(duì)列中并清空from隊(duì)列的過程如下:
6.1)設(shè)置空隊(duì)列指針change,change賦值為top;
6.2)將top賦值為fromp;
6.3)將fromp賦值為change。
更進(jìn)一步,所述步驟(8)的過程如下:
8.1)在ttl時(shí)間內(nèi),下游task是否確認(rèn)收到該消息,若是則進(jìn)行步驟8.2),否則進(jìn)行步驟8.3;
8.2)當(dāng)前tuple已處理成功,進(jìn)行步驟(9);
8.3)當(dāng)前tuple處理失敗,將該tuple寫回fromp指向的隊(duì)列,進(jìn)行步驟(9)。
所述步驟(6)中,效果等同于from隊(duì)列與to隊(duì)列互換,該步驟由一個(gè)單獨(dú)的線程copy-thread負(fù)責(zé)執(zhí)行,top指向的隊(duì)列與eden隊(duì)列和from隊(duì)列相比會(huì)被dataqueue優(yōu)先讀取。
所述步驟(8)中,在topology中計(jì)算失敗的數(shù)據(jù)被寫回到fromp指向的隊(duì)列,該步驟由一個(gè)單獨(dú)的線程backflow-thread負(fù)責(zé)執(zhí)行;雖然task等待發(fā)送出的tuple反饋,但此處tuple是無狀態(tài)的,task僅僅確認(rèn)數(shù)據(jù)是否發(fā)送到下游task,而不會(huì)對數(shù)據(jù)的處理過程進(jìn)行跟蹤。
在topology運(yùn)行過程中,上述步驟會(huì)持續(xù)進(jìn)行,直到topology顯式地終止。初始化、數(shù)據(jù)的讀取以及數(shù)據(jù)的計(jì)算在主線程(main-thread)中執(zhí)行,copy-thread負(fù)責(zé)隊(duì)列的替換(復(fù)制算法),backflow-thread負(fù)責(zé)數(shù)據(jù)的回流。由于to隊(duì)列的優(yōu)先讀取與復(fù)制算法的存在,使得數(shù)據(jù)的容錯(cuò)可以得到保證。此外,雖然在復(fù)制期間(步驟6)to隊(duì)列不可讀,from隊(duì)列不可寫,但實(shí)際上使用的復(fù)制方法只是將指向from與to的指針進(jìn)行替換,并清除from中的數(shù)據(jù),此過程只需執(zhí)行少量磁盤讀寫操作,因此算法執(zhí)行速度得以保證。
本發(fā)明的有益效果是:實(shí)時(shí)流計(jì)算中的數(shù)據(jù)只有兩種狀態(tài),分別是“未讀取”和“已完成”。數(shù)據(jù)若在計(jì)算過程中失敗會(huì)由backflow-thread負(fù)責(zé)將數(shù)據(jù)回流,回流的數(shù)據(jù)由copy-thread負(fù)責(zé)重新將數(shù)據(jù)放置待讀取隊(duì)列。因此,無需在數(shù)據(jù)計(jì)算過程中維持“掛起”狀態(tài)和數(shù)據(jù)計(jì)算過程的跟蹤,此外,由于to隊(duì)列的優(yōu)先讀取,回流的數(shù)據(jù)不會(huì)長時(shí)間堆積在隊(duì)列尾部。該方法的主要優(yōu)點(diǎn)是:1)數(shù)據(jù)無狀態(tài)且具有容錯(cuò)性;2)降低數(shù)據(jù)計(jì)算延遲,提高系統(tǒng)響應(yīng)性;3)回流的數(shù)據(jù)會(huì)盡可能優(yōu)先處理。
附圖說明
圖1是本發(fā)明實(shí)施例中apahcestorm記錄級(jí)容錯(cuò)示意圖。
圖2是本發(fā)明實(shí)施例中kafka隊(duì)列數(shù)據(jù)狀態(tài)機(jī)示意圖。
圖3是本發(fā)明實(shí)施例中并行數(shù)據(jù)回流方法數(shù)據(jù)狀態(tài)機(jī)示意圖。
圖4是本發(fā)明實(shí)施例中并行數(shù)據(jù)回流方法示意圖。
具體實(shí)施方式
為使本發(fā)明的上述特征和過程更加明顯易懂,下文特舉實(shí)施例,并配合附圖作詳細(xì)說明如下。
參照圖1~圖4,一種面向?qū)崟r(shí)流計(jì)算的并行數(shù)據(jù)回流方法,以apahcestorm作為實(shí)時(shí)流計(jì)算系統(tǒng),apachekafka作為數(shù)據(jù)隊(duì)列。apachestorm中的spout分為可靠spout和不可靠spout??煽康膕pout實(shí)現(xiàn)了至少一次(at-least-once)語義,它會(huì)重發(fā)失敗的tuple,確保每一個(gè)tuple至少被處理一次,它是一種數(shù)據(jù)有狀態(tài)的實(shí)現(xiàn)方式;不可靠的spout實(shí)現(xiàn)的是至多一次(at-most-once)語義,它不會(huì)對發(fā)送失敗的tuple做處理。由于storm中spout的數(shù)據(jù)發(fā)送方法nexttuple()和數(shù)據(jù)確認(rèn)方法ack()/fail()在同一個(gè)線程中被串行調(diào)用,其中ack()是tuple處理成功時(shí)調(diào)用的函數(shù),fail()是tuple處理失敗時(shí)調(diào)用的函數(shù)。本發(fā)明的并行數(shù)據(jù)回流將ack()/fail()和nexttuple()放在不同的線程中執(zhí)行,其中nexttuple在main-thread中執(zhí)行,ack()/fail()會(huì)在backflow-thread中執(zhí)行。
圖1是apahcestorm記錄級(jí)容錯(cuò)示意圖,本實(shí)施例中的并行數(shù)據(jù)回流依賴apachestorm的記錄級(jí)容錯(cuò)實(shí)現(xiàn)。圖中,id值為1的數(shù)據(jù)流被完整執(zhí)行指的是該數(shù)據(jù)流分別經(jīng)過bolt1或bolt2,最終達(dá)到bolt3。沒有被完整執(zhí)行指的是數(shù)據(jù)流在任意節(jié)點(diǎn)處理失敗或處理超時(shí)。storm的記錄級(jí)容錯(cuò)是通過內(nèi)置的確認(rèn)器(acker)實(shí)現(xiàn)的,通過對流中的數(shù)據(jù)分組進(jìn)行編號(hào),每次操作都產(chǎn)生新的操作數(shù)并進(jìn)行異或(xor)運(yùn)算,因此若在運(yùn)算中這些操作數(shù)都重復(fù)偶數(shù)次,則整個(gè)異或結(jié)果一定為零,acker通過異或結(jié)果來實(shí)現(xiàn)全局路經(jīng)的跟蹤。基本流程是:在topology中,系統(tǒng)每產(chǎn)生一個(gè)數(shù)據(jù)流分組,就會(huì)給這個(gè)分組分配一個(gè)根id,id由64位的整數(shù)構(gòu)成。每當(dāng)該分組被發(fā)送到一個(gè)bolt時(shí)會(huì)產(chǎn)生一個(gè)新的id,并將所發(fā)射分組的根id和新產(chǎn)生的id發(fā)送給確認(rèn)器,確認(rèn)器通過對這些id進(jìn)行異或運(yùn)算來判斷消息單元是否處理完成。
圖2是kafka隊(duì)列數(shù)據(jù)狀態(tài)機(jī)示意圖。如圖所示,為了保證可靠性,kafka的一條消息在被處理的過程中處于“掛起”狀態(tài),并沒有真正被取出,該狀態(tài)直到消息處理完成信號(hào)到達(dá)后才會(huì)改變,結(jié)合圖1,即kafka中讀取的數(shù)據(jù)必須由storm的acker進(jìn)行全局的跟蹤直到數(shù)據(jù)被完整執(zhí)行的信號(hào)到達(dá),數(shù)據(jù)的狀態(tài)才會(huì)改變,這無疑會(huì)增加系統(tǒng)的負(fù)載和復(fù)雜性。初始數(shù)據(jù)處于“open”狀態(tài),topology讀取(read)該數(shù)據(jù)后,數(shù)據(jù)狀態(tài)變?yōu)椤皃rocessed”,該狀態(tài)即為“掛起”狀態(tài),若讀取失敗(fail)則狀態(tài)不變。數(shù)據(jù)若在計(jì)算過程中失敗,“掛起”的數(shù)據(jù)會(huì)被重放(replay)。若topology返回該數(shù)據(jù)被完整執(zhí)行的信號(hào)(“success”),則數(shù)據(jù)狀態(tài)變?yōu)椤癱ommit”。若信號(hào)“commit”超時(shí)未到達(dá),則該數(shù)據(jù)也會(huì)被重放(replay)。
圖3是并行數(shù)據(jù)回流方法數(shù)據(jù)狀態(tài)機(jī)示意圖。如圖所示,本發(fā)明采用并行數(shù)據(jù)回流的方式,被讀取的數(shù)據(jù)無“掛起”狀態(tài)。初始數(shù)據(jù)處于“open”狀態(tài),topology讀取(read)該數(shù)據(jù)后,數(shù)據(jù)狀態(tài)變?yōu)椤癱ommit”,若讀取失敗(fail)則狀態(tài)不變。
圖4是并行數(shù)據(jù)回流方法示意圖。為了實(shí)現(xiàn)并行數(shù)據(jù)回流,kafkatopic被拆分為三個(gè)并行的邏輯主題,分別作為eden隊(duì)列,from隊(duì)列和to隊(duì)列,其中eden為原始隊(duì)列,kafkatopic可以理解為數(shù)據(jù)在kafka邏輯上的分類。結(jié)合圖3,作步驟說明如下:
步驟(1)初始化三個(gè)kafka隊(duì)列,分別為eden隊(duì)列、from隊(duì)列和to隊(duì)列,它們分別由三個(gè)指針edenp(初始化時(shí)指向eden隊(duì)列)、fromp(初始化時(shí)指向from隊(duì)列)和top(初始化時(shí)指向to隊(duì)列)來標(biāo)識(shí);若topology需要從外部數(shù)據(jù)源獲取數(shù)據(jù),則外部數(shù)據(jù)源的數(shù)據(jù)會(huì)先存入eden隊(duì)列;
步驟(2)初始化一個(gè)管道dataqueue,dataqueue負(fù)責(zé)從eden隊(duì)列、from隊(duì)列和to隊(duì)列中讀取數(shù)據(jù)到topology中,dataqueue通過指針(edenp、fromp、top)來選擇讀取的隊(duì)列;
步驟(3)topology的spout向dataqueue發(fā)起讀請求,如圖4中的①;
步驟(4)dataqueue讀取三個(gè)隊(duì)列中的數(shù)據(jù),供spout使用,其過程如下:
4.1)判斷top指向的隊(duì)列是否為空,若非空,進(jìn)行步驟4.2),否則進(jìn)行步驟4.3;
4.2)讀取top指向的隊(duì)列中的數(shù)據(jù),如圖4中的②,進(jìn)行步驟(5);
4.3)讀取edenp指向的隊(duì)列,如圖4中的③;
步驟(5)判斷top指向的隊(duì)列是否為空,若是,進(jìn)行步驟(6);若否,進(jìn)行步驟(7);
步驟(6)將from隊(duì)列中的數(shù)據(jù)復(fù)制到to隊(duì)列中,并清空from隊(duì)列,如圖4中的④。實(shí)施例中復(fù)制前fromp隊(duì)列有數(shù)據(jù)塊a、e、h、g,其過程如下:
6.1)設(shè)置空隊(duì)列指針change,change賦值為top;
6.2)將top賦值為fromp,此時(shí)top指向的隊(duì)列中有數(shù)據(jù)塊a、e、h、g;
6.3)將fromp賦值為change,此時(shí)fromp指向的隊(duì)列為空;
步驟(7)topology獲取dataqueue中的數(shù)據(jù),當(dāng)前task向下游發(fā)送一個(gè)tuple,將tuple的狀態(tài)從“open”改變“commit”;
步驟(8)當(dāng)前task等待發(fā)送tuple的反饋,最長等待時(shí)間不超過ttl,若發(fā)送失敗或超時(shí)未反饋,則選擇回流該tuple,ttl是task之間消息傳遞的最長往返時(shí)間,本實(shí)施例設(shè)置的ttl值為100毫秒,其過程如下:
8.1)在ttl時(shí)間內(nèi),下游task是否確認(rèn)收到該消息,若是則進(jìn)行步驟8.2),否則進(jìn)行步驟8.3);
8.2)當(dāng)前tuple已處理成功,進(jìn)行步驟(9);
8.3)當(dāng)前tuple處理失敗,將該tuple寫回fromp指向的隊(duì)列,寫回的tuple相當(dāng)于一條新的消息,其狀態(tài)為“open”,進(jìn)行步驟(9);
步驟(9)判斷topology是否可以停止,若否,則回到步驟(4),否則,結(jié)束。
該實(shí)施例中并行數(shù)據(jù)回流方法的實(shí)現(xiàn)依賴于storm的記錄級(jí)容錯(cuò)機(jī)制,即tuple處理成功或失敗時(shí)spout的ack()/fail()方法會(huì)被調(diào)用。對于記錄級(jí)容錯(cuò),storm通過確認(rèn)器(acker)確保每個(gè)tuple在出錯(cuò)時(shí)被重發(fā)。本實(shí)施例在storm的確認(rèn)機(jī)制中嵌入了并行數(shù)據(jù)回流,并將確認(rèn)機(jī)制和發(fā)送數(shù)據(jù)方法隔離在不同的線程中運(yùn)行,其中fail()方法負(fù)責(zé)將失敗的tuple重新寫回kafka隊(duì)列,相當(dāng)于backflow-thread線程。由于并行數(shù)據(jù)回流中的復(fù)制算法需要對kafka的topic進(jìn)行擴(kuò)展,因此kafkaspout被創(chuàng)建時(shí),除了負(fù)責(zé)讀取原主題(eden隊(duì)列)中的數(shù)據(jù),它還負(fù)責(zé)在kafka中創(chuàng)建相應(yīng)topology的from主題和to主題,分別用于from隊(duì)列與to隊(duì)列,創(chuàng)建主題只會(huì)在topology首次運(yùn)行時(shí)執(zhí)行,與復(fù)制算法一同由copy-thread線程負(fù)責(zé)執(zhí)行。backflow-thread線程通過storm提供的kafkabolt發(fā)送tuple到fromp指向的隊(duì)列。當(dāng)系統(tǒng)出現(xiàn)故障或過載時(shí),因計(jì)算失敗丟失的tuple通過并行數(shù)據(jù)回流可以進(jìn)行恢復(fù),保證了數(shù)據(jù)的容錯(cuò)性。