Flink总结

Flink

数据处理架构

批处理

  • 事务性处理

    • 多应用共享一个数据库,数据库支持事务,一般都是单体
    • 更改数据库表模式和数据库扩缩容时费劲
  • 分析型处理

    • 通过ETL把数据导到数据仓库
    • 使用定期批处理任务生成报告或者即席查询分析数据

流处理

  • 有状态,支持存储中间结果
  • 支持事件型应用,事件流可能是一个无限的事件序列

基础概念

并行

  • 数据并行

    • 同一个算子的不同实例处理不同的数据,既算子的并行度
  • 任务并行

    • 不同算子本来是有先后顺序的,放在不同的机器上,实现流水线式的作业

数据交换策略

  • 算子间均有多个实例,那两种算子多对多实例间怎么传递数据

    • 转发

    • 基于键值

    • 随机

    • 广播

      • 前序的同一个数据会被后续的多个实例处理
  • api

    • shuffle

      • 随机,每个发送任何和所有下游任务都有通信
    • rebalance

      • 轮流,所有发送任务和接收任务之间都有通信
    • rescale

      • 轮流,每个发送任务只和部分下游任务有通信,更加轻量
    • global

      • 将当前算子所有任务发往下游的第一个任务,既归拢
    • broadcast

      • 广播,每个事件复制发送给下游所有任务

性能指标

  • 分类

    • 延迟

      • 一般定义为从接收时间到输出时间的间隔时间,不纠结内部各个算子的延迟,因为并行度等问题,不好描述

        • Flink内部通过一个自己生成特殊的延迟标记来模拟事件,实现监测
    • 吞吐

      • 系统每单位事件可以处理的数据量
  • 关系

    • 延迟越低,吞吐肯定越高

    • 吞吐高延迟不一定低,因为可能有网络IO之类的高延迟环节

    • 如果接收数据的速度大于吞吐,则会导致耗尽缓冲区,甚至可能丢失数据,这个叫做背压

    • 跨机器的传输采用TCP,每个任务都有自己收发数据的缓冲区,跟TCP链接一对一,所以在shffle和广播的交换策略下,缓冲区的数量可达到算子任务数的平方个

    • flink控制背压的方式是通过缓冲区和信用值,信用值既接收端沟通发送端的积压量信息,然后调节各个发送端下一轮的发送量,从而实现动态流量控制

      • 子主题 1

操作

  • 转换

    • 概念

      • 每个事件只处理一次
    • api

      • 作用于单个事件的基本转换,输入和输出都是dataStream

        • map

          • 单个事件的1对1
        • flatmap

          • 单个事件的1转n
        • fliter

          • 单个事件的1转0、1
      • 按key分的转换,dataSteam和keyedstream之间的互转

        • keyby

          • 逻辑上将单条流转成多条,注意只是逻辑上,靠的是通过多个keyed的算子状态来区分,但是物流上不论任务的缓冲区还是检查点什么的,都是一条流
          • keyby的方法很多,除了可以指定tuple、还可以直接用"."来获取结构体中的内容,还可以通过通配符来解析多个字段。
        • 滚动聚合的那些api

          • 将keyedStream中每个逻辑子流都聚合成一个单值,然后所有的逻辑子流单值连在一起就变成了一个dataStream
      • 单条流和多条流之间的转换

        • union

          • 物理上多条相同泛型的datastream合并成一条

            • 没有顺序保证,也不会去重
        • connect

          • 物理上多条不同泛型的datastream流合并成一条

            • 合并后的流还是针对每种类型的事件分别处理,唯一的好处是可以同时获得两条流的上下文信息,可以存储一些状态来做判断
        • split和select

          • union的逆操作
        • sideout

          • union的逆操作
    • 实现函数

      • 所有的实现函数必须都是可序列化的,因为Flink会使用java的序列化机制将函数发到对应的工作进程
      • 所有的函数都有对应的rich版本,就是有open和close方法
      • 所有的函数都有对应的底层版本,既process版本,可以获取对应的context和计时器
  • 滚动聚合

    • 概念

      • 合并事件和当前状态生成一个新的状态
      • 必须满足交换律和结合律,否则就对事件顺序有要求
      • 滚动聚合是将一个dataStream转换为一个单值
    • api

      • 系统自带

        • sum

        • min

        • max

        • minby

          • min是求最小值,minby是求最小值所对应的事件
        • maxby

      • reduce

        • 输入参数和状态类型一致
      • aggregate

        • 输入参数和状态类型可以不同,比reduce更灵活
  • 窗口

    • 概念

      • 收集并缓存多个事件来生成一个结果
      • keyed流上的窗口可以并行处理,但是最多也就是每个key一个线程,不能再分了
      • 非keyed的流只能单线程处理
    • 组件

      • 窗口分配器

        • 分类

          • 滚动窗口

            • 固定收集时间或者收集数量
          • 会话窗口

            • 固定间隔时间,不能根据数量
          • 滑动窗口

            • 维度可以是时间也可以是数量
            • 有收集长度、滑动偏移量两个参数
        • api

          • keyedStream

            • window()
          • 非keyedStream

            • windowAll()
      • 窗口函数

        • 全量聚合函数,会保存所有元素

          • processWindowFunction
        • 增量聚合函数,只保存聚合结果

          • reduceFunction

            • 输入和输出类型一致
          • aggregateFunction

            • 输入类型、中间类型、输出类型均可不同

代码

  • getExecutionEnvironment可以根据上下文环境的不同,获取本地或者远程执行环境
  • 只有在env.execute之后,系统才会触发程序执行

时间语义

  • 事件时间

    • 在靠近source的地方手动生成,否则在keyby等会导致乱序的算子后面生成的话,时间戳就混乱了

      • 水位线的生成

        • 每个任务的水位线由所有前置输入分区中最小的一个水位线决定

          • 如果有一个分区的水位线不涨了,则整个应用都停了
        • 水位线的传播永远都是广播形式

      • 迟到事件的处理

        • 可以设置延迟容忍度

          • 延迟容忍度内的迟到数据,每次来一个都会调用一次处理函数,超过了则直接丢弃
        • 可以sideOut迟到数据

  • 处理时间

    • 既机器时间
  • ingestion time 摄入时间

    • 相当于事件时间和处理时间的混合体,很少用

状态管理

  • 作用域

    • 算子状态

      • 概念

        • 作用于某个算子任务,不能被别的任务访问,无论该任务是否是来自同一个算子(注意广播状态也是访问的当前任务的算子状态,只是大家的状态是相同的值罢了)
        • 但是要注意,在并行度发生变化的时候,可能同一个算子的多个任务状态需要重新洗牌,这个时候就可能会需要把多个任务的算子状态发给同一个算子,不过这个过程对开发人员不感知
      • 三类原语

        • 列表状态
        • 联合列表状态
        • 广播状态
    • 键值分区状态

      • 概念

        • 一个任务中可能维护了多个键的分区,每个键的分区都有自己的状态实例
      • 三类原语

        • 单值状态
        • 列表状态
        • map状态
        • reducingState
        • aggregatingState
  • 结果保障

    • 至少一次

    • 至多一次

    • 精确一次

    • 端到端精确一次

      • source要求有重置读取能力

      • sink要求有幂等写或者事务写的能力

        • 幂等写

          • 重放过程中,可能只有一部分状态被重新覆盖,导致有一些先前写入的但是不再需要的状态残留,所以可能会有整体结果不一致的可能
        • 事务写

          • 最终结果一定是一致的,但是在提交前,结果对外不可见,所以延迟会高一些

            • WAL写前日志

              • 由flink提供,但是无法保证百分百精确一次,且有数据写入的波峰
            • 2PC

              • 需要sink本身支持,可以百分百精确一致,且没有数据写入波峰
  • 状态恢复

    • 检查点

      • 检查点的分隔符总是以广播形式发送
      • 每个任务在收接收分隔符时,会有一个分隔符对齐的过程,保证所有前置输入分区的检查点一致
      • 检查点是自动触发,但是不会自动保存
    • 保存点

      • 保存点是手动触发,但是会持久保存
  • 状态存储

    • 状态后端

      • 内存
      • 文件
      • rocksDb
    • 状态获取

      • 状态不是存在处理函数里,而是在context里,处理函数通过context获取对应实例的状态
      • 每个状态原语都有自己的状态描述符,里面包含了状态名称和类型,比如valueStateDescriptor

运行架构

数据流处理

  • flink

    • jobManager

      • 一个作业一个,主要负责协调
    • taskManager

      • 一个taskManager是一个进程,其中有多个slot,但每个slot不一定只有一个线程,slot是任务的概念,不是计算资源的概念

        • 一个TaskManager默认的slot数会等于机器CPU的线程数
      • 每个slot允许执行一个任务,一个算子的所有slot数既其并行度(taskManager数乘以每个taskManager上的slot数)

      • 一个任务可以是一个算子实例,也可以是因为任务链接连在一起的多个连续算子实例

        • 任务链接的前提条件是需要相邻的算子有相同的并行度
      • 一个taskManager中的任务可以是来自一个作业,也可以是来自不同作业

    • dispatcher

      • 多个作业共享,主要负责协调jobManager和clinet

集群管理

  • Yarn等

持久化

  • hdfs等

高可用

  • zookeeper

分支主题 3

上一篇:Linux与Xshell


下一篇:JVM诊断及工具笔记(1)使用arthas热更新代码