Flink基础

本文详细介绍了Apache Flink的核心概念,包括有界流和无界流、状态管理和容错机制。深入探讨了Flink的时间语义、窗口与水印机制,以及JobManager和TaskManager在Flink架构中的角色。同时,文章还阐述了Flink的分布式缓存、故障恢复策略、并行度管理和不同类型窗口的使用场景。此外,还提到了Flink状态的分类及其存储方式,如Keyed State和Operator State,以及不同StateBackend的特点。
摘要由CSDN通过智能技术生成

Flink核心概念

概念

  • Streams:可分为有界流无界流
  • State:状态指的是在进行流式计算中的信息。一般用于容错和持久化,流式计算本质上是增量计算,需要不断地查询过去的状态。并且状态的持久化也是集群出现Fail-over的情况下自动重启的前提条件。
  • Time:支持Event Time、Processing Time、Ingestion Time语义,时间是判断业务状态是否滞后和延迟的重要依据
  • API:Flink提供了不同级别的抽象来支持流式或批处理程序的开发,由上而下可分为SQL/Table API、DataStream/DataSet API、ProcessFunction

特性

  • 批流一体
  • Exactly-Once语义
  • 高效的状态管理
  • 多种时间语义

Flink架构模型

在这里插入图片描述

  • JobManager:它扮演的是集群管理者的角色,负责调度任务、协调 checkpoints、协调故障恢复、收集 Job 的状态信息,并管理 Flink 集群中的从节点 TaskManager
  • TaskManager:实际负责执行计算的 Worker,在其上执行 Flink Job 的一组 Task;TaskManager 还是所在节点的管理员,它负责把该节点上的服务器信息比如内存、磁盘、任务运行情况等向 JobManager 汇报
  • Client:用户在提交编写好的 Flink 工程时,会先创建一个客户端再进行提交,这个客户端就是 Client,Client 会根据用户传入的参数选择使用 yarn per job 模式、stand-alone 模式还是 yarn-session 模式将 Flink 程序提交到集群

Flink分层模型

在这里插入图片描述

  • DataSet:Source部分来源于文件、表或者Java集合

  • DataStream:Source部分一般来源于消息中间件(Kafka)

  • Table/SQl:为简化计算模型设计的一套符合SQL语义的开发语言

聚合函数min和minBy的区别(同max和maxBy):

min和minBy都会返回整个元素,只是min会根据用户指定的字段取最小值,并且把这个值保存在对应的位置,而对于其它字段,并不能保证其数值正确。min会返回指定字段的最大值(只返回指定字段),minBy会返回对应的元素(包括其他字段)

Flink常见核心概念

  • 分布式缓存:目的是为了在分布式环境中让每一个TaskManager节点保存一份相同的数据或者文件,当前计算节点的task就像读取本地文件一样拉取这些配置

分布式缓存开发步骤:

  1. 首先需要在 env 环境中注册一个文件,该文件可以来源于本地,也可以来源于 HDFS ,并且为该文件取一个名字(env.registerCacheFile(“xxxxx”))
  2. 在使用分布式缓存时,可在具体的算子中,根据注册的名字直接获取( getRuntimeContext().getDistributedCache().getFile(“xxx”))
  • 故障恢复:支持两种策略(full和region)
  • 重启策略:
    • 固定延迟重启:配置重试次数和重试间隔
    • 失败率重启:配置重试间隔、计算失败率时间间隔、最大失败次数
    • 无重启:直接退出
  • 并行度:在分布式环境中,一个算子任务被切分成多少个子任务并行执行。算子>执行环境>提交任务>系统配置

注:在实际生产环境中由于每个任务的负载和资源消耗不一样,推荐在代码中指定每个任务的重试机制和重启策略

Flink窗口、时间和水印

窗口

  • 滚动窗口:窗口数据由固定大小,窗口的数据不会叠加
  • 滑动窗口:窗口数据由固定大小,并且有生成间隔
  • 会话窗口:窗口数据没有固定大小,根据用户传入的参数进行划分,窗口数据无叠加

时间

在这里插入图片描述

  • Event Time:时间实际发生的时间;每条数据都携带时间戳
  • Ingestion Time:事件进入流处理框架的时间;Flink会使用系统时间作为时间戳绑定到每条数据中,防止内部处理时发生乱序的情况,但无法解决数据到达Flink之前就发生了乱序的问题
  • Processing Time:事件被处理的时间;数据不携带任何时间戳信息

水印(WaterMark)

水印本质是为了解决数据乱序的问题,本质是 DataStream 中一个带有时间戳的元素。如果 Flink 系统中出现了一个 WaterMark T,那么就意味着 EventTime < T 的数据都已经到达,窗口的结束时间和 T 相同的那个窗口被触发进行计算了。水印是 Flink 判断迟到数据的标准,同时也是窗口触发的标记

水印的种类

  1. 周期性水印(AssignerWithPeriodicWatermarks):一般使用该方式生成,周期默认时200ms,有三种提取Event Time的方式:
    1. AscendingTimestampExtractor:数据时间戳时升序的,如果有数据升序中有小于当前时间戳的事件,则该事件会丢失,丢失的数据可以通过sideOutputLateData获取到。
    2. BoundedOutOfOrdernessTimestampExtractor:适用于无序的,指定相应的延迟时间。
    3. IngestionTimeExtractor:当时间特性指定为Ingestion Time时,直接生成时间戳和获取水印。
  2. PunctuatedWatermarks:Flink中没有内置实现,适用于根据接收到的消息判读是否需要产生水印的情况

Flink状态和容错

状态指的是Flink程序的中间计算结果,这些结果包括业务数据、元数据。

适用于状态计算的情况:

  1. 复杂事件处理获取符合某一特定时间规则的事件(CEP)
  2. 聚合计算
  3. 机器学习的模型训练
  4. 使用历史数据进行计算

状态的分类

在这里插入图片描述

  • Keyed State:每个key都有自己的状态,并且只有指定的key才能访问和更新自己对应的状态。
  • Operator State:作用于所有的算子上,每个算子共享一个状态,流入这个算子的数据可以访问和更新这个状态。一般用于保存流入数据的偏移量或者对输出数据做缓存。

并行度发生变化时,对应state的变化情况:

  • Keyed State:该类型的数据会自动跟着key的分配,随着并行度的改变而改变。
  • Operator State:有两种分配方式
    • 均匀分配
    • 将所有状态合并,再分发到各个实例上

状态的存储

  • MemoryStateBackend:存储在内存中,一般用于测试。
  • FsStateBackend:状态数据存储在TaskManager的内存中,CheckPoint时,将状态快照写入到配置的文件系统中。
  • RocksDBStateBackend:状态数据保存在RocksDB数据库中,可指定RocksDB数据库的文件目录,是目前唯一支持增量快照的状态后端存储。

Flink分流

  • 使用filter方式分流:弊端是多次遍历原始流
  • 使用split方式分流:弊端是不能进行二次split
  • SideOutPut分流:推荐使用,可进行多次流的切分
// SideOutPut示例:
public static void main(String[] args) throws Exception {

    StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
    //获取数据源
    List data = new ArrayList<Tuple3<Integer,Integer,Integer>>();
    data.add(new Tuple3<>(0,1,0));
    data.add(new Tuple3<>(0,1,1));
    data.add(new Tuple3<>(0,2,2));
    data.add(new Tuple3<>(0,1,3));
    data.add(new Tuple3<>(1,2,5));
    data.add(new Tuple3<>(1,2,9));
    data.add(new Tuple3<>(1,2,11));
    data.add(new Tuple3<>(1,2,13));


    DataStreamSource<Tuple3<Integer,Integer,Integer>> items = env.fromCollection(data);

    OutputTag<Tuple3<Integer,Integer,Integer>> zeroStream = new OutputTag<Tuple3<Integer,Integer,Integer>>("zeroStream") {};
    OutputTag<Tuple3<Integer,Integer,Integer>> oneStream = new OutputTag<Tuple3<Integer,Integer,Integer>>("oneStream") {};


    SingleOutputStreamOperator<Tuple3<Integer, Integer, Integer>> processStream= items.process(new ProcessFunction<Tuple3<Integer, Integer, Integer>, Tuple3<Integer, Integer, Integer>>() {
        @Override
        public void processElement(Tuple3<Integer, Integer, Integer> value, Context ctx, Collector<Tuple3<Integer, Integer, Integer>> out) throws Exception {

            if (value.f0 == 0) {
                ctx.output(zeroStream, value);
            } else if (value.f0 == 1) {
                ctx.output(oneStream, value);
            }
        }
    });

    DataStream<Tuple3<Integer, Integer, Integer>> zeroSideOutput = processStream.getSideOutput(zeroStream);
    DataStream<Tuple3<Integer, Integer, Integer>> oneSideOutput = processStream.getSideOutput(oneStream);

    zeroSideOutput.print();
    oneSideOutput.printToErr();

    //打印结果
    String jobName = "user defined streaming source";
    env.execute(jobName);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值