写点什么

大数据 -120 - Flink 滑动窗口(Sliding Window)详解:原理、应用场景与实现示例 基于时间驱动 & 基于事件驱动

作者:武子康
  • 2025-10-10
    山东
  • 本文字数:5068 字

    阅读完需:约 17 分钟

大数据-120 - Flink滑动窗口(Sliding Window)详解:原理、应用场景与实现示例 基于时间驱动&基于事件驱动

点一下关注吧!!!非常感谢!!持续更新!!!

🚀 AI 篇持续更新中!(长期更新)

AI 炼丹日志-31- 千呼万唤始出来 GPT-5 发布!“快的模型 + 深度思考模型 + 实时路由”,持续打造实用 AI 工具指南!📐🤖

💻 Java 篇正式开启!(300 篇)

目前 2025 年 10 月 07 日更新到:Java-141 深入浅出 MySQL Spring 事务失效的常见场景与解决方案详解(3)MyBatis 已完结,Spring 已完结,Nginx 已完结,Tomcat 已完结,分布式服务正在更新!深入浅出助你打牢基础!

📊 大数据板块已完成多项干货更新(300 篇):

包括 Hadoop、Hive、Kafka、Flink、ClickHouse、Elasticsearch 等二十余项核心组件,覆盖离线+实时数仓全栈!大数据-278 Spark MLib - 基础介绍 机器学习算法 梯度提升树 GBDT 案例 详解


章节内容

上节我们完成了如下的内容:


  • Flink Window 背景总览

  • Flink Window 滚动时间窗口

  • 基于时间驱动

  • 基于事件驱动


滑动时间窗口


滑动窗口是固定窗口更广义的一种形式,它通过引入滑动间隔实现了窗口的动态移动。滑动窗口由固定的窗口长度(window size)和滑动间隔(slide interval)两个关键参数组成,其中窗口长度决定了每个窗口包含的数据范围,而滑动间隔则控制着窗口的移动频率。


Flink 的滑动时间窗口(Sliding Window)是一种特别适用于流式数据处理场景的窗口机制。它能够在持续流动的数据流中,按照设定的时间范围定期进行数据计算和聚合。这种窗口机制广泛应用于实时监控、异常检测、趋势分析等需要对数据进行周期性分析的场景。例如,在电商平台中,可以使用窗口长度为 1 小时、滑动间隔为 5 分钟的滑动窗口来实时统计近一小时的销售额变化趋势。


具体实现时,滑动窗口会按照指定的窗口大小和滑动步长不断地在数据流上滑动。比如设置窗口大小为 10 分钟、滑动步长为 5 分钟,那么每个窗口会包含 10 分钟的数据,但每隔 5 分钟就会产生一个新的窗口。这样的设计使得相邻窗口之间存在 5 分钟的重叠数据,从而确保计算结果的连续性。对于每个窗口内的数据,Flink 都会独立执行预定义的聚合函数(如 sum、count、avg 等)进行计算。


与固定窗口相比,滑动窗口的优势在于它能够提供更细粒度的时间覆盖,避免重要数据被窗口边界分割。但同时也会带来更高的计算开销,因为相同的数据可能会被多个窗口重复计算。在实际应用中,需要根据业务需求和数据特点,在计算精度和性能开销之间找到合适的平衡点。

类型特点

窗口长度固定,可以有重叠。滑动窗口是一种常用的数据处理模式,具有以下特点:


  1. 窗口重叠机制

  2. 滑动窗口会有重叠部分,因此每个事件可能会被包含在多个窗口中

  3. 重叠程度由窗口大小和滑动步长决定。例如:

  4. 窗口大小为 5 分钟,滑动步长为 1 分钟,则重叠部分为 4 分钟

  5. 窗口大小为 1 小时,滑动步长为 30 分钟,则重叠部分为 30 分钟

  6. 典型应用场景

  7. 滑动窗口更适合定期计算某个时间范围内的聚合值,像是:

  8. 移动平均值(如股票 5 日均线)

  9. 最近一段时间的活跃用户统计(如过去 24 小时内活跃用户数)

  10. 实时流量监控(如每分钟请求量)

  11. 传感器数据平滑处理(如温度传感器 5 秒均值)

  12. 实现方式

  13. 基于时间:按固定时间间隔滑动(如每 1 分钟计算一次过去 5 分钟的数据)

  14. 基于事件数量:每收到 N 个事件就计算一次最近 M 个事件的数据

  15. 混合模式:同时考虑时间和事件数量触发计算

  16. 计算特点

  17. 增量计算:可以复用重叠部分的计算结果,提高效率

  18. 边界处理:需要考虑窗口边界事件的归属问题

  19. 状态管理:需要维护窗口状态,特别是长窗口的场景

  20. 优势比较

  21. 相比滚动窗口(无重叠),能提供更平滑的数据变化趋势

  22. 相比会话窗口(基于事件间隔),能保证定期输出计算结果

  23. 特别适合需要连续监控和实时响应的应用场景

关键参数

窗口大小(window size)

窗口大小定义了每个时间窗口所包含的数据范围,是流处理中最重要的参数之一。它表示系统处理数据时划分的时间段长度,通常以时间单位(秒、分钟、小时)表示。例如:


  • 10 秒窗口:系统每 10 秒收集的数据作为一个处理单元

  • 1 分钟窗口:每分钟的数据作为一个批次处理


窗口大小直接影响:


  1. 数据处理延迟:窗口越大,延迟越高

  2. 结果精确度:窗口越小,结果越实时

  3. 系统负载:窗口越小,计算频率越高

滑动步长(slide interval)

滑动步长决定了窗口移动的频率,即系统创建新窗口的时间间隔。这个参数控制着:


  • 窗口重叠程度:当步长小于窗口大小时,会产生窗口重叠

  • 计算触发频率:步长越小,计算触发越频繁


典型配置示例:


  1. 10 秒窗口+5 秒步长:

  2. 窗口 1:00:00-00:10

  3. 窗口 2:00:05-00:15

  4. 窗口 3:00:10-00:20

  5. 这样每 5 秒就会产生一个包含 10 秒数据的新窗口

  6. 1 分钟窗口+30 秒步长:

  7. 窗口 1:00:00-01:00

  8. 窗口 2:00:30-01:30

  9. 窗口 3:01:00-02:00


应用场景:


  • 实时监控系统:5 秒窗口+1 秒步长,实现准实时的监控报警

  • 每日统计报表:24 小时窗口+24 小时步长,每天生成一次完整报表

  • 用户行为分析:30 分钟窗口+5 分钟步长,平衡实时性和计算开销

基于时间驱动

场景:我们可以每 30 秒计算一次最近一分钟用户购买的商品数


package icu.wzk;public class SlidingWindow {
public static void main(String[] args) throws Exception { StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); env.setParallelism(1); DataStreamSource<String> dataStreamSource = env.socketTextStream("localhost", 9999); SingleOutputStreamOperator<Tuple2<String, Integer>> mapStream = dataStreamSource .map(new MapFunction<String, Tuple2<String, Integer>>() { @Override public Tuple2<String, Integer> map(String value) throws Exception { SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); long timeMillis = System.currentTimeMillis(); int random = new Random().nextInt(10); System.out.println("value: " + value + ", random: " + random + ", timestamp: " + format.format(timeMillis)); return Tuple2.of(value, random); } }); KeyedStream<Tuple2<String, Integer>, Tuple> keyedStream = mapStream .keyBy(new KeySelector<Tuple2<String, Integer>, Tuple>() { @Override public Tuple getKey(Tuple2<String, Integer> value) throws Exception { return Tuple1.of(value.f0); } }); WindowedStream<Tuple2<String, Integer>, Tuple, TimeWindow> timeWindow = keyedStream .timeWindow(Time.seconds(10), Time.seconds(5)); timeWindow.apply(new MyTimeWindowFunction()).print(); env.execute("SlidingWindow"); }
}
复制代码

基于事件驱动

package icu.wzk;public class SlidingWindow {
public static void main(String[] args) throws Exception { StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); env.setParallelism(1); DataStreamSource<String> dataStreamSource = env.socketTextStream("localhost", 9999); SingleOutputStreamOperator<Tuple2<String, Integer>> mapStream = dataStreamSource .map(new MapFunction<String, Tuple2<String, Integer>>() { @Override public Tuple2<String, Integer> map(String value) throws Exception { SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); long timeMillis = System.currentTimeMillis(); int random = new Random().nextInt(10); System.out.println("value: " + value + ", random: " + random + ", timestamp: " + format.format(timeMillis)); return Tuple2.of(value, random); } }); KeyedStream<Tuple2<String, Integer>, Tuple> keyedStream = mapStream .keyBy(new KeySelector<Tuple2<String, Integer>, Tuple>() { @Override public Tuple getKey(Tuple2<String, Integer> value) throws Exception { return Tuple1.of(value.f0); } }); WindowedStream<Tuple2<String, Integer>, Tuple, GlobalWindow> globalWindow = keyedStream .countWindow(3, 2); globalWindow.apply(new MyCountWindowFuntion()).print(); env.execute("SlidingWindow"); }
}
复制代码

会话窗口

由一系列事件组合一个指定时间长度 timeout 间隙组成,类似于 Web 应用的 Session,也就是一段时间没有接收到新数据会生成新的窗口。Session 窗口分配器通过 Session 活动来对元素进行分组,Session 窗口跟滚动窗口和滑动窗口相比,不会有重叠和固定的开始时间和结束时间的情况。Session 窗口在一个固定的时间周期内不再收到元素,即非活动间隔产生,那么这个窗口就会关闭。一个 Session 窗口通过一个 Session 间隔来配置,这个 Session 间隔定义了非活跃周期的长度,当这个非活跃周期产生,那么当前的 Session 将关闭并且后续的元素将被分配到新的 Session 窗口去。

类型特点

会话窗口(Session Window)是一种特殊的时间窗口类型,具有以下具体特点:


  1. 非重叠性

  2. 会话窗口之间完全独立,不会出现时间重叠

  3. 每个窗口都是单独存在的个体

  4. 不同于翻滚窗口的固定分割和滑动窗口的重叠特性

  5. 动态时间边界

  6. 没有预设的固定开始和结束时间

  7. 窗口的开启由第一个到达的元素触发

  8. 窗口的关闭取决于配置的超时时间(Session Gap)

  9. 基于活动的窗口机制

  10. 当超过配置的会话间隙(Session Gap)时间没有新元素到达时,当前会话窗口会自动关闭

  11. 例如:如果设置 Session Gap 为 5 分钟,当超过 5 分钟没有新数据,当前窗口就会结束

  12. 自适应分割

  13. 后续到达的元素会触发新会话窗口的创建

  14. 每个新窗口都独立于之前的窗口

  15. 窗口持续时间完全取决于数据到达模式


应用场景示例:


  • 用户行为分析:将用户连续的操作记录作为一个会话

  • 网络会话管理:TCP 连接的开始和结束

  • 电商场景:用户的一次完整购物流程


技术实现特点:


  • 需要维护每个键(key)的最新活动时间戳

  • 需要定期检查超时的窗口

  • 适合处理不规律到达的数据流


与常规窗口的对比:


  • 翻滚窗口:固定大小,固定间隔

  • 滑动窗口:固定大小,可重叠

  • 会话窗口:动态大小,不重叠

基于时间驱动

package icu.wzk;public class SessionWindow {
public static void main(String[] args) throws Exception { StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); env.setParallelism(1); DataStreamSource<String> dataStreamSource = env.socketTextStream("localhost", 9999); SingleOutputStreamOperator<Tuple2<String, Integer>> mapStream = dataStreamSource .map(new MapFunction<String, Tuple2<String, Integer>>() { @Override public Tuple2<String, Integer> map(String value) throws Exception {
return null; } }); KeyedStream<Tuple2<String, Integer>, Tuple> keyedStream = mapStream .keyBy(new KeySelector<Tuple2<String, Integer>, Tuple>() { @Override public Tuple getKey(Tuple2<String, Integer> value) throws Exception { return Tuple1.of(value.f0); } }); WindowedStream<Tuple2<String, Integer>, Tuple, TimeWindow> window = keyedStream .window(ProcessingTimeSessionWindows.withGap(Time.seconds(10))); window.apply(new MyTimeWindowFunction()).print(); env.execute("SessionWindow"); }
}
复制代码


发布于: 刚刚阅读数: 4
用户头像

武子康

关注

永远好奇 无限进步 2019-04-14 加入

Hi, I'm Zikang,好奇心驱动的探索者 | INTJ / INFJ 我热爱探索一切值得深究的事物。对技术、成长、效率、认知、人生有着持续的好奇心和行动力。 坚信「飞轮效应」,相信每一次微小的积累,终将带来深远的改变。

评论

发布
暂无评论
大数据-120 - Flink滑动窗口(Sliding Window)详解:原理、应用场景与实现示例 基于时间驱动&基于事件驱动_Java_武子康_InfoQ写作社区