過去無論您是在生産中使用,還是調研Apache Flink,估計您總是會問這樣一個問題:我該如何通路和更新Flink儲存點(savepoint)中儲存的state?不用再詢問了,Apache Flink 1.9.0引入了狀态處理器( State Processor
)API,它是基于DataSet API的強大擴充,允許讀取,寫入和修改Flink的儲存點和檢查點(checkpoint)中的狀态。
在這篇文章中,我們将解釋為什麼此功能對Flink來說很重要,以及該功能的用途和用法。最後,我們将讨論狀态處理器API的未來規劃,以保持與Flink批流統一的未來整體規劃一緻。
截止到Apache Flink 1.9的狀态流處理現狀
幾乎所有複雜的流處理應用程式都是有狀态的,其中大多數都是設計為運作數月甚至數年。随着時間的推移,這些作業積累了很多有價值的狀态,如果由于故障而丢失,這些狀态的重建将變得代價很高甚至是不可能的。為了保證應用程式狀态的一緻性和持久性,Flink從一開始就設計了一套複雜巧妙的檢查點和恢複機制。在每一個版本中,Flink社群都添加了越來越多與狀态相關的特性,以提高檢查點執行和恢複的速度、改進應用程式的維護和管理。
然而,Flink使用者經常會提出能夠“從外部”通路應用程式的狀态的需求。這個需求的動機可能是驗證或調試應用程式的狀态,或者将應用程式的狀态遷移到另一個應用程式,或者從外部系統(例如關系資料庫)導入應用程式的初始狀态。
盡管這些需求的出發點都是合理的,但到目前為止從外部通路應用程式的狀态這一功能仍然相當有限。Flink的可查詢狀态(
queryable state
)功能隻支援基于鍵的查找(點查詢),且不保證傳回值的一緻性(在應用程式發生故障恢複前後,傳回值可能不同),并且可查詢狀态隻支援讀取并不支援修改和寫入。此外,狀态的一緻性快照:儲存點,也是無法通路的,因為這是使用自定義二進制格式進行編碼的。
使用狀态處理器(State Processor)API對應用程式狀态進行讀寫
Flink1.9引入的狀态處理器API,真正改變了這一現狀,實作了對應用程式狀态的操作。該功能借助DataSet API,擴充了輸入和輸出格式以讀寫儲存點或檢查點資料。由于DataSet和Table API的互通性,使用者甚至可以使用關系表API或SQL查詢來分析和處理狀态資料。
例如,使用者可以建立正在運作的流處理應用程式的儲存點,并使用批處理程式對其進行分析,以驗證該應用程式的行為是否正确。 或者,使用者也可以任意讀取、處理、并寫入資料到儲存點中,将其用于流計算應用程式的初始狀态。 同時,現在也支援修複儲存點中狀态不一緻的條目。最後,狀态處理器API開辟了許多方法來開發有狀态的應用程式,以繞過以前為了保證可以正常恢複而做的諸多限制:使用者現在可以任意修改狀态的資料類型,調整運算符的最大并行度,拆分或合并運算符狀态,重新配置設定運算符UID等等。
将應用程式與資料集進行映射
狀态處理器API将流應用程式的狀态映射到一個或多個可以分别處理的資料集。為了能夠使用API,您需要了解此映射的工作方式。
首先,讓我們看看有狀态的Flink作業是什麼樣的。Flink作業由算子(
operator
)組成,通常是一個或多個source算子,一些進行資料處理的算子以及一個或多個sink算子。每個算子在一個或多個任務中并行運作,并且可以使用不同類型的狀态:可以具有零個,一個或多個清單形式的
operator states
,他們的作用域範圍是目前算子執行個體;如果這些算子應用于鍵控流(
keyed stream
),它還可以具有零個,一個或多個
keyed states
,它們的作用域範圍是從每個處理記錄中提取的鍵。您可以将keyed states視為分布式鍵-值映射。
下圖顯示的應用程式“MyApp”,由稱為“Src”,“Proc”和“Snk”的三個算子組成。Src具有一個
operator state
(os1),Proc具有一個
operator state
(os2)和兩個
keyed state
(ks1,ks2),而Snk則是無狀态的。
MyApp的儲存點或檢查點均由所有狀态的資料組成,這些資料的組織方式可以恢複每個任務的狀态。在使用批處理作業處理儲存點(或檢查點)的資料時,我們腦海中需要将每個任務狀态的資料映射到資料集或表中。因為實際上,我們可以将儲存點視為資料庫。每個算子(由其UID辨別)代表一個名稱空間。算子的每個
operator state
都射到名稱空間中的一個單列專用表,該列儲存所有任務的狀态資料。operator的所有
keyed state
都映射到一個鍵值多清單,該表由一列key和與每個
key state
映射的一列值組成。下圖顯示了MyApp的儲存點如何映射到資料庫
該圖顯示了"Src"的
operator state
的值如何映射到具有一列和五行的表,一行資料代表對于Src的所有并行任務中的一個并行執行個體。類似地,"Proc"的
operator state
os2,也映射到單個表。對于
keyed state
,ks1和ks2則是被組合到具有三列的單個表中,一列代表主鍵,一列代表ks1,一列代表ks2。該表為兩個keyed state的每個不同key都保有一行。由于“Snk”沒有任何狀态,是以其映射表為空。
狀态處理器API提供了建立,加載和編寫儲存點的方法。使用者可以從已加載的儲存點讀取資料集,也可以将資料集轉換為狀态并将其添加到儲存點中。總之,可以使用DataSet API的全部功能集來處理這些資料集。使用這些方法,可以解決所有前面提到的用例(以及更多用例)。如果您想詳細了解如何使用狀态處理器API,請
檢視文檔。
為什麼使用DataSet API?
如果您熟悉Flink的未來規劃,可能會對狀态處理器API基于DataSet API而感到驚訝,因為目前Flink社群計劃使用
BoundedStreams
的概念擴充DataStream API,并棄用DataSet API。但是在設計此狀态處理器功能時,我們還評估了DataStream API以及Table API,他們都不能提供相應的功能支援。由于不想此功能的開發是以受到阻礙,我們決定先在DataSet API上建構該功能,并将其對DataSet API的依賴性降到最低。基于此,将其遷移到另一個API應該是相當容易的。
總結
Flink使用者很長時間以來有從外部通路和修改流應用程式的狀态的需求,借助于狀态處理器API,Flink為使用者如何維護和管理流應用程式打開了許多新可能性,包括流應用程式的任意演變以及應用程式狀态的導出和引導。簡而言之,狀态處理器API得儲存點不再是一個黑匣子。