flink的架构
Apache Flink 是一个针对无界和有界数据流进行状态计算的开源分布式处理框架。它具有高吞吐、低延迟、精确一次(Exactly-Once)一致性保证以及高可用性等特点。
Flink 的架构设计非常优秀,主要采用 Master-Worker(主从)架构。下面从运行时架构、核心组件、任务执行图(Graph)以及核心机制四个维度来详细解析 Flink 的架构。
一、 Flink 运行时架构 (Runtime Architecture)
Flink 运行时主要由三个核心组件组成:Client(客户端)、JobManager(主节点/协调器) 和 TaskManager(从节点/执行器)。
+------------------+
| Client | (提交 JobGraph)
+--------+---------+
|
v
+--------------------------+--------------------------+
| JobManager | (Master 进程)
| +----------------+ +----------------+ +-------+ |
| | Dispatcher | | ResourceManager| |JobMaster| |
| +----------------+ +----------------+ +-------+ |
+--------------------------+--------------------------+
| (分配 Slot / 发送 Task)
v
+--------------------------+--------------------------+
| TaskManager | (Worker 进程)
| +-----------------------------------------------+ |
| | Task Slot 1 | Task Slot 2 | |
| | (Thread) | (Thread) | |
| +-----------------------------------------------+ |
+-----------------------------------------------------+
1. Client (客户端)
- 作用:Client 不是 Flink 运行时集群的一部分,而是用于准备和发送数据流(Dataflow)到 JobManager。
- 工作内容:它将用户编写的代码(如 Java/Scala)翻译成一个作业图(JobGraph),然后提交给 JobManager。
2. JobManager (Master 进程)
JobManager 是集群的控制中心,负责管理作业的执行和资源的分配。在 Flink 1.5 之后,JobManager 内部被重构为三个子组件:
- Dispatcher (分发器):
- 提供 REST 接口,接收 Client 提交的 JobGraph。
- 为每个新提交的作业启动一个新的
JobMaster。 - 提供 Flink Web UI,展示作业运行状态。
- ResourceManager (资源管理器):
- 负责管理集群中的资源(主要是 TaskManager 的 Task Slot)。
- 支持多种资源平台(YARN、Kubernetes、Mesos、Standalone)。
- 当 JobMaster 申请资源时,ResourceManager 会将空闲的 Slot 分配给它;如果资源不足,会向外部容器平台申请启动新的 TaskManager。
- JobMaster (作业管理器):
- 一个作业对应一个 JobMaster。
- 将 JobGraph 转换成可以并行执行的 ExecutionGraph(执行图)。
- 向 ResourceManager 申请执行任务所需的资源(Slots)。
- 分发任务到 TaskManager 执行,并监控任务的运行状态。
- 协调 Checkpoint(检查点)的创建。
3. TaskManager (Worker 进程)
TaskManager 是具体执行计算任务的节点。
- 作用:负责执行 JobMaster 分配的具体 Task,并进行数据流的传输和缓冲。
- Task Slot (任务槽):
- TaskManager 的资源(主要是内存)会被静态划分为一个或多个 Task Slot。
- Slot 是 Flink 资源分配的最小单位。
- 每个 Slot 代表 TaskManager 的一部分内存资源(注意:Slot 目前只隔离内存,不隔离 CPU)。
- 一个 Slot 中运行的是一个线程(Thread),可以运行一个或多个 Task(通过 Slot 共享机制)。
二、 Flink 的任务执行图 (Dataflow Graphs)
Flink 程序在提交和执行过程中,会经历四种不同阶段的图转换,这是 Flink 能够进行深度优化和高效调度的关键:
- StreamGraph (流图):根据用户编写的 API 代码直接生成的图,表达了拓扑结构。
- JobGraph (作业图):在 Client 端生成。它将可以合并的算子(Operators)链化(Chain)在一起(例如
map->filter可以合并成一个OperatorChain),减少了线程切换和序列化开销,降低延迟。 - ExecutionGraph (执行图):在 JobManager 中生成。它是 JobGraph 的并行化版本,将抽象的算子拆分成了具体的并行子任务(SubTasks)。
- Physical Graph (物理执行图):JobManager 调度任务到 TaskManager 上运行时的具体布局,不是一个具体的数据结构,而是运行时的状态。
三、 Flink 核心架构机制
Flink 之所以能成为新一代流处理霸主,得益于其独特的底层机制:
1. 状态管理 (State Management)
Flink 是一个有状态的流处理系统。
- 状态(State):计算过程中的中间结果(如聚合累加器、历史窗口数据)。
- 状态后端(State Backend):决定了状态如何存储和访问。
- HashMapStateBackend:状态存放在 TaskManager 的 JVM 堆内存中,读写极快,但受内存大小限制。
- EmbeddedRocksDBStateBackend:状态存放在本地 RocksDB 数据库中(属于堆外内存/磁盘),支持超大状态,但有序列化开销。
2. 容错机制 (Checkpointing & Chandy-Lamport)
Flink 实现了精确一次(Exactly-Once)的一致性语义,核心是其分布式快照算法:
- Checkpoint(检查点):Flink 会定期在数据流中插入 Barrier(屏障)。当 Barrier 流经算子时,算子会将当前的状态异步持久化到分布式存储(如 HDFS)中。
- 如果发生故障,Flink 会将整个作业重置到最近一次成功的 Checkpoint,并重新消费数据,确保结果不重复也不丢失。
3. 内存管理 (Memory Management)
Flink 没有完全依赖 JVM 的垃圾回收机制,而是自己管理内存:
- 它将内存划分为框架内存、任务内存、网络缓冲内存、托管内存(用于 RocksDB 或批处理排序)等。
- 通过序列化将对象存储在底层的
MemorySegment(字节数组)中,极大地减少了 JVM GC 的压力。
4. 时间语义与窗口 (Time & Window)
Flink 支持三种时间:
- Event Time (事件时间):事件实际发生的时间(最常用,最准确)。
- Ingestion Time (摄入时间):数据进入 Flink 的时间。
- Processing Time (处理时间):执行算子机器的系统时间。
- Watermark (水位线):用于衡量 Event Time 进展的机制,解决数据乱序和延迟到达的问题。
四、 Flink 部署模式 (Deployment Modes)
根据集群生命周期和资源隔离程度,Flink 支持三种部署模式:
- Application Mode (应用模式 - 推荐):
- Client 的
main()方法在 JobManager 上运行。 - 每个作业独占一个 Flink 集群,作业结束集群销毁。
- 优点:对客户端压力小,适合生产环境(尤其是 Kubernetes/YARN)。
- Client 的
- Per-Job Mode (单作业模式):
- Client 在本地解析 JobGraph,然后向资源框架申请一个专属 Flink 集群。
- 优点:资源隔离性好。
- Session Mode (会话模式):
- 预先启动一个 Flink 集群,多个作业共享这个集群的资源。
- 优点:作业启动快,适合运行执行时间短的小任务或测试。
总结
Flink 的架构设计以数据流(Streams)和状态(State)为核心。通过 JobManager 协调和 TaskManager 执行,利用 Task Slot 实现资源隔离,通过 Checkpoint 保证高可用,并借助 Operator Chaining 和自主内存管理实现极致的性能。这套架构让 Flink 能够完美胜任超大规模、超低延迟的实时数据处理场景。