flink学习(四)

学习目标

1.Time与window
2.EventTime与window
3.Flink的容错(checkpoint)
4.Flink的状态管理 state

1.Time与window

1.1Time

Event Time: 数据产生的时间
Ingestion Time: 是数据进入 Flink 的时间。
Processing Time :算子操作使用的时间

1.2window

Window 可以分成两类:

  1. CountWindow: 按照指定的数据条数生成一个 Window, 与时间无关。
  2. TimeWindow: 按照时间生成 Window。

滚动窗口( Tumbling Window)

将数据依据固定的窗口长度对数据进行切片。
特点: 时间对齐, 窗口长度固定, 没有重叠 。

滑动窗口( Sliding Window)

滑动窗口是固定窗口的更广义的一种形式, 滑动窗口由固定的窗口长度和滑动间隔组成。
特点: 时间对齐, 窗口长度固定, 有重叠。
分为三种情况:
窗口大小>滑动距离 =====》有重叠,重复消费数据
窗口大小=滑动距离 =====》没有重复,不重叠,也不丢失
窗口大小<滑动距离 =====》丢失数据

会话窗口( Session Window)

由一系列事件组合一个指定时间长度的 timeout 间隙组成, 类似于 web 应用的 session,
也 就是一段时间没有接收到新数据就会生成新的窗口。
特点: 时间无对齐。

Window API
CountWindow案例

package com.czxy.flink.stream.window

import org.apache.flink.streaming.api.scala.{DataStream, KeyedStream, StreamExecutionEnvironment, WindowedStream}
import org.apache.flink.streaming.api.windowing.windows.GlobalWindow

/**
 * 思路步骤:
 * 1.获取执行环境
 * 2.创建 SocketSource
 * 3.对 stream 进行处理并按 key 聚合
 * 4.countWindow 操作
 * 5.执行聚合操作
 * 6.将聚合数据输出
 * 7.执行程序
 */
object StreamCountWindow {
  def main(args: Array[String]): Unit = {
    //1.创建执行环境
    val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment

    //2.构建数据源,创建 SocketSource
    val socketSource: DataStream[String] = env.socketTextStream("node01",9999)

    //3.对 stream 进行处理并按 key 聚合
    import org.apache.flink.api.scala._
    val groupKeyedStream: KeyedStream[(String, Int), String] = socketSource.flatMap(x=>x.split(" ")).map((_,1)).keyBy(_._1)

    //4.引入countWindow 操作,每5条数据计算一次
    val countWindowStream: WindowedStream[(String, Int), String, GlobalWindow] = groupKeyedStream.countWindow(5)

    //5.执行聚合操作
    val resultDataStream: DataStream[(String, Int)] = countWindowStream.sum(1)

    //6.将聚合数据输出
    resultDataStream.print()

    //7.执行程序
    env.execute("StreamCountWindow")
  }

}

TimeWindow案例

package com.czxy.flink.stream.window

import org.apache.flink.streaming.api.scala.{DataStream, KeyedStream, StreamExecutionEnvironment, WindowedStream}
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.api.windowing.windows.TimeWindow

/**
 * 思路步骤:
 * 1.获取执行环境
 * 2.创建你 socket 链接获取数据
 * 3.进行数据转换处理并按 key 聚合
 * 4.引入 timeWindow
 * 5.执行聚合操作
 * 6.输出打印数据
 * 7.执行程序
 */
object StreamTimeWindow {
  def main(args: Array[String]): Unit = {
    //1.获取执行环境
    val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
    //2.创建你 socket 链接获取数据
    val socketSource = env.socketTextStream("node01",9999)
    //3.进行数据转换处理并按 key 聚合
    import org.apache.flink.api.scala._
    val groupKeyedStream: KeyedStream[(String, Int), String] = socketSource.flatMap(x=>x.split(" ")).map((_,1)).keyBy(_._1)
    //4.引入 滚动窗口timeWindow,每3秒钟计算一次
    //val timeWindowStream: WindowedStream[(String, Int), String, TimeWindow] = groupKeyedStream.timeWindow(Time.seconds(3))
    //4.引入 滑动窗口timeWindow,窗口大小为10秒,滑动距离为5秒=>重复消费
    val timeWindowStream: WindowedStream[(String, Int), String, TimeWindow] = groupKeyedStream.timeWindow(Time.seconds(10),Time.seconds(5))
    //5.执行聚合操作
    val result: DataStream[(String, Int)] = timeWindowStream.sum(1)
    //6.打印输出
    result.print()
    //7.执行程序
    env.execute("StreamTimeWindow")
  }
}

SreamReduceWindow案例

package com.czxy.flink.stream.window

import org.apache.flink.streaming.api.scala.{DataStream, StreamExecutionEnvironment, WindowedStream}
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.api.windowing.windows.TimeWindow

object StreamReduceWindow {
  def main(args: Array[String]): Unit = {
    //1.获取执行环境
    val env = StreamExecutionEnvironment.getExecutionEnvironment
    //2.构建数据集
    val socketSource = env.socketTextStream("node01",9999)
    //3.分组
    import org.apache.flink.api.scala._
    val group = socketSource.flatMap(x=>x.split(" ")).map((_,1)).keyBy(_._1)

    //4.引入窗口timeWindow
    val timeWindow: WindowedStream[(String, Int), String, TimeWindow] = group.timeWindow(Time.seconds(5))

    //5.聚合操作
    val result: DataStream[(String, Int)] = timeWindow.reduce((v1, v2)=>(v1._1,v1._2+v2._2))

    //6.输出打印
    result.print()
    //7.执行程序
    env.execute()

  }
}

Window Apply案例

package com.czxy.flink.stream.window

import org.apache.flink.streaming.api.scala.function.RichWindowFunction
import org.apache.flink.streaming.api.scala.{DataStream, KeyedStream, StreamExecutionEnvironment, WindowedStream}
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.api.windowing.windows.TimeWindow
import org.apache.flink.util.Collector

//使用 apply 方法来实现单词统计
object StreamApplyWindow {
  def main(args: Array[String]): Unit = {
    /**
     * 思路步骤:
     * 1) 获取流处理运行环境
     * 2) 构建 socket 流数据源, 并指定 IP 地址和端口号
     * 3) 对接收到的数据转换成单词元组
     * 4) 使用 keyBy 进行分流( 分组)
     * 5) 使用 timeWindow 指定窗口的长度( 每 3 秒计算一次)
     * 6) 实现一个 WindowFunction 匿名内部类
     * a. apply 方法中实现聚合计算
     * b. 使用 Collector.collect 收集数据
     * 7) 打印输出
     * 8) 启动执行
     * 9) 在 Linux 中, 使用 nc -lk 端口号 监听端口, 并发送单词
     */

    //1.获取流处理运行环境
    val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
    //2. 构建 socket 流数据源, 并指定 IP 地址和端口号
    val socketSource: DataStream[String] = env.socketTextStream("node01",9999)
    //3.对接收到的数据转换成单词元组
    import org.apache.flink.api.scala._
    val wordAndOne: DataStream[(String, Int)] = socketSource.flatMap(x=>x.split(" ")).map((_,1))
    //4.使用 keyBy 进行分流( 分组)
    val groupKeyedStream: KeyedStream[(String, Int), String] = wordAndOne.keyBy(_._1)
    //5.使用 timeWindow 指定窗口的长度( 每 3 秒计算一次)
    val timeWindow: WindowedStream[(String, Int), String, TimeWindow] = groupKeyedStream.timeWindow(Time.seconds(3))
    //6.实现一个 WindowFunction 匿名内部类
    val result: DataStream[(String, Int)] = timeWindow.apply(new RichWindowFunction[(String, Int), (String, Int), String, TimeWindow] {
      override def apply(key: String, window: TimeWindow, input: Iterable[(String, Int)], out: Collector[(String, Int)]): Unit = {
        //apply 方法中实现聚合计算
        val tuple: (String, Int) = input.reduce((v1, v2) => (v1._1, v1._2 + v2._2))
        //使用 Collector.collect 收集数据
        out.collect(tuple)
      }
    })
    //7.打印输出
    result.print()
    //8.执行程序
    env.execute("StreamApplyWindow")
  }
}

StreamAggregationWindow案例

package com.czxy.flink.stream.window

import org.apache.flink.streaming.api.scala.{DataStream, KeyedStream, StreamExecutionEnvironment, WindowedStream}
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.api.windowing.windows.TimeWindow

object StreamAggregationWindow {
  def main(args: Array[String]): Unit = {
    //1.获取流处理运行环境
    val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
    //2. 构建 socket 流数据源, 并指定 IP 地址和端口号
    val socketSource: DataStream[String] = env.socketTextStream("node01",9999)
    //3.对接收到的数据转换成单词元组
    import org.apache.flink.api.scala._
    val wordAndOne: DataStream[(String, Int)] = socketSource.flatMap(x=>x.split(" ")).map((_,1))
    //4.使用 keyBy 进行分流( 分组)
    val groupKeyedStream: KeyedStream[(String, Int), String] = wordAndOne.keyBy(_._1)
    //5.使用 timeWindow 指定窗口的长度( 每 3 秒计算一次)
    val timeWindow: WindowedStream[(String, Int), String, TimeWindow] = groupKeyedStream.timeWindow(Time.seconds(3))
    //6.执行聚合操作
    val result: DataStream[(String, Int)] = timeWindow.max(1)
    //7.打印输出
    result.print()
    //8.执行程序
    env.execute(this.getClass.getSimpleName)

  }
}

2.EventTime 与 Window

2.1EventTime 的引入
如果要使用 EventTime, 那么需要引入 EventTime 的时间属性

在这里插入代码片val env = StreamExecutionEnvironment.getExecutionEnvironment
// 从调用时刻开始给 env 创建的每一个 stream 追加时间特征
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTim

2.2 Watermark
Watermark 是用于处理乱序事件的, 而正确的处理乱序事件, 通常用 Watermark 机制结合 window 来实现 。

2.3EventTimeWindow API

滚动窗口

package com.czxy.flink.stream.waterwindow

import org.apache.flink.streaming.api.TimeCharacteristic
import org.apache.flink.streaming.api.functions.timestamps.BoundedOutOfOrdernessTimestampExtractor
import org.apache.flink.streaming.api.scala.{DataStream, KeyedStream, StreamExecutionEnvironment, WindowedStream}
import org.apache.flink.streaming.api.windowing.assigners.TumblingEventTimeWindows
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.api.windowing.windows.TimeWindow

object TumblingEventTimeWindowsDemo {
  def main(args: Array[String]): Unit = {
    /**
     * 步骤:
     * 1.创建流处理环境
     * 2.设置EventTime
     * 3.构建数据源
     * 4.设置水印
     * 5.逻辑处理
     * 6.引入滚动窗口TumblingEventTimeWindows
     * 7.聚合操作
     * 8.输出打印
     * 9.执行程序
     */
    //1.创建流处理环境
    val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
    //2.设置EventTime
    env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)
    //3.构建数据源
    //数据格式: 1000 hello
    val socketSource = env.socketTextStream("node01",9999)
    //4.设置水印
    val waterMark: DataStream[String] = socketSource.assignTimestampsAndWatermarks(new BoundedOutOfOrdernessTimestampExtractor[String](Time.seconds(0)) {
      override def extractTimestamp(element: String): Long = {
        val eventTime: Long = element.split(" ")(0).toLong
        eventTime
      }
    })
    //5.逻辑处理
    import org.apache.flink.api.scala._
    val groupStream: KeyedStream[(String, Int), String] = waterMark.map(x=>x.split(" ")(1)).map((_,1)).keyBy(_._1)
    //6.引入滚动窗口TumblingEventTimeWindows
    val windowStream: WindowedStream[(String, Int), String, TimeWindow] = groupStream.window(TumblingEventTimeWindows.of(Time.seconds(3)))
    //7.聚合操作
    val result: DataStream[(String, Int)] = windowStream.sum(1)
    //8.输出打印
    result.print()
    //9.执行程序
    env.execute(this.getClass.getSimpleName)
  }
}

滑动窗口

package com.czxy.flink.stream.waterwindow

import org.apache.flink.streaming.api.TimeCharacteristic
import org.apache.flink.streaming.api.functions.timestamps.BoundedOutOfOrdernessTimestampExtractor
import org.apache.flink.streaming.api.scala.{DataStream, KeyedStream, StreamExecutionEnvironment, WindowedStream}
import org.apache.flink.streaming.api.windowing.assigners.SlidingEventTimeWindows
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.api.windowing.windows.TimeWindow

object SlidingEventTimeWindowsDemo {
  def main(args: Array[String]): Unit = {
    /** * 步骤:
     * 1.创建流处理环境
     * 2.设置EventTime
     * 3.构建数据源
     * 4.设置水印
     * 5.逻辑处理
     * 6.引入滑动窗口SlidingEventTimeWindows
     * 7.聚合操作
     * 8.输出打印
     * 9.执行程序
     */

    //1.创建流处理环境
    val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
    //2.设置EventTime
    env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)
    //3.构建数据源
    //数据格式为:1000 hello
    val socketSource: DataStream[String] = env.socketTextStream("node01", 9999)
    //4.设置水印
    val waterMark: DataStream[String] = socketSource.assignTimestampsAndWatermarks(new BoundedOutOfOrdernessTimestampExtractor[String](Time.seconds(0)) {
      override def extractTimestamp(element: String): Long = {
        val eventTime: Long = element.split(" ")(0).toLong
        eventTime
      }
    })
    //5.逻辑处理
    import org.apache.flink.api.scala._
    val groupStream: KeyedStream[(String, Int), String] = waterMark.map(x => x.split(" ")(1)).map((_, 1)).keyBy(_._1)
    //6.引入滑动窗口SlidingEventTimeWindows
    val windowStream: WindowedStream[(String, Int), String, TimeWindow] = groupStream.window(SlidingEventTimeWindows.of(Time.seconds(5), Time.seconds(2)))
    //7.聚合计算
    val result: DataStream[(String, Int)] = windowStream.sum(1)
    //8.打印输出
    result.print()
    env.execute(this.getClass.getSimpleName)

  }
}

会话窗口

package com.czxy.flink.stream.waterwindow

import org.apache.flink.streaming.api.TimeCharacteristic
import org.apache.flink.streaming.api.functions.timestamps.BoundedOutOfOrdernessTimestampExtractor
import org.apache.flink.streaming.api.scala.{DataStream, KeyedStream, StreamExecutionEnvironment, WindowedStream}
import org.apache.flink.streaming.api.windowing.assigners.EventTimeSessionWindows
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.api.windowing.windows.TimeWindow

object EventTimeSessionWindowsDemo {
  def main(args: Array[String]): Unit = {
    /**
     * 步骤:
     * 1.创建流处理环境
     * 2.设置EventTime
     * 3.构建数据源
     * 4.设置水印
     * 5.逻辑处理
     * 6.引入会话窗口EventTimeSessionWindows
     * 7.聚合操作
     * 8.输出打印
     */
    //1.创建流处理环境
    val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
    //2.设置EventTime
    env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)
    //3.构建数据源
    //数据格式为:1000 hello
    val socketSource: DataStream[String] = env.socketTextStream("node01", 9999)
    //4.设置水印
    val waterMark: DataStream[String] = socketSource.assignTimestampsAndWatermarks(new BoundedOutOfOrdernessTimestampExtractor[String](Time.seconds(0)) {
      override def extractTimestamp(element: String): Long = {
        val eventTime: Long = element.split(" ")(0).toLong
        eventTime
      }
    })
    //5.逻辑处理
    import org.apache.flink.api.scala._
    val groupStream: KeyedStream[(String, Int), String] = waterMark.map(x => x.split(" ")(1)).map((_, 1)).keyBy(_._1)
    //6.引入会话窗口EventTimeSessionWindows
    val windowStream: WindowedStream[(String, Int), String, TimeWindow] = groupStream.window(EventTimeSessionWindows.withGap(Time.seconds(3)))
    //7.聚合计算
    val result = windowStream.sum(1)
    //8.打印输出
    result.print()
    //9.执行程序
    env.execute("EventTimeSessionWindowsDemo")

  }
}

3.Flink 的容错checkpoint

3.1Checkpoint 介绍

  1. CheckpointCoordinator 周期性的向该流应用的所有 source 算子发送 barrier。
  2. 当某个 source 算子收到一个 barrier 时, 便暂停数据处理过程, 然后将自己的当前状态制作成快照, 并保存到指定的持久化存储中, 最后向CheckpointCoordinator 报告 自己快照制作情况, 同时向自身所有下游算子广播该 barrier, 恢复数据处理 。
  3. 下游算子收到 barrier 之后, 会暂停自己的数据处理过程, 然后将自身的相关状态制作成快照, 并保存到指定的持久化存储中, 最后向 CheckpointCoordinator 报告自身 快照情况, 同时向自身所有下游算子广播该 barrier, 恢复数据处理。
  4. 每个算子按照步骤 3 不断制作快照并向下游广播, 直到最后 barrier 传递到 sink 算子, 快照制作完成。
  5. 当 CheckpointCoordinator 收到所有算子的报告之后, 认为该周期的快照制作成功; 否则, 如果在规定的时间内没有收到所有算子的报告, 则认为本周期快照制作失败。如果一个算子有两个输入源, 则暂时阻塞先收到 barrier 的输入源, 等到第二个输入源相同编号的 barrier 到来时, 再制作自身快照并向下游广播该 barrier。

3.2持久化存储

3.2.1MemStateBackend(默认)
3.2.2FsStateBackend(建议使用)
3.2.3RocksDBStateBackend

3.3Checkpoint 的高级选项

3.4Flink 的重启策略

1.固定延迟重启策略(Fixed Delay Restart Strategy)
2.失败率重启策略
3.失败率重启策略

4.Flink 的状态管理

1.State-Keyed State
2.State-Operator State
3.Broadcast State

奥利给!下次是flink完结了!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值