數棧技術分享:詳解FlinkX中的斷點續傳和實時採集

數棧DTinsight發表於2021-05-06

袋鼠云云原生一站式資料中臺PaaS——數棧,覆蓋了建設資料中心過程中所需要的各種工具(包括資料開發平臺、資料資產平臺、資料科學平臺、資料服務引擎等),完整覆蓋離線計算、實時計算應用,幫助企業極大地縮短資料價值的萃取過程,提高提煉資料價值的能力。

目前,數棧-離線開發平臺(BatchWorks) 中的資料離線同步任務、數棧-實時開發平臺(StreamWorks)中的資料實時採集任務已經統一基於FlinkX來實現。資料的離線採集和實時採集基本的原理的是一樣的,主要的不同之處是源頭的流是否有界,所以統一用Flink的Stream API 來實現這兩種資料同步場景,實現資料同步的批流統一。

一、功能介紹

1、斷點續傳

斷點續傳是指資料同步任務在執行過程中因各種原因導致任務失敗,不需要重頭同步資料,只需要從上次失敗的位置繼續同步即可,類似於下載檔案時因網路原因失敗,不需要重新下載檔案,只需要繼續下載就行,可以大大節省時間和計算資源。斷點續傳是數棧-離線開發平臺(BatchWorks)裡資料同步任務的一個功能,需要結合任務的出錯重試機制才能完成。當任務執行失敗,會在Engine裡進行重試,重試的時候會接著上次失敗時讀取的位置繼續讀取資料,直到任務執行成功為止。

2、實時採集

實時採集是數棧-實時開發平臺(StreamWorks)裡資料採集任務的一個功能,當資料來源裡的資料發生了增刪改操作,同步任務監聽到這些變化,將變化的資料實時同步到目標資料來源。除了資料實時變化外,實時採集和離線資料同步的另一個區別是:實時採集任務是不會停止的,任務會一直監聽資料來源是否有變化。這一點和Flink任務是一致的,所以實時採集任務是數棧流計算應用裡的一個任務型別,配置過程和離線計算裡的同步任務基本一樣。

二、Flink中的Checkpoint機制

斷點續傳和實時採集都依賴於Flink的Checkpoint機制,所以我們們先來簡單瞭解一下。

Checkpoint是Flink實現容錯機制最核心的功能,它能夠根據配置週期性地基於Stream中各個Operator的狀態來生成Snapshot,從而將這些狀態資料定期持久化儲存下來,當Flink程式一旦意外崩潰時,重新執行程式時可以有選擇地從這些Snapshot進行恢復,從而修正因為故障帶來的程式資料狀態中斷。


Checkpoint觸發時,會向多個分散式的Stream Source中插入一個Barrier標記,這些Barrier會隨著Stream中的資料記錄一起流向下游的各個Operator。當一個Operator接收到一個Barrier時,它會暫停處理Steam中新接收到的資料記錄。因為一個Operator可能存在多個輸入的Stream,而每個Stream中都會存在對應的Barrier,該Operator要等到所有的輸入Stream中的Barrier都到達。

當所有Stream中的Barrier都已經到達該Operator,這時所有的Barrier在時間上看來是同一個時刻點(表示已經對齊),在等待所有Barrier到達的過程中,Operator的Buffer中可能已經快取了一些比Barrier早到達Operator的資料記錄(Outgoing Records),這時該Operator會將資料記錄(Outgoing Records)發射(Emit)出去,作為下游Operator的輸入,最後將Barrier對應Snapshot發射(Emit)出去作為此次Checkpoint的結果資料。

三、斷點續傳

1、前提條件

同步任務要支援斷點續傳,對資料來源有一些強制性的要求:

1)資料來源(這裡特指關聯式資料庫)中必須包含一個升序的欄位,比如主鍵或者日期型別的欄位,同步過程中會使用checkpoint機制記錄這個欄位的值,任務恢復執行時使用這個欄位構造查詢條件過濾已經同步過的資料,如果這個欄位的值不是升序的,那麼任務恢復時過濾的資料就是錯誤的,最終導致資料的缺失或重複;

2)資料來源必須支援資料過濾,如果不支援的話,任務就無法從斷點處恢復執行,會導致資料重複;

3)目標資料來源必須支援事務,比如關聯式資料庫,檔案型別的資料來源也可以透過臨時檔案的方式支援。

2、任務執行的詳細過程

我們用一個具體的任務詳細介紹一下整個過程,任務詳情如下:

1)讀取資料

讀取資料時首先要構造資料分片,構造資料分片就是根據通道索引和checkpoint記錄的位置構造查詢sql,sql模板如下:

select * from data_test 
where id mod ${channel_num}=${channel_index}
and id > ${offset}

如果是第一次執行,或者上一次任務失敗時還沒有觸發checkpoint,那麼offset就不存在,根據offset和通道可以確定具體的查詢sql:

offset存在時

第一個通道:

select * from data_test
where id mod 2=0
and id > ${offset_0};

第二個通道:

select * from data_test
where id mod 2=1
and id > ${offset_1};

offset不存在時

第一個通道:

select * from data_test
where id mod 2=0;

第二個通道:

select * from data_test
where id mod 2=1;

資料分片構造好之後,每個通道就根據自己的資料分片去讀資料了。

2)寫資料

寫資料前會先做幾個操作:

a、檢測 /data_test 目錄是否存在,如果目錄不存在,則建立這個目錄,如果目錄存在,進行2操作;
b、判斷是不是以覆蓋模式寫資料,如果是,則刪除 /data_test目錄,然後再建立目錄,如果不是,則進行3操作;
c、檢測 /data_test/.data 目錄是否存在,如果存在就先刪除,再建立,確保沒有其它任務因異常失敗遺留的髒資料檔案;

資料寫入hdfs是單條寫入的,不支援批次寫入。資料會先寫入/data_test/.data/目錄下,資料檔案的命名格式為:

channelIndex.jobId.fileIndex

包含通道索引,jobId,檔案索引三個部分。

3)checkpoint觸發時

在FlinkX中“狀態”表示的是標識欄位id的值,我們假設checkpoint觸發時兩個通道的讀取和寫入情況如圖中所示:

checkpoint觸發後,兩個reader先生成Snapshot記錄讀取狀態,通道0的狀態為 id=12,通道1的狀態為 id=11。Snapshot生成之後向資料流裡面插入barrier,barrier隨資料流向Writer。以Writer_0為例,Writer_0接收Reader_0和Reader_1發來的資料,假設先收到了Reader_0的barrier,這個時候Writer_0停止寫出資料到HDFS,將接收到的資料先放到 InputBuffer裡面,一直等待Reader_1的barrier到達之後再將Buffer裡的資料全部寫出,然後生成Writer的Snapshot,整個checkpoint結束後,記錄的任務狀態為:

Reader_0:id=12

Reader_1:id=11

Writer_0:id=無法確定

Writer_1:id=無法確定

任務狀態會記錄到配置的HDFS目錄/flinkx/checkpoint/abc123下。因為每個Writer會接收兩個Reader的資料,以及各個通道的資料讀寫速率可能不一樣,所以導致writer接收到的資料順序是不確定的,但是這不影響資料的準確性,因為讀取資料時只需要Reader記錄的狀態就可以構造查詢sql,我們只要確保這些資料真的寫到HDFS就行了。在Writer生成Snapshot之前,會做一系列操作保證接收到的資料全部寫入HDFS:

a、close寫入HDFS檔案的資料流,這時候會在/data_test/.data目錄下生成兩個兩個檔案:

/data_test/.data/0.abc123.0

/data_test/.data/1.abc123.0

b、將生成的兩個資料檔案移動到/data_test目錄下;

c、更新檔名稱模板更新為:channelIndex.abc123.1;

快照生成後任務繼續讀寫資料,如果生成快照的過程中有任何異常,任務會直接失敗,這樣這次快照就不會生成,任務恢復時會從上一個成功的快照恢復。

4)任務正常結束

任務正常結束時也會做和生成快照時同樣的操作,close檔案流,移動臨時資料檔案等。

5)任務異常終止

任務如果異常結束,假設任務結束時最後一個checkpoint記錄的狀態為:

Reader_0:id=12Reader_1:id=11

那麼任務恢復的時候就會把各個通道記錄的狀態賦值給offset,再次讀取資料時構造的sql為:

第一個通道:

select * from data_test
where id mod 2=0
and id > 12;

第二個通道:

select * from data_test
where id mod 2=1
and id > 11;
這樣就可以從上一次失敗的位置繼續讀取資料了。

3、支援斷點續傳的外掛

理論上只要支援過濾資料的資料來源,和支援事務的資料來源都可以支援斷點續傳的功能,目前FlinkX支援的外掛如下:

四、實時採集

目前FlinkX支援實時採集的外掛有KafKa、binlog外掛,binlog外掛是專門針對mysql資料庫做實時採集的,如果要支援其它的資料來源,只需要把資料打到Kafka,然後再用FlinkX的Kafka外掛消費資料即可,比如oracle,只需要使用oracle的ogg將資料打到Kafka。這裡我們專門講解一下mysql的實時採集外掛binlog。

1、binlog

binlog是Mysql sever層維護的一種二進位制日誌,與innodb引擎中的redo/undo log是完全不同的日誌;其主要是用來記錄對mysql資料更新或潛在發生更新的SQL語句,並以"事務"的形式儲存在磁碟中。

binlog的作用主要有:

1)複製:MySQL Replication在Master端開啟binlog,Master把它的二進位制日誌傳遞給slaves並回放來達到master-slave資料一致的目的;

2)資料恢復:透過mysqlbinlog工具恢復資料;

3)增量備份。

2、MySQL 主備複製

有了記錄資料變化的binlog日誌還不夠,我們還需要藉助MySQL的主備複製功能:主備複製是指 一臺伺服器充當主資料庫伺服器,另一臺或多臺伺服器充當從資料庫伺服器,主伺服器中的資料自動複製到從伺服器之中。

主備複製的過程:

1)MySQL master 將資料變更寫入二進位制日誌( binary log, 其中記錄叫做二進位制日誌事件binary log events,可以透過 show binlog events 進行檢視);


2)MySQL slave 將 master 的 binary log events 複製到它的中繼日誌(relay log);

3)MySQL slave 重放 relay log 中事件,將資料變更反映它自己的資料。

3、寫入Hive

binlog外掛可以監聽多張表的資料變更情況,解析出的資料中包含表名稱資訊,讀取到的資料可以全部寫入目標資料庫的一張表,也可以根據資料中包含的表名資訊寫入不同的表,目前只有Hive外掛支援這個功能。Hive外掛目前只有寫入外掛,功能基於HDFS的寫入外掛實現,也就是說從binlog讀取,寫入hive也支援失敗恢復的功能。

寫入Hive的過程:

1)從資料中解析出MySQL的表名,然後根據表名對映規則轉換成對應的Hive表名;

2)檢查Hive表是否存在,如果不存在就建立Hive表;

3)查詢Hive表的相關資訊,構造HdfsOutputFormat;

4)呼叫HdfsOutputFormat將資料寫入HDFS。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69995740/viewspace-2771057/,如需轉載,請註明出處,否則將追究法律責任。

相關文章