flink读取有界流时开时间窗遇到的问题

探讨了使用流处理API处理批数据的不合理性,分析了基于时间窗口聚合数据时的常见问题,如数据输出缺失和内存溢出风险。

有界流:

不知道有没有这个概念,我这里用它表示以流处理的方式读取的批数据,比如streamExecutionEnvironment.fromCollection(...)

其实这种做法或需求是比较奇怪的,要用流处理,但读的却是批数据,最好用流处理api处理流数据,用批处理api处理批数据。

我这里之所以有这样反人类的设计,是出于批处理一次性读取全部数据有可能会内存溢出的情况下考虑的。想通过流的方式读取批数据来解决。但是后面想了想,这好像简直是一厢情愿。批量读取数据后交给流处理api,这只是处理的过程按流的方式进行,但读数据还是一次性读取的,并不是流的方式一条条读(不过这只是我个人的分析,没有找到相关的资料,也没有验证),所以,这种想法太愚蠢。

虽然这种做法是愚蠢的,是不推荐使用的。但可能有朋友也跟我一样“愚蠢”,因此这里记录一下这种方式遇到的问题,供朋友参考。

上代码:

public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setStreamTimeCharacteristic(TimeCharacteristic.ProcessingTime);
        List<BatchReduce.Deposit> list = new ArrayList<>();
        list.add(new BatchReduce.Deposit(1,100));
        list.add(new BatchReduce.Deposit(2,100));
        list.add(new BatchReduce.Deposit(5,100));
        list.add(new BatchReduce.Deposit(4,100));
        list.add(new BatchReduce.Deposit(1,50));
        list.add(new BatchReduce.Deposit(2,60));
        list.add(new BatchReduce.Deposit(1,60));
        list.add(new BatchReduce.Deposit(1,50));
        DataStreamSource<BatchReduce.Deposit> source = env.fromCollection(list);
       
        SingleOutputStreamOperator<BatchReduce.Deposit> sum = source.keyBy(new KeySelector<BatchReduce.Deposit, Integer>() {
            @Override
            public Integer getKey(BatchReduce.Deposit value) throws Exception {
                return value.getStudentID();
            }
        }).timeWindow(Time.seconds(1))
                .sum("money");
        sum.print();
        env.execute();
    }

代码很简单,就是要根据studentID分组,然后开1s的时间窗对money进行聚合。

但现象是压根没有数据输出。这里数据量太小,当数据量大的时候,更好测试。

分析原因,是因为这种方式读的数据是没有时间概念的,是一次性批量读取的。可能数据还没有进入窗口,或还没有达到触发窗口的条件时,整个程序就结束了。因此不会输出。(这可以在读取大数据量的时候,逐步调大时间窗口大小来测试)

因此,这种读取批数据后开时间窗进行计算的方式是绝对不可取的。

但如果不加时间直接聚合,则没有问题。或者加计数窗countwindow,但这种需要解决最后一个窗口数据不足时如何触发,不然也会由于程序结束导致丢最后一个窗口的数据。

### 使用 Flink SQL 读取 Kafka 数据处理为有边界的流 Flink 支持将 Kafka 数据源作为有界流处理,这通常适用于需要一次性处理历史数据的场景。通过 Flink SQL,可以定义 Kafka 表结构,在查询中指定数据的边界条件,从而将流式数据转换为有界流。 Kafka 数据源可以通过 `kafka` 连接器进行定义,结合 `JSON` 或 `CSV` 等格式进行解析。以下是一个 Kafka 表定义的示例: ```sql CREATE TABLE kafka_source ( `user_id` STRING, `event_type` STRING, `event_time` STRING ) WITH ( 'connector' = 'kafka', 'topic' = 'your_kafka_topic', 'properties.bootstrap.servers' = 'localhost:9092', 'properties.group.id' = 'flink-sql-demo-group', 'format' = 'json' ); ``` 为了将 Kafka 数据作为有界流处理,可以使用 `BATCH` 执行模式,结合时间范围或数据量限制来定义边界。例如,可以通过 `event_time` 字段限制查询的时间窗口: ```sql SET 'execution.runtime-mode' = 'BATCH'; SELECT * FROM kafka_source WHERE event_time BETWEEN '2023-01-01 00:00:00' AND '2023-01-01 23:59:59'; ``` 上述语句将以批处理模式运行,仅处理 `event_time` 在指定时间范围内的数据,从而形成有界流[^3]。 ### 动态边界控制 除了通过时间范围限制数据边界外,还可以通过 `LIMIT` 子句限制返回的记录数,从而实现基于数据量的边界控制: ```sql SELECT * FROM kafka_source WHERE event_time BETWEEN '2023-01-01 00:00:00' AND '2023-01-01 23:59:59' LIMIT 1000; ``` 该查询将处理指定时间范围内的前 1000 条记录,适用于一次性分析或测试目的。 ### 事件时间与时间戳抽取 Flink SQL 支持多种方式定义事件时间属性,确保在有界流处理中正确识别时间维度。例如,可以将 Kafka 消息中的时间戳字段作为事件时间: ```sql CREATE TABLE kafka_source ( `ts_field` TIMESTAMP(3), `user_id` STRING, `event_type` STRING, `event_time` STRING ) WITH ( 'connector' = 'kafka', 'topic' = 'your_kafka_topic', 'properties.bootstrap.servers' = 'localhost:9092', 'properties.group.id' = 'flink-sql-demo-group', 'format' = 'json' ) PARTITIONED BY (...) ROWTIME (`ts_field`); ``` 也可以使用 Kafka 消息自带的时间戳作为事件时间来源: ```sql ROWTIME (`ts_field`, 'kafka') ``` 此外,Flink 提供了灵活的时间戳抽取机制,支持从字段、数据流或自定义提取器中获取时间戳[^5]。 ### 总结 Flink SQL 提供了完整的机制来处理 Kafka 数据作为有界流,包括通过时间范围和数据量限制定义边界、设置事件时间属性以及使用批处理模式执行查询。通过这些功能,可以灵活地处理一次性数据任务,如历史数据分析、数据验证等。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值