3. Flink基础概念

在工业实时数据处理场景中,Flink 之所以能够稳定承接高吞吐、低延迟的数据计算任务,核心在于它围绕“事件驱动”和“分布式并行执行”建立了一套清晰的概念体系。理解事件、流、算子、作业,以及 JobManager、TaskManager、Slot 与并行度之间的关系,是后续编写、调优和排障 Flink 应用的基础。

一、事件与流:Flink 处理的数据对象

事件(Event)是 Flink 处理的最小数据单位。在工业场景中,一个事件可以是一条传感器采集记录、一次设备告警、一笔订单状态变更,或者一条 PLC 点位采样值。事件通常包含数据本身以及时间信息,例如事件时间、摄取时间或处理时间。

流(Stream)是事件的连续序列。流可以是无界的,例如设备持续上报的实时数据;也可以是有界的,例如从历史数据库中读取的一批记录。Flink 将无界流和有界流统一抽象为 DataStream,因此同一套 API 既能处理实时数据,也能处理离线批数据。

在工业现场,事件往往带有明显的时序特征。例如温度传感器每 100ms 上报一次数据,这些事件按时间顺序进入 Flink,形成一条持续增长的数据流。Flink 通过水位线机制处理乱序事件,保证窗口计算结果的正确性。

二、算子与作业:从逻辑计算到物理执行

算子(Operator)是 Flink 中执行计算逻辑的基本单元。常见算子包括 map、filter、keyBy、window、reduce、aggregate、join、sink 等。每个算子对输入流进行转换,并产生新的输出流。例如,map 算子可以将原始 JSON 字符串解析为对象,filter 算子可以过滤掉无效数据,keyBy 算子可以按设备 ID 分组。

作业(Job)是由多个算子组成的有向无环图(DAG)。当用户提交一个 Flink 程序时,Flink 会将算子连接成 JobGraph,再进一步转换为 ExecutionGraph,最终在集群中分布式执行。一个作业可以包含多个算子链,算子链将多个算子合并到同一个任务中,减少线程间切换和序列化开销。

核心关系:事件组成流,流经过算子转换,多个算子构成作业,作业由 JobManager 调度、TaskManager 执行。

三、JobManager 与 TaskManager:集群中的两类角色

Flink 运行时采用主从架构,主要包含两类进程:JobManager 和 TaskManager。

JobManager 是作业的管理者,负责接收客户端提交的作业、生成执行计划、调度任务、协调检查点与故障恢复。在 HA 模式下,JobManager 可以有多个实例,通过 ZooKeeper 或 Kubernetes 选主实现高可用。JobManager 不直接处理数据,而是负责“指挥”。

TaskManager 是作业的执行者,负责实际运行任务、处理数据流、进行网络传输和状态存储。每个 TaskManager 是一个 JVM 进程,内部可以运行多个任务。TaskManager 将自己拥有的 Slot 资源注册到 ResourceManager,由 JobManager 统一分配。

角色主要职责是否处理数据典型数量
JobManager作业调度、检查点协调、故障恢复否1 个或 HA 下多个
TaskManager执行任务、数据处理、状态存储是多个
SlotTaskManager 上的资源单元承载任务每个 TM 多个

四、Slot 与并行度:资源分配与并行执行

Slot 是 TaskManager 上的资源分配单元。每个 TaskManager 可以配置一个或多个 Slot,每个 Slot 能够运行一个任务链。Slot 并不等同于 CPU 核数,而是 Flink 对内存、线程等资源的逻辑划分。通过 Slot 共享机制,同一个作业的不同任务可以共享同一个 Slot,从而提高资源利用率。

并行度(Parallelism)是指一个算子或整个作业被拆分成多少个并行实例执行。例如,一个 map 算子的并行度为 4,意味着有 4 个并行的 map 任务同时处理数据。并行度决定了作业的吞吐能力,但也受限于可用 Slot 数量。

# 在 flink-conf.yaml 中设置默认并行度
parallelism.default: 4

# 每个 TaskManager 提供 4 个 Slot
taskmanager.numberOfTaskSlots: 4

# 提交作业时指定并行度
flink run -p 8 -c com.example.IndustrialJob industrial-job.jar

并行度与 Slot 的关系可以这样理解:如果作业总并行度为 8,每个 TaskManager 有 4 个 Slot,那么至少需要 2 个 TaskManager 才能提供足够的 Slot 来运行该作业。如果 Slot 不足,作业会处于等待资源状态,无法启动。

Flink 作业执行与资源关系 事件 Event 传感器 / 告警 / 订单 带时间戳的数据记录 流 Stream 无界 / 有界事件序列 DataStream 抽象 算子 Operator map / filter / keyBy window / reduce / sink 组成 DAG 作业 Job JobGraph → ExecutionGraph JobManager 作业调度 / 检查点协调 故障恢复 / 资源申请 不直接处理数据 TaskManager 执行任务 / 数据处理 / 状态存储 Slot 1 Slot 2 Slot 3 Slot 4(可扩展) 并行度 Parallelism 算子被拆分为多个并行实例 并行度 ≤ 可用 Slot 总数 决定吞吐与资源占用 Slot 共享 同一作业不同任务可共享 Slot 提高资源利用率 避免资源碎片化 Slot 数 ≠ CPU 核数 资源不足时 作业等待 Slot 状态:SCHEDULED / CREATED 需扩容 TaskManager 或调低并行度

五、案例场景:工业设备温度监控作业

假设某工厂需要实时监控 1000 台设备的温度数据。每台设备每 200ms 上报一次温度事件,Flink 作业需要过滤异常高温、按设备分组、计算 1 分钟滑动平均温度,并将结果写入告警系统。

该作业的并行度可以设置为 8:source 算子并行度为 8,map 和 filter 算子并行度为 8,keyBy 之后 window 和 aggregate 算子并行度也为 8。如果每个 TaskManager 配置 4 个 Slot,则需要至少 2 个 TaskManager 来提供 8 个 Slot。JobManager 负责将 8 个并行任务分配到这些 Slot 中执行。

DataStream<SensorEvent> stream = env
    .addSource(new SensorSource())
    .setParallelism(8);

stream
    .filter(e -> e.getTemperature() > 80)
    .keyBy(SensorEvent::getDeviceId)
    .window(SlidingEventTimeWindows.of(Time.minutes(1), Time.seconds(10)))
    .aggregate(new AvgTemperatureAggregate())
    .setParallelism(8)
    .addSink(new AlertSink());

六、常见误区与复盘

  • 误区一:并行度越高越好。并行度过高会导致 Slot 竞争、网络传输增加、状态后端压力增大,反而降低吞吐。应根据数据量、算子复杂度和集群资源综合评估。
  • 误区二:Slot 数等于 CPU 核数。Slot 是逻辑资源单元,一个 Slot 可以运行多个算子链,Slot 数应根据内存和任务负载配置,而不是简单等同于 CPU 核数。
  • 误区三:JobManager 负责数据处理。JobManager 只负责调度和协调,真正处理数据的是 TaskManager。如果 TaskManager 资源不足,作业会卡在等待资源状态。
  • 误区四:算子并行度必须一致。不同算子可以设置不同并行度,例如 source 并行度可以高于 sink 并行度,但需要注意数据倾斜和反压问题。

排障提示:当作业长时间处于 SCHEDULED 状态时,优先检查可用 Slot 总数是否小于作业所需并行度;当作业出现反压时,优先检查高并行度算子是否存在数据倾斜或状态过大问题。

掌握事件、流、算子、作业、JobManager、TaskManager、Slot 与并行度之间的关系,就能够在工业实时数据处理中合理设计作业结构、分配集群资源,并为后续的容错、状态管理和性能调优打下坚实基础。