Flink 提供了三種可用的狀態后端:MemoryStateBackend,FsStateBackend,和RocksDBStateBackend。
MemoryStateBackend MemoryStateBackend 是將狀態維護在 Java 堆上的一個內部狀態后端。鍵值狀態和窗口算子使用哈希表來存儲數據(values)和定時器(timers)。當應用程序 checkpoint 時,此后端會在將狀態發給 JobManager 之前快照下狀態,JobManager 也將狀態存儲在 Java 堆上。默認情況下,MemoryStateBackend 配置成支持異步快照。異步快照可以避免阻塞數據流的處理,從而避免反壓的發生。 使用 MemoryStateBackend 時的注意點: 默認情況下,每一個狀態的大小限制為 5 MB。可以通過 MemoryStateBackend 的構造函數增加這個大小。 狀態大小受到 akka 幀大小的限制,所以無論怎么調整狀態大小配置,都不能大於 akka 的幀大小。也可以通過 akka.framesize 調整 akka 幀大小(通過配置文檔了解更多)。 狀態的總大小不能超過 JobManager 的內存。 何時使用 MemoryStateBackend: 本地開發或調試時建議使用 MemoryStateBackend,因為這種場景的狀態大小的是有限的。 MemoryStateBackend 最適合小狀態的應用場景。例如 Kafka consumer,或者一次僅一記錄的函數 (Map, FlatMap,或 Filter)。
FsStateBackend FsStateBackend 需要配置的主要是文件系統,如 URL(類型,地址,路徑)。舉個例子,比如可以是: “hdfs://namenode:40010/flink/checkpoints” 或 “s3://flink/checkpoints” 當選擇使用 FsStateBackend 時,正在進行的數據會被存在 TaskManager 的內存中。在 checkpoint 時,此后端會將狀態快照寫入配置的文件系統和目錄的文件中,同時會在 JobManager 的內存中(在高可用場景下會存在 Zookeeper 中)存儲極少的元數據。 默認情況下,FsStateBackend 配置成提供異步快照,以避免在狀態 checkpoint 時阻塞數據流的處理。該特性可以實例化 FsStateBackend 時傳入 false 的布爾標志來禁用掉,例如: new FsStateBackend(path, false); 使用 FsStateBackend 時的注意點: 當前的狀態仍然會先存在 TaskManager 中,所以狀態的大小不能超過 TaskManager 的內存。 何時使用 FsStateBackend: FsStateBackend 適用於處理大狀態,長窗口,或大鍵值狀態的有狀態處理任務。 FsStateBackend 非常適合用於高可用方案。
RocksDBStateBackend RocksDBStateBackend 的配置也需要一個文件系統(類型,地址,路徑),如下所示: “hdfs://namenode:40010/flink/checkpoints” 或 “s3://flink/checkpoints” RocksDB 是一種嵌入式的本地數據庫。RocksDBStateBackend 將處理中的數據使用 RocksDB 存儲在本地磁盤上。在 checkpoint 時,整個 RocksDB 數據庫會被存儲到配置的文件系統中,或者在超大狀態作業時可以將增量的數據存儲到配置的文件系統中。同時 Flink 會將極少的元數據存儲在 JobManager 的內存中,或者在 Zookeeper 中(對於高可用的情況)。RocksDB 默認也是配置成異步快照的模式。 使用 RocksDBStateBackend 時的注意點: RocksDB 支持的單 key 和單 value 的大小最大為每個 2^31 字節。這是因為 RocksDB 的 JNI API 是基於 byte[] 的。 我們需要強調的是,對於使用具有合並操作的狀態的應用程序,例如 ListState,隨着時間可能會累積到超過 2^31 字節大小,這將會導致在接下來的查詢中失敗。 何時使用 RocksDBStateBackend: RocksDBStateBackend 最適合用於處理大狀態,長窗口,或大鍵值狀態的有狀態處理任務。 RocksDBStateBackend 非常適合用於高可用方案。 RocksDBStateBackend 是目前唯一支持增量 checkpoint 的后端。增量 checkpoint 非常使用於超大狀態的場景。 當使用 RocksDB 時,狀態大小只受限於磁盤可用空間的大小。這也使得 RocksDBStateBackend 成為管理超大狀態的最佳選擇。使用 RocksDB 的權衡點在於所有的狀態相關的操作都需要序列化(或反序列化)才能跨越 JNI 邊界。與上面提到的堆上后端相比,這可能會影響應用程序的吞吐量。