Flink 四大基石:核心原理与实战速查

摘要

作为 Flink 实时开发的核心基础,Window、Time+Watermark、State、Checkpoint 被称为 Flink 的四大基石。掌握这四大核心知识,是从 Flink 基础使用走向实战开发的关键,本文将从核心概念、解决问题、高频 API、极简 Demo四个维度做体系化整理,打造一份可直接用于开发查阅的速查手册,所有案例均基于 Flink DataStream API 实现,保证简洁、可运行、易复用。

一、Window:流到批的桥梁

流处理的核心是处理无界流 ,而实际业务中需要对无界流做分段统计 (如每分钟订单量、每 5 秒接口请求数),Window 就是实现流到批切分 的核心组件,是 Flink 实现聚合计算的基础。

1. Window 解决的核心问题

  • 无界连续的数据流 ,按照指定的时间 / 数据量规则 切分为有界的数据集
  • 仅对每个有界数据集做聚合计算,实现流处理中的批量统计
  • 解决无界流无法直接做聚合的核心痛点

2. 核心窗口分类:滚动窗口、滑动窗口

|-----------------------|----------------------------|-------------------------------------|------------------------------------------------------|
| 窗口类型 | 核心区别 | 核心参数 | 典型应用场景 |
| 滚动窗口(Tumbling Window) | 窗口之间无重叠、无间隔 ,数据仅属于一个窗口 | 窗口大小(window size) | 固定周期的独立统计(如每分钟 UV、每小时订单总额) |
| 滑动窗口(Sliding Window) | 窗口之间有重叠 ,数据可属于多个窗口 | 窗口大小(window size)+ 滑动步长(slide step) | 高频连续统计(如每 5 秒统计最近 30 秒的接口 QPS、每 1 分钟统计最近 5 分钟的商品点击量) |

极简 Demo:滚动窗口 + 滑动窗口基础使用

java 复制代码
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.assigners.SlidingProcessingTimeWindows;
import org.apache.flink.streaming.api.windowing.assigners.TumblingProcessingTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;

public class WindowBasicDemo {
    public static void main(String[] args) throws Exception {
        // 1. 创建执行环境
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);

        // 2. 构造测试数据:模拟实时数字流
        DataStream<Integer> dataStream = env.socketTextStream("localhost", 9999)
                .map(new MapFunction<String, Integer>() {
                    @Override
                    public Integer map(String s) throws Exception {
                        return Integer.parseInt(s);
                    }
                });

        // 3. 滚动窗口:每10秒统计一次求和(无重叠)
        DataStream<Integer> tumblingWindowStream = dataStream
                .keyBy(x -> x % 2) // 按奇偶分区
                .window(TumblingProcessingTimeWindows.of(Time.seconds(10)))
                .sum(0);

        // 4. 滑动窗口:每5秒统计最近10秒的求和(有重叠)
        DataStream<Integer> slidingWindowStream = dataStream
                .keyBy(x -> x % 2) // 按奇偶分区
                .window(SlidingProcessingTimeWindows.of(Time.seconds(10), Time.seconds(5)))
                .sum(0);

        // 5. 打印结果
        tumblingWindowStream.print("滚动窗口结果:");
        slidingWindowStream.print("滑动窗口结果:");

        // 6. 执行任务
        env.execute("Window Basic Demo");
    }
}

3. Window Function 窗口函数

窗口函数是窗口内数据的计算逻辑 ,即切分后的有界数据集如何做聚合,核心分为增量聚合函数全量聚合函数 ,是开发中必用的核心函数,高频 API 及特性整理如下:

|----------|-------------------------------------|------------------------|--------------------------|----------------------------------------------------------------------------------------|
| 函数类型 | 核心特性 | 优点 | 缺点 | 高频实现类 / API |
| 增量聚合函数 | 数据逐条进入 窗口时,实时更新聚合结果,窗口触发时直接输出结果 | 内存占用低、性能高,适合大数据量场景 | 无法获取窗口的元数据(如窗口开始 / 结束时间) | SumFunction/sum() MaxFunction/max() MinFunction/min() ReduceFunction AggregateFunction |
| 全量聚合函数 | 数据全部进入 窗口后,统一做聚合计算,窗口触发时输出结果 | 可获取窗口完整元数据、全量数据,支持复杂计算 | 内存占用高,需缓存窗口内所有数据 | ProcessWindowFunction(最通用) |

极简 Demo:增量聚合(ReduceFunction)+ 全量聚合(ProcessWindowFunction)

java 复制代码
import org.apache.flink.api.common.functions.ReduceFunction;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.windowing.ProcessWindowFunction;
import org.apache.flink.streaming.api.windowing.assigners.TumblingProcessingTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.streaming.api.windowing.windows.TimeWindow;
import org.apache.flink.util.Collector;

public class WindowFunctionDemo {
    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);

        // 构造测试数据
        DataStream<Integer> dataStream = env.socketTextStream("localhost", 9999)
                .map(Integer::parseInt);

        // 1. 增量聚合:ReduceFunction 实现累加
        DataStream<Integer> reduceStream = dataStream
                .keyBy(x -> x % 2)
                .window(TumblingProcessingTimeWindows.of(Time.seconds(10)))
                .reduce(new ReduceFunction<Integer>() {
                    @Override
                    public Integer reduce(Integer value1, Integer value2) throws Exception {
                        return value1 + value2;
                    }
                });

        // 2. 全量聚合:ProcessWindowFunction 实现求和(可获取窗口时间)
        DataStream<String> processStream = dataStream
                .keyBy(x -> x % 2)
                .window(TumblingProcessingTimeWindows.of(Time.seconds(10)))
                .process(new ProcessWindowFunction<Integer, String, Integer, TimeWindow>() {
                    @Override
                    public void process(Integer key, Context context, Iterable<Integer> elements, Collector<String> out) throws Exception {
                        // 获取窗口元数据:开始/结束时间
                        long windowStart = context.window().getStart();
                        long windowEnd = context.window().getEnd();
                        // 全量数据求和
                        int sum = 0;
                        for (Integer e : elements) {
                            sum += e;
                        }
                        // 输出结果:key + 窗口时间 + 求和结果
                        out.collect("key:" + key + ",窗口开始:" + windowStart + ",窗口结束:" + windowEnd + ",求和结果:" + sum);
                    }
                });

        reduceStream.print("增量聚合(Reduce):");
        processStream.print("全量聚合(Process):");

        env.execute("Window Function Demo");
    }
}

二、Time + Watermark:解决流处理的乱序问题

Flink 的窗口计算依赖时间 触发,而实时数据流中存在数据乱序 (如数据产生时间是 10:00,到达 Flink 的时间是 10:05),如果直接按系统时间计算,会导致统计结果不准确。Time(时间语义) 定义了 Flink 的时间计算标准,Watermark(水位线) 是解决乱序数据的核心方案,两者结合是 Flink 实现精准实时计算的基础。

1. Time 三大时间语义

Flink 提供三种时间语义,开发中Event Time 是使用频率最高、最贴合业务实际的,三者核心区别通过表格整理,明确适用场景:

|-----------------------|------------------------------------------|------------------|--------------------------------------|------------------------------|--------------------------------------------|
| 时间语义 | 定义 | 计算依据 | 优点 | 缺点 | 适用场景 |
| 处理时间(Processing Time) | 数据到达 Flink 算子 的系统时间 | 算子所在机器的本地时间 | 无需额外配置、计算简单、性能最高 | 受网络延迟、机器时钟影响,统计结果不准确 | 对实时性要求极高、对准确性要求较低的场景(如临时监控、粗略统计) |
| 事件时间(Event Time) | 数据产生的时间 (由数据生产者携带,如日志的 timestamp 字段) | 数据本身的时间戳 | 贴合业务实际,统计结果精准,不受传输延迟影响 | 需要指定时间戳提取规则、配置 Watermark,略复杂 | 绝大多数业务场景(如订单统计、用户行为分析、商品点击量统计) |
| 摄入时间(Ingestion Time) | 数据进入 Flink 数据源 的时间 | Flink 数据源节点的系统时间 | 比 Processing Time 准确,比 Event Time 简单 | 仍受 Flink 内部处理延迟影响 | 无需精准事件时间、但需要比 Processing Time 更准确的场景(极少使用) |

核心结论 :实际开发中,优先使用 Event Time ,搭配 Watermark 解决乱序问题,是 Flink 实时计算的标准配置。

2. Event Time 的核心重要性

  • 贴合业务实际 :统计的是数据实际产生 的时间维度,而非 Flink 处理的时间维度,结果更有业务价值;
  • 解耦数据传输计算 :不受网络延迟、节点处理速度影响,即使数据乱序到达,也能精准统计;
  • 支持数据回溯 :基于数据本身的时间戳,可重新计算历史时间段的结果,适合故障恢复、数据补算。

3. Watermark 核心概念

(1)Watermark 是什么?

Watermark(水位线)是Event Time 下的一种特殊的数据流标记 ,本质是一个时间戳 ,格式为Watermark(t),表示所有事件时间小于等于 t 的数据已经全部到达 Flink

(2)为什么需要 Watermark?

实时数据流中存在数据乱序数据延迟 ,如果直接按事件时间触发窗口,会出现 "窗口已触发,后续仍有该窗口的数到达" 的情况,导致统计结果缺失。Watermark 的核心作用是告诉 Flink 一个时间阈值 ,当 Watermark 到达窗口结束时间时,才触发窗口计算,从而兼容一定程度的乱序和延迟。

4. Watermark 解决的问题及实现原理

(1)解决的核心问题
  • 处理Event Time 下的数据乱序,保证窗口计算的完整性
  • 定义数据延迟的容忍度 ,平衡计算的精准性实时性
  • 触发窗口的最终计算 ,避免因少量延迟数据导致窗口一直不触发。
(2)核心实现原理
  1. 从数据流中提取事件时间戳 ,为每条数据打上 Event Time;
  2. Flink 根据指定的水印生成策略 ,实时生成 Watermark(如 "允许数据延迟 3 秒",则 Watermark = 当前最大事件时间 - 3 秒);
  3. Watermark随着数据流 在算子间传递,是全局的时间标记;
  4. 当 Watermark 的时间戳大于等于窗口的结束时间 时,触发该窗口的聚合计算;
  5. 对于 Watermark 触发后到达的超延迟数据 ,可通过侧输出流(Side Output) 收集,避免数据丢失。
(3)Watermark 时序图
(4)多并行度下的 Watermark 传递机制

Flink 任务默认是多并行度的,每个并行子任务会独立生成 Watermark,当 Watermark 传递到下游算子 时,下游算子会取所有并行子任务中最小的 Watermark 作为当前的全局 Watermark,即 "水印对齐"。

核心原因 :保证所有并行子任务的乱序数据都被兼容,避免因某个子任务的水印超前导致其他子任务的延迟数据丢失。

5. Time + Watermark 极简核心 Demo

java 复制代码
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.AssignerWithPunctuatedWatermarks;
import org.apache.flink.streaming.api.watermark.Watermark;
import org.apache.flink.streaming.api.windowing.assigners.TumblingEventTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.util.OutputTag;

import javax.annotation.Nullable;

// 测试数据格式:数字,事件时间戳(如:1,1719600000000)
public class TimeWatermarkDemo {
    // 定义侧输出流标签,收集超延迟数据
    private static final OutputTag<Integer> LATE_DATA_TAG = new OutputTag<Integer>("late-data") {};

    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);

        // 1. 构造测试数据,提取事件时间
        SingleOutputStreamOperator<MyData> dataStream = env.socketTextStream("localhost", 9999)
                .map(new MapFunction<String, MyData>() {
                    @Override
                    public MyData map(String s) throws Exception {
                        String[] split = s.split(",");
                        return new MyData(Integer.parseInt(split[0]), Long.parseLong(split[1]));
                    }
                })
                // 2. 分配事件时间戳 + 生成Watermark(允许延迟3秒)
                .assignTimestampsAndWatermarks(new AssignerWithPunctuatedWatermarks<MyData>() {
                    private long maxEventTime = 0L;
                    private final long delayTime = 3000L; // 3秒延迟

                    @Override
                    public long extractTimestamp(MyData myData, long l) {
                        // 提取数据的事件时间戳
                        long eventTime = myData.getEventTime();
                        maxEventTime = Math.max(maxEventTime, eventTime);
                        return eventTime;
                    }

                    @Nullable
                    @Override
                    public Watermark checkAndGetNextWatermark(MyData myData, long l) {
                        // 生成Watermark:最大事件时间 - 延迟时间
                        return new Watermark(maxEventTime - delayTime);
                    }
                });

        // 3. 基于Event Time的滚动窗口,收集超延迟数据到侧输出流
        SingleOutputStreamOperator<Integer> windowStream = dataStream
                .keyBy(MyData::getNum)
                .window(TumblingEventTimeWindows.of(Time.seconds(10)))
                .sideOutputLateData(LATE_DATA_TAG) // 收集超延迟数据
                .sum("num");

        // 4. 打印正常窗口结果和超延迟数据
        windowStream.print("Event Time窗口结果:");
        windowStream.getSideOutput(LATE_DATA_TAG).print("超延迟数据:");

        env.execute("Time + Watermark Demo");
    }

    // 自定义数据实体
    public static class MyData {
        private Integer num;
        private Long eventTime;

        public MyData(Integer num, Long eventTime) {
            this.num = num;
            this.eventTime = eventTime;
        }

        public Integer getNum() {
            return num;
        }

        public Long getEventTime() {
            return eventTime;
        }
    }
}

Flink 是有状态的流处理框架 ,State(状态)是指 Flink 在计算过程中缓存的中间数据 ,比如窗口的聚合结果、数据流的去重标记、累计的计数等。有状态计算是 Flink 区别于其他流处理框架的核心特性,也是实现复杂实时计算的基础。

1. 有状态计算 vs 无状态计算

|----------|-------------------------------------|------------------|----------------------|-----------------------------|
| 计算类型 | 核心定义 | 特点 | 适用场景 | 示例 |
| 无状态计算 | 每个数据的计算结果仅依赖自身 ,不依赖任何中间数据,算子无缓存 | 计算简单、无内存占用、并行度高 | 简单的数据转换(如过滤、映射、格式转换) | 过滤掉空值数据、将字符串转为数字、日志字段提取 |
| 有状态计算 | 每个数据的计算结果依赖自身 + 中间状态 ,算子会缓存中间数据 | 支持复杂计算、结果连续、贴合业务 | 聚合统计、去重、限流、关联、累计计算 | 窗口求和、用户行为去重、接口 QPS 限流、累计订单量 |

2. State 核心分类

Flink 的 State 按作用范围 分为算子状态(Operator State)按键状态(Keyed State) ,其中Keyed State 是开发中使用频率 99% 的状态类型,两者核心特性、分类、高频 API 整理如下:

(1)核心分类对比

|----------------------|----------------------------------|-----------------|------------------------|-------------------------------------|--------------------------------------------------------------|
| 状态类型 | 作用范围 | 绑定对象 | 并行度扩展 | 适用场景 | 核心 API |
| 算子状态(Operator State) | 整个算子的所有并行子任务 | 算子(Operator) | 仅支持重分配 (如均匀拆分、广播) | 数据源的状态管理(如 Kafka Consumer 的 offset) | ListState UnionListState BroadcastState |
| 按键状态(Keyed State) | 算子的单个 Key 分区 ,不同 Key 的状态相互隔离 | Key(由 keyBy 指定) | 支持无缝扩展 ,按 Key 重新分区 | 绝大多数业务场景(聚合、去重、累计、关联) | ValueState ListState MapState ReducingState AggregatingState |

(2)Keyed State 细分类型(开发必用)

|------------|----------------------------|-------------------------------|-----------------------------------------------------|
| 细分类型 | 核心作用 | 特点 | 高频 API |
| ValueState | 存储单个值 ,适用于单值累计(如计数、求和) | 键值对形式,Key 为分区 Key,Value 为单个数据 | value()(获取值)update(T value)(更新值)clear()(清空状态) |
| ListState | 存储一个列表 ,适用于缓存多条数据 | 支持添加、遍历、清空列表 | add(T value)(添加数据)get()(获取列表)clear()(清空状态) |
| MapState | 存储一个键值对集合 ,适用于多维度累计 | 支持按 Key 增删改查,类似 Java 的 Map | put(K k, V v)(添加键值对)get(K k)(获取值)remove(K k)(删除键值对) |

3. State 极简核心 Demo(Keyed State - ValueState 实现累计计数)

java 复制代码
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.api.common.state.ValueState;
import org.apache.flink.api.common.state.ValueStateDescriptor;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.KeyedProcessFunction;
import org.apache.flink.util.Collector;

// 实现:按Key累计计数,统计每个数字出现的次数
public class StateBasicDemo {
    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);

        // 1. 构造测试数据
        DataStream<Integer> dataStream = env.socketTextStream("localhost", 9999)
                .map(Integer::parseInt);

        // 2. 按Key分区,使用KeyedProcessFunction实现有状态计算
        DataStream<String> stateStream = dataStream
                .keyBy(x -> x)
                .process(new KeyedProcessFunction<Integer, Integer, String>() {
                    // 定义ValueState,存储每个Key的累计计数
                    private ValueState<Integer> countState;

                    // 初始化状态
                    @Override
                    public void open(Configuration parameters) throws Exception {
                        ValueStateDescriptor<Integer> descriptor = new ValueStateDescriptor<>(
                                "countState", // 状态名称
                                Integer.class, // 状态类型
                                0 // 状态默认值
                        );
                        countState = getRuntimeContext().getState(descriptor);
                    }

                    // 处理每条数据
                    @Override
                    public void processElement(Integer value, Context ctx, Collector<String> out) throws Exception {
                        // 获取当前状态值(累计计数)
                        int currentCount = countState.value();
                        // 计数+1,更新状态
                        currentCount++;
                        countState.update(currentCount);
                        // 输出结果:Key + 累计计数
                        out.collect("数字:" + value + ",累计出现次数:" + currentCount);
                    }
                });

        // 3. 打印结果
        stateStream.print("State累计计数结果:");

        env.execute("State Basic Demo");
    }
}

核心要点 :Keyed State 必须在keyBy之后使用,通过open方法初始化状态,通过RuntimeContext获取状态实例,所有状态操作均为本地操作,性能极高。

Flink 作为分布式流处理框架,运行过程中会遇到节点故障、网络中断、程序重启 等问题,Checkpoint 是 Flink 实现故障容错 的核心机制,而 Savepoint 是基于 Checkpoint 实现的手动持久化 机制,两者结合保证了 Flink 任务的高可用数据一致性 ,是生产环境必配的核心功能。

核心考察点 :Checkpoint 与 Savepoint 的原理区别使用场景 ,也是面试和开发中的高频考点,本文从原理、特性、使用、对比四个维度做体系化整理。

1. Checkpoint:分布式快照,实现故障容错

(1)Checkpoint 核心概念

Checkpoint(检查点)是 Flink 为有状态任务 生成的分布式快照 ,本质是将任务运行过程中的所有 State(状态) 按指定周期持久化到持久化存储 (如 HDFS、S3、本地文件),当任务发生故障时,可从最近的 Checkpoint 快照中恢复状态,继续计算,保证数据的Exactly-Once(精准一次) 语义。

(2)核心实现原理(极简版)
  1. 触发 :Flink JobManager 按指定Checkpoint 周期 ,向所有 Source 算子发送Checkpoint 触发指令
  2. 快照 :Source 算子生成快照,将自身状态(如 Kafka offset)持久化到存储,然后将Checkpoint Barrier (检查点屏障)发送到下游算子;
  3. 屏障传递 :Checkpoint Barrier 随着数据流在算子间传递,下游算子接收到所有输入的 Barrier 后,生成自身状态的快照并持久化,再将 Barrier 发送到下一级算子;
  4. 确认 :当所有 Sink 算子完成快照并持久化后,向 JobManager 发送Checkpoint 完成确认
  5. 恢复 :任务故障时,JobManager 选择最近的成功 Checkpoint ,通知所有算子从该快照中恢复状态,任务从故障点继续运行。
(3)核心作用
  • 实现故障容错 :任务故障后无需重新计算全量数据,从 Checkpoint 恢复即可,减少数据丢失和重复计算;
  • 保证数据一致性 :结合 Flink 的流控机制,实现 Exactly-Once 语义,确保数据处理精准一次;
  • 支持任务重启 :生产环境中升级程序、调整并行度时,可基于 Checkpoint 无缝重启,不影响业务。
(4)生产常用配置
java 复制代码
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.CheckpointingMode;

public class CheckpointConfigDemo {
    public static void main(String[] args) {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

        // 1. 开启Checkpoint,设置周期为10秒(生产常用:10s-1min)
        env.enableCheckpointing(10000);

        // 2. 设置Checkpoint模式为Exactly-Once(精准一次,生产默认)
        env.getCheckpointConfig().setCheckpointingMode(CheckpointingMode.EXACTLY_ONCE);

        // 3. 设置Checkpoint超时时间:1分钟(超时则本次Checkpoint失败)
        env.getCheckpointConfig().setCheckpointTimeout(60000);

        // 4. 设置最大并行Checkpoint数:1(同一时间仅允许一个Checkpoint执行)
        env.getCheckpointConfig().setMaxConcurrentCheckpoints(1);

        // 5. 设置Checkpoint失败后,任务是否失败:false(生产常用,避免单个Checkpoint失败导致任务挂掉)
        env.getCheckpointConfig().setFailOnCheckpointingErrors(false);

        // 6. 设置持久化存储(如HDFS,生产必配,本地仅用于测试)
        // env.getCheckpointConfig().setCheckpointStorage("hdfs://hadoop01:9000/flink/checkpoint");
    }
}

2. Savepoint:手动创建的持久化快照,实现任务灵活管理

(1)Savepoint 核心概念

Savepoint 是用户手动触发 的、基于 Checkpoint 机制实现的持久化快照 ,本质是一份特殊的 Checkpoint ,与 Checkpoint 不同的是,Savepoint 是手动管理 的,不会被 Flink 自动删除,主要用于任务的版本升级、并行度调整、集群迁移 等场景。

(2)核心实现原理

Savepoint 的实现原理与 Checkpoint完全一致 ,都是生成分布式快照并持久化状态,区别仅在于触发方式生命周期管理

  • Checkpoint 由 Flink自动触发、自动管理 ,旧的 Checkpoint 会被新的覆盖 / 删除;
  • Savepoint 由用户手动触发、手动管理 ,不会被 Flink 自动删除,需用户手动清理。

3. Checkpoint 与 Savepoint 核心对比

|----------|---------------------------------------------|---------------------------------------------|
| 对比维度 | Checkpoint | Savepoint |
| 触发方式 | 自动触发 ,按配置的周期自动执行 | 手动触发 ,由用户通过命令行 / API 执行 |
| 生命周期 | 由 Flink自动管理 ,新的 Checkpoint 会覆盖旧的,可配置保留数 | 由用户手动管理 ,不会被 Flink 自动删除,需手动创建 / 删除 / 恢复 |
| 核心目的 | 实现故障容错 ,任务故障时自动恢复,保证高可用 | 实现任务灵活管理 ,如版本升级、并行度调整、集群迁移 |
| 数据保留 | 保留近期的少量快照(生产常用:保留 3-5 个) | 长期保留,直到用户手动删除 |
| 触发时机 | 运行过程中持续触发 | 任务升级、重启、扩缩容前手动触发 |

4. Checkpoint 极简使用 Demo(整合 State,实现故障恢复)

java 复制代码
import org.apache.flink.api.common.state.ValueState;
import org.apache.flink.api.common.state.ValueStateDescriptor;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.CheckpointingMode;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.KeyedProcessFunction;
import org.apache.flink.util.Collector;

// 整合Checkpoint + State,实现故障恢复后的累计计数不丢失
public class CheckpointStateDemo {
    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);

        // ========== Checkpoint 核心配置 ==========
        env.enableCheckpointing(5000); // 5秒触发一次Checkpoint
        env.getCheckpointConfig().setCheckpointingMode(CheckpointingMode.EXACTLY_ONCE);
        env.getCheckpointConfig().setCheckpointTimeout(30000);
        env.getCheckpointConfig().setMaxConcurrentCheckpoints(1);
        // 配置持久化存储(本地测试,生产替换为HDFS)
        env.getCheckpointConfig().setCheckpointStorage("file:///D:/flink/checkpoint");

        // 1. 构造测试数据
        DataStream<Integer> dataStream = env.socketTextStream("localhost", 9999)
                .map(Integer::parseInt);

        // 2. 有状态计算:累计计数
        DataStream<String> resultStream = dataStream
                .keyBy(x -> x)
                .process(new KeyedProcessFunction<Integer, Integer, String>() {
                    private ValueState<Integer> countState;

                    @Override
                    public void open(Configuration parameters) throws Exception {
                        countState = getRuntimeContext().getState(
                                new ValueStateDescriptor<>("countState", Integer.class, 0)
                        );
                    }

                    @Override
                    public void processElement(Integer value, Context ctx, Collector<String> out) throws Exception {
                        int currentCount = countState.value();
                        currentCount++;
                        countState.update(currentCount);
                        out.collect("数字:" + value + ",累计次数:" + currentCount);
                    }
                });

        // 3. 打印结果
        resultStream.print("Checkpoint+State 结果:");

        env.execute("Checkpoint & State Demo");
    }
}

测试故障恢复 :运行程序后输入数字,累计计数正常增长,手动停止程序后重新运行,程序会从 Checkpoint 中恢复状态,累计计数不会从 0 开始,实现无丢失恢复。

五、四大基石核心总结

Flink 的四大基石是层层递进、相互依赖的核心体系,支撑了所有实时计算场景:

  1. Window :实现流到批的切分,是聚合计算的基础;
  2. Time + Watermark :为 Window 提供精准的时间触发机制,解决 Event Time 下的乱序问题;
  3. State :为 Window 和业务计算提供中间数据缓存,是有状态计算的核心;
  4. Checkpoint & Savepoint :为 State 提供持久化和故障恢复能力,保证任务的高可用和数据一致性。

📚 我的技术博客导航:[点击进入一站式查看所有干货]


相关推荐
1941s2 小时前
OpenClaw 每日新玩法 | NanoClaw —— 轻量级、安全的 OpenClaw 替代方案
人工智能·安全·agent·openclaw
攻城狮7号2 小时前
深度解析 GPT-5.4:从“聊天对话”到“原生全能数字员工”的技术演进
人工智能·openai·智能体·gpt-5.4
NAGNIP2 小时前
一文搞懂CNN经典架构-AlexNet!
人工智能·算法
Agent产品评测局2 小时前
企业 AI Agent 落地,如何保障数据安全与合规?——企业级智能体安全架构与合规路径深度盘点
人工智能·安全·ai·chatgpt·安全架构
Hello.Reader2 小时前
深度学习 三次浪潮、三大驱动力与神经科学的恩怨(二)
人工智能·深度学习
ggabb2 小时前
汉字破局:AI时代的文明反攻与英语世界的“偷师”真相
人工智能
roman_日积跬步-终至千里2 小时前
【深度学习】从前向传播到反向传播:用两层 sigmoid 网络把 Backprop 一次讲透
人工智能·深度学习
sinat_286945192 小时前
claude code上下文
人工智能·深度学习·prompt
逐梦苍穹2 小时前
去掉一层东西,Claude.ai直接快了 65%
人工智能·claude