Flink_Kakfa自定義輸出分區

  • 在我們將消息寫入kafka的topic時,我們可以通過FlinkkafkaPartitioner指定寫入topic的哪個分區。
  • 在不指定的情況下,默認的分區器會將每個數據任務映射到一個單獨的kafka分區中,即單個任務的所有記錄都會發往同一分區。
  • 如果任務數多餘分區數,則每個分區可能會包含多個任務發來的記錄。 而如果任務數小於分區數,則默認配置會導致有些分區收不到數據。
    若此時恰好有使用事件時間的Flink應用消費了該Topic,那麼可能會導致問題;
    • 導致問題的原因
      • Flink_Kafka爲了利用Kafka各個分區的保序性特徵,分配器會在每個分區上定義水位線,然後再對各個分區之間的水位線進行合併。
      • 因此,如果某一分區變成非活躍狀態且不再提供消息,那麼這個數據源任務的水位線將無法前進,繼而導致整個應用的水位線都不會前進。因此單個非活躍的分區會導致整個應用停止運行。

示例:Flink自定義kakfa輸出分區

object addSink_kafka_並自定義序列化和分區 extends App {

  import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment

  val streamLocal = StreamExecutionEnvironment.createLocalEnvironment(3)

  import org.apache.flink.api.scala._ //如果數據是有限的(靜態數據集)可以引入這個包
  val dataStream: DataStream[(String, Int)] = streamLocal.fromElements(("flink_er", 3), ("f", 1), ("c", 2), ("c", 1), ("d", 5))

  val properties = new Properties()
  properties.setProperty("bootstrap.servers", "master:9092")
  val flinkKafkaProducer = new FlinkKafkaProducer(
    "ceshi01",
    new MySchema(),
    properties,
    Optional.of(new FlinkKafkaPartitioner[(String, Int)] {
      /**
        * @param record      正常的記錄
        * @param key         KeyedSerializationSchema中配置的key
        * @param value       KeyedSerializationSchema中配置的value
        * @param targetTopic targetTopic
        * @param partitions  partition列表[0, 1, 2, 3, 4]
        * @return partition
        */
      override def partition(record: (String, Int), key: Array[Byte], value: Array[Byte], targetTopic: String, partitions: Array[Int]): Int = {
        Math.abs(new String(key).hashCode() % partitions.length)
      }
    })
  )
  dataStream.addSink(flinkKafkaProducer)

  streamLocal.execute()
}

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