Flink流处理

本文详细介绍了Flink流处理的基本概念,包括DataSource、Transformation、Sink和Window操作。讲解了如何创建各种数据源,如基于集合、文件、网络套接字及自定义数据源,特别是如何从Kafka和MySQL获取数据。还深入讨论了DataStream的Transformation,如keyBy、Connect、split和select。同时,阐述了Flink的水印机制及其在解决网络延迟问题中的作用。
摘要由CSDN通过智能技术生成

Flink流处理

1. 输入数据集DataSource

Flink 中可以使用 StreamExecutionEnvironment.getExecutionEnvironment创建流处理的执行环境。

Flink 中可以使用 StreamExecutionEnvironment.addSource(source) 来为程序添加数据来源。

Flink 已经提供了若干实现好了的 source functions,当然也可以通过实现 SourceFunction来自定义非并行的source或者实现 ParallelSourceFunction 接口或者扩展 RichParallelSourceFunction 来自定义并行的 source。

Flink在流处理上的source和在批处理上的source基本一致。大致有4大类:

  • 基于本地集合的source(Collection-based-source)

  • 基于文件的source(File-based-source)- 读取文本文件,即符合 TextInputFormat 规范的文件,并将其作为字符串返回

  • 基于网络套接字的source(Socket-based-source)- 从 socket 读取。元素可以用分隔符切分。

  • 自定义的source(Custom-source)

1.1. 基于集合的source

//创建流处理的执行环境

val env = StreamExecutionEnvironment.getExecutionEnvironment

//使用env.fromElements()来创建数据源

val dataStream: DataStream[String] = env.fromElements(“spark”, “flink”)

import org.apache.flink.streaming.api.scala.{
   DataStream, StreamExecutionEnvironment}
import org.apache.flink.streaming.api.scala._
import scala.collection.immutable.{
   Queue, Stack}
import scala.collection.mutable
import scala.collection.mutable.{
   ArrayBuffer, ListBuffer}

object StreamingDemoFromCollectionSource {
   
  def main(args: Array[String]): Unit = {
   
    val senv = StreamExecutionEnvironment.getExecutionEnvironment
    //0.用element创建DataStream(fromElements)
    val ds0: DataStream[String] = senv.fromElements("spark", "flink")
    ds0.print()

    //1.用Tuple创建DataStream(fromElements)
    val ds1: DataStream[(Int, String)] = senv.fromElements((1, "spark"), (2, "flink"))
    ds1.print()

    //2.用Array创建DataStream
    val ds2: DataStream[String] = senv.fromCollection(Array("spark", "flink"))
    ds2.print()

    //3.用ArrayBuffer创建DataStream
    val ds3: DataStream[String] = senv.fromCollection(ArrayBuffer("spark", "flink"))
    ds3.print()

    //4.用List创建DataStream
    val ds4: DataStream[String] = senv.fromCollection(List("spark", "flink"))
    ds4.print()

    //5.用List创建DataStream
    val ds5: DataStream[String] = senv.fromCollection(ListBuffer("spark", "flink"))
    ds5.print()

    //6.用Vector创建DataStream
    val ds6: DataStream[String] = senv.fromCollection(Vector("spark", "flink"))
    ds6.print()

    //7.用Queue创建DataStream
    val ds7: DataStream[String] = senv.fromCollection(Queue("spark", "flink"))
    ds7.print()

    //8.用Stack创建DataStream
    val ds8: DataStream[String] = senv.fromCollection(Stack("spark", "flink"))
    ds8.print()

    //9.用Stream创建DataStream(Stream相当于lazy List,避免在中间过程中生成不必要的集合)
    val ds9: DataStream[String] = senv.fromCollection(Stream("spark", "flink"))
    ds9.print()

    //10.用Seq创建DataStream
    val ds10: DataStream[String] = senv.fromCollection(Seq("spark", "flink"))
    ds10.print()

    //11.用Set创建DataStream(不支持)
    //val ds11: DataStream[String] = senv.fromCollection(Set("spark", "flink"))
    //ds11.print()

    //12.用Iterable创建DataStream(不支持)
    //val ds12: DataStream[String] = senv.fromCollection(Iterable("spark", "flink"))
    //ds12.print()

    //13.用ArraySeq创建DataStream
    val ds13: DataStream[String] = senv.fromCollection(mutable.ArraySeq("spark", "flink"))
    ds13.print()

    //14.用ArrayStack创建DataStream
    val ds14: DataStream[String] = senv.fromCollection(mutable.ArrayStack("spark", "flink"))
    ds14.print()

    //15.用Map创建DataStream(不支持)
    //val ds15: DataStream[(Int, String)] = senv.fromCollection(Map(1 -> "spark", 2 -> "flink"))
    //ds15.print()

    //16.用Range创建DataStream
    val ds16: DataStream[Int] = senv.fromCollection(Range(1, 9))
    ds16.print()

    //17.用fromElements创建DataStream
    val ds17: DataStream[Long] = senv.generateSequence(1, 9)
    ds17.print()

    senv.execute(this.getClass.getName)
  }
}

1.2. 基于文件的source

Flink的流处理可以直接通过readTextFile()方法读取文件来创建数据源,方法如下:

object DataSource_CSV {
   
  def main(args: Array[String]): Unit = {
   
    // 1. 获取流处理运行环境
    val env = StreamExecutionEnvironment.getExecutionEnvironment
    // 2. 读取文件
    val textDataStream: DataStream[String] = env.readTextFile("hdfs://node01:8020/flink-datas/score.csv")
    // 3. 打印数据
    textDataStream.print()
    // 4. 执行程序
    env.execute()
  }
}

1.3. 基于网络套接字的source

上面两种方式创建的数据源一般都是固定的.如果需要源源不断的产生数据,可以使用socket的方式来获取数据,通过调用socketTextStream()方法

示例

编写Flink程序,接收socket的单词数据,并以空格进行单词拆分打印。

步骤

  1. 获取流处理运行环境

  2. 构建socket流数据源,并指定IP地址和端口号

  3. 对接收到的数据进行空格拆分

  4. 打印输出

  5. 启动执行

  6. 在Linux中,使用nc -lk 端口号监听端口,并发送单词

    **安装nc: ** yum install -y nc

    nc -lk 9999 监听9999端口的信息

代码

object SocketSource {
   
  def main(args: Array[String]): Unit = {
   
    //1. 获取流处理运行环境
    val env = StreamExecutionEnvironment.getExecutionEnvironment
    //  2. 构建socket流数据源,并指定IP地址和端口号
    // hadoop hadoop hive spark
    val socketDataStream: DataStream[String] = env.socketTextStream("node01", 9999)
    //  3. 转换,以空格拆分单词
    val mapDataSet: DataStream[String] = socketDataStream.flatMap(_.split(" "))
    //  4. 打印输出
    mapDataSet.print()
    //  5. 启动执行
    env.execute("WordCount_Stream")
  }
}

1.4. 自定义source

我们也可以通过去实现SourceFunction或者它的子类RichSourceFunction类来自定义实现一些自定义的source,Kafka创建source数据源类FlinkKafkaConsumer010也是采用类似的方式。

1.4.1. 自定义数据源

示例:

自定义数据源, 每1秒钟随机生成一条订单信息(订单ID用户ID订单金额时间戳)

要求:

  • 随机生成订单ID(UUID)

  • 随机生成用户ID(0-2)

  • 随机生成订单金额(0-100)

  • 时间戳为当前系统时间

开发步骤:

  1. 创建订单样例类

  2. 获取流处理环境

  3. 创建自定义数据源

    • 循环1000次
    • 随机构建订单信息
    • 上下文收集数据
    • 每隔一秒执行一次循环
  4. 打印数据

  5. 执行任务

代码:

object StreamFlinkSqlDemo {
   

  // 创建一个订单样例类Order,包含四个字段(订单ID、用户ID、订单金额、时间戳)
  case class Order(id: String, userId: Int, money: Long, createTime: Long)

  def main(args: Array[String]): Unit = {
   
    // 1. 获取流处理运行环境
    val env = StreamExecutionEnvironment.getExecutionEnvironment

    // 2. 创建一个自定义数据源
    val orderDataStream = env.addSource(new RichSourceFunction[Order] {
   
      override def run(ctx: SourceFunction.SourceContext[Order]): Unit = {
   
        // 使用for循环生成1000个订单
        for (i <- 0 until 1000) {
   
          // 随机生成订单ID(UUID)
          val id = UUID.randomUUID().toString
          // 随机生成用户ID(0-2)
          val userId = Random.nextInt(3)
          // 随机生成订单金额(0-100)
          val money = Random.nextInt(101
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值