Flink-狀態編程和容錯機制 | 算子狀態和鍵控狀態的介紹及數據結構 | 狀態的定義及使用

GitHub代碼

https://github.com/SmallScorpion/flink-tutorial.git

狀態編程和容錯機制

流式計算分爲無狀態和有狀態兩種情況。無狀態的計算觀察每個獨立事件,並根據最後一個事件輸出結果。例如,流處理應用程序從傳感器接收溫度讀數,並在溫度超過90度時發出警告。有狀態的計算則會基於多個事件輸出結果。以下是一些例子。

  1. 所有類型的窗口。例如,計算過去一小時的平均溫度,就是有狀態的計算。
  2. 所有用於複雜事件處理的狀態機。例如,若在一分鐘內收到兩個相差20度以上的溫度讀數,則發出警告,這是有狀態的計算。
  3. 流與流之間的所有關聯操作,以及流與靜態表或動態表之間的關聯操作,都是有狀態的計算。

下圖展示了無狀態流處理和有狀態流處理的主要區別。無狀態流處理分別接收每條數據記錄(圖中的黑條),然後根據最新輸入的數據生成輸出數據(白條)。有狀態流處理會維護狀態(根據每條輸入記錄進行更新),並基於最新輸入的記錄和當前的狀態值生成輸出記錄(灰條)。

在這裏插入圖片描述

Flink中的狀態

  1. 由一個任務維護,並且用來計算某個結果的所有數據,都屬於這個任務的狀態
  2. 可以認爲狀態就是一個本地變量,可以被任務的業務邏輯訪問
  3. Flink 會進行狀態管理,包括狀態一致性、故障處理以及高效存儲和訪問,以便開發人員可以專注於應用程序的邏輯
  4. 在 Flink 中,狀態始終與特定算子相關聯
  5. 爲了使運行時的 Flink 瞭解算子的狀態,算子需要預先註冊其狀態

在這裏插入圖片描述

算子狀態(Operator State)

  1. 算子狀態的作用範圍限定爲算子任務,由同一並行任務所處理的所有數據都可以訪問到相同的狀態
  2. 狀態對於同一子任務而言是共享的
  3. 算子狀態不能由相同或不同算子的另一個子任務訪問

在這裏插入圖片描述

算子狀態數據結構

在這裏插入圖片描述

鍵控狀態(Keyed State)

  1. 鍵控狀態是根據輸入數據流中定義的鍵(key)來維護和訪問的
  2. Flink 爲每個 key 維護一個狀態實例,並將具有相同鍵的所有數據,都分區到同一個算子任務中,這個任務會維護和處理這個 key 對應的狀態
  3. 當任務處理一條數據時,它會自動將狀態的訪問範圍限定爲當前數據的 key
  4. Keyed State很類似於一個分佈式的key-value map數據結構,只能用於KeyedStream(keyBy算子處理之後)

在這裏插入圖片描述

鍵控狀態數據結構

在這裏插入圖片描述

狀態定義及使用

import java.lang

import com.atguigu.bean.SensorReading
import com.atguigu.window.MyReduceFunc
import org.apache.flink.api.common.functions.RichReduceFunction
import org.apache.flink.api.common.state.{ListState, ListStateDescriptor, MapState, MapStateDescriptor, ReducingState, ReducingStateDescriptor, ValueState, ValueStateDescriptor}
import org.apache.flink.api.java.tuple.Tuple
import org.apache.flink.streaming.api.scala._

object ValueStateTest {
  def main(args: Array[String]): Unit = {

    val env = StreamExecutionEnvironment.getExecutionEnvironment
    env.setParallelism(1)

    val inputDStream: DataStream[String] = env.readTextFile("D:\\MyWork\\WorkSpaceIDEA\\flink-tutorial\\src\\main\\resources\\SensorReading.txt")

    val dataDstream: DataStream[SensorReading] = inputDStream.map(
      data => {
        val dataArray: Array[String] = data.split(",")
        SensorReading(dataArray(0), dataArray(1).toLong, dataArray(2).toDouble)
      })

    val resultDStrem: DataStream[SensorReading] = dataDstream
      .keyBy("id")
        .reduce( MyStateTestFunc() )

    dataDstream.print("data")
    
    env.execute("state test job")

  }
}


case class MyStateTestFunc() extends RichReduceFunction[SensorReading]{

  // state 定義
  lazy val myValueState: ValueState[Double] = getRuntimeContext
    .getState( new ValueStateDescriptor[Double]("myValue", classOf[Double]))

  lazy val myListState: ListState[String] = getRuntimeContext
    .getListState( new ListStateDescriptor[String]("myList", classOf[String]) )

  lazy val myMapState: MapState[String, Double] = getRuntimeContext
    .getMapState( new MapStateDescriptor[String, Double]("myMap", classOf[String], classOf[Double]))

  lazy val myReducingState: ReducingState[SensorReading] = getRuntimeContext
    .getReducingState( new ReducingStateDescriptor[SensorReading]("myReduce", MyReduceFunc(), classOf[SensorReading]) )


  override def reduce(t: SensorReading, t1: SensorReading): SensorReading = {

    // 獲取狀態
    val myValue: Double = myValueState.value()
    val myList: lang.Iterable[String] = myListState.get()
    val myMap: Double = myMapState.get("sensor_1")
    val myReducing: SensorReading = myReducingState.get()


    // 狀態寫入
    myValueState.update( 0.0 )
    myListState.add( "hello flink" )
    myMapState.put( "sensor_1", 1.0)
    myReducingState.add( t1 )

    t1
  }
}

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章