Flink-时间语义

1时间语义

flink种设计时间的不同概念:

  • 1 Event Time:事件时间,指代事件创建的时间,指代数据中的时间错带指代事件时间,Flink通过时间戳分配器访问事件时间
  • 2 Ingestion Time: 摄入时间:指代数据进入Flink的时间
  • 3 Processing Time:进程时间:数据执行算子的处理时间

1 EventTime 的引入:

在Flink的流式处理中,绝大部分的业务都会使用eventTime,一般只在eventTime无法使用时,才会被迫使用ProcessingTime或者IngestionTime。

如果要使用EventTime,那么需要引入EventTime的时间属性

StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment
// 从调用时刻开始给env创建的每一个stream追加时间特征
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)

2 Watermark

1 watermark概述:

1 在eventTime事件时间中,Flink接收事件的数据不是严格按照事件时间进行排序,会出现乱序,需要watermark进行处理乱序的一种机制

2 一旦出现乱序,如果只根据eventTime决定window的运行,我们不能明确数据是否全部到位,但又不能无限期的等下去,此时必须要有个机制来保证一个特定的时间后,必须触发window去进行计算了,这个特别的机制,就是Watermark。

2 watermark的理论知识

Watermark,这条Watermark就等于当前所有到达数据中的maxEventTime- 延迟时长,

也就是说,Watermark是基于数据携带的时间戳生成的,

一旦Watermark比当前未触发的窗口的停止时间要晚,那么就会触发相应窗口的执行。

由于event time是由数据携带的,因此,如果运行过程中无法获取新的数据,那么没有被触发的窗口将永远都不被触发。

图解案例:

乱序流的Watermarker如下图所示:(Watermark设置为2)

上图中,我们设置的允许最大延迟到达时间为2s,所以时间戳为7s的事件对应的Watermark是5s,

时间戳为12s的事件的Watermark是10s,如果我们的窗口1是1s~5s,

窗口2是6s~10s,那么时间戳为7s的事件到达时的Watermarker恰好触发窗口1,时间戳为12s的事件到达时的Watermark恰好触发窗口2

Watermark就是触发前一窗口的“关窗时间”,一旦触发关门那么以当前时刻为准在窗口范围内的所有数据都会收入窗中。

只要没有达到水位那么不管现实中的时间推进了多久都不会触发关窗。

3 理论小结

watermark是用来处理按照事件时间出现乱序的一种机制

4 Watermark引入

dataStream.assignTimestampsAndWatermarks( new BoundedOutOfOrdernessTimestampExtractor<SensorReading>(Time.milliseconds(1000)) {
  @Override
public long extractTimestamp(element: SensorReading): Long = {
    return element.getTimestamp() * 1000L;//获取事件数据的时间戳作为事件时间
  }
} );

我们看到上面的例子中创建了一个看起来有点复杂的类,这个类实现的其实就是分配时间戳的接口。

Flink暴露了TimestampAssigner接口供我们实现,使我们可以自定义如何从事件数据中抽取时间戳。

StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

// 设置事件时间语义
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
// 在添加数据源时候设置时间戳以及watermark
DataStream<SensorReading> dataStream = env.addSource(new SensorSource())
        .assignTimestampsAndWatermarks(new MyAssigner());// 这里就可以自定义事件语义的时间戳

MyAssigner有两种类型(分配时间戳的接口)

  • AssignerWithPeriodicWatermarks
  • AssignerWithPunctuatedWatermarks

以上两个接口都继承自TimestampAssigner。

watermark生产的时间间隔,怎么周期性生成watermark设置

可以使用ExecutionConfig.setAutoWatermarkInterval()方法进行设置。

// 每隔5秒产生一个watermark env.getConfig.setAutoWatermarkInterval(5000);

以上代码解析:

产生watermark的逻辑:每隔5秒钟,

Flink会调用AssignerWithPeriodicWatermarks的getCurrentWatermark()方法。

如果方法返回一个时间戳大于之前水位的时间戳,新的watermark会被插入到流中。

这个检查保证了水位线是单调递增的。如果方法返回的时间戳小于等于之前水位的时间戳,则不会产生新的watermark。

周期性获取时间戳的例子:自定义周期性时间戳分配器

// 自定义周期性时间戳分配器
public static class MyPeriodicAssigner implements AssignerWithPeriodicWatermarks<SensorReading>{
    private Long bound = 60 * 1000L;    // 延迟一分钟
    private Long maxTs = Long.MIN_VALUE;    // 当前最大时间戳

    @Nullable
    @Override
    public Watermark getCurrentWatermark() {
        return new Watermark(maxTs - bound);
    }

    @Override
    public long extractTimestamp(SensorReading element, long previousElementTimestamp) {
        maxTs = Math.max(maxTs, element.getTimestamp());
        return element.getTime

不周期性:自定义时间戳:

如果数据是单调递增:AscendingTimestampExtractor,这个类会直接使用数据的时间戳生成watermark。

代码如下:

DataStream<SensorReading> dataStream = …

dataStream.assignTimestampsAndWatermarks(
new AscendingTimestampExtractor<SensorReading>() {
    @Override
    public long extractAscendingTimestamp(SensorReading element) {
        return element.getTimestamp() * 1000;
    }
});

乱序数据流,如果能大致估算出最大延迟时间,则使用 BoundedOutOfOrdernessTimestampExtractor(Time.seconds(1))

这个可以根据事件的时间戳减去1S,作为时间戳

DataStream<SensorReading> dataStream = …

dataStream.assignTimestampsAndWatermarks(
new BoundedOutOfOrdernessTimestampExtractor<SensorReading>(Time.seconds(1)) {
    @Override
    public long extractTimestamp(SensorReading element) {
        return element.getTimestamp() * 1000L;
    }
});

<think>嗯,用户问的是Flink如何保证Exactly-once语义。我需要先回忆一下Flink的相关知识。Exactly-once是流处理中非常重要的特性,确保每条数据只被处理一次,即使在故障恢复时也是如此。 首先,Flink的检查点机制应该是关键。检查点基于Chandy-Lamport算法,定期保存作业状态。每个检查点会插入barrier到数据流中,barrier将流分成不同的窗口,当所有任务都确认状态保存后,检查点才算完成。这样在故障恢复时,可以从最近的检查点重启,保证状态的一致性。 然后,可能需要提到状态后端,比如RocksDB,它支持异步快照,减少对处理性能的影响。不过状态后端具体是存储部分,可能和Exactly-once的实现关系不大,但检查点的持久化存储确实重要。 另外,两阶段提交协议(2PC)在Flink中的应用。比如在连接外部系统(如Kafka)时,Flink通过TwoPhaseCommitSinkFunction实现精确一次输出。这涉及到预提交和提交两个阶段,确保数据要么完全提交,要么回滚,避免部分写入。 还需要区分Exactly-once的不同层次:Flink内部的状态一致性,以及端到端的精确一次。内部通过检查点和恢复机制,而端到端需要外部系统的协同,比如支持事务的Sink。 可能用户需要具体的步骤或流程图说明。比如检查点的触发、barrier对齐、状态快照,故障恢复时的状态回滚和重放数据。这时候分步骤解释会更清晰。 还要注意不同版本的Flink是否有改进,比如在Aligned Checkpoint和Unaligned Checkpoint的区别,后者在反压严重时也能保证生成检查点,但可能会影响Exactly-once的保证吗?不过用户可能不需要这么深入,但可能需要简单提及。 另外,可能用户对Exactly-once和At-least-once的区别有疑惑,可以简要比较,但用户的问题主要关注Exactly-once的实现,所以重点应在Flink的机制。 总结下来,回答的结构应该是:先介绍Exactly-once的重要性,然后分检查点机制和两阶段提交,再讲内部和端到端的保证,可能最后举例说明,比如Kafka到Flink再到Kafka的案例。需要确保用中文,行内公式正确,结构清晰。</think>Flink 通过**分布式快照检查点(Checkpoint)**和**两阶段提交协议(2PC)**的结合实现端到端的 Exactly-once 语义。以下是其核心机制的分步解析: --- ### 一、Checkpoint 机制:保证内部状态一致性 1. **触发检查点** JobManager 周期性触发检查点(如每 10 秒),向 Source 节点插入**特殊标记(Barrier)**到数据流中,将数据流逻辑切分为窗口。 2. **Barrier 对齐** - 每个算子收到 Barrier 后暂停处理后续数据,**先缓存输入流的数据**。 - 当所有输入流的 Barrier 都到达时,算子将当前状态**异步持久化**到可靠存储(如 HDFS/S3)。 - 公式表示状态保存过程: $$ S_i = f(S_{i-1}, D_{window}) $$ 其中 $S_i$ 为第 $i$ 次检查点状态,$D_{window}$ 为当前窗口数据。 3. **恢复机制** 故障时,Flink 回滚到最近完整的检查点,从持久化状态重新处理后续数据,确保状态与数据流完全一致。 --- ### 二、端到端 Exactly-once:两阶段提交协议(2PC) 对于外部系统(如 Kafka、数据库),Flink 通过 **`TwoPhaseCommitSinkFunction`** 实现事务性写入: | 阶段 | 行为 | |---------------------|----------------------------------------------------------------------| | **1. 预提交(Pre-commit)** | Sink 将数据写入外部系统,但标记为**未提交**(如 Kafka 事务未提交)。 | | **2. 提交(Commit)** | 当 Checkpoint 完成时,JobManager 通知所有算子提交事务。 | | **回滚(Rollback)** | 若 Checkpoint 失败,事务自动回滚,外部系统丢弃未提交数据。 | --- ### 三、关键设计优化 1. **精确一次 vs 至少一次** - *Exactly-once*:通过 Barrier 对齐和事务提交确保一致性。 - *At-least-once*:Barrier 不对齐时可能重复处理数据。 2. **反压处理** - **Unaligned Checkpoint**(Flink 1.11+):允许 Barrier 跨越缓存数据,避免反压导致检查点超时。 3. **端到端场景示例** ```text Kafka → Flink → Kafka └── Source 记录消费偏移量(状态) └── Sink 开启 Kafka 事务写入 └── Checkpoint 成功时提交偏移量和事务 ``` --- ### 四、适用场景 - **高一致性要求**:金融交易、计费系统。 - **高吞吐场景**:Checkpoint 间隔需权衡吞吐和恢复时间。 通过以上机制,Flink 在分布式环境下实现了**状态一致性**和**端到端数据精确处理**,成为流处理领域的核心优势之一。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值