当前位置: 首页 > news >正文

【数据工程】16. Notions of Time in Stream Processing

流处理中的时间概念(Notions of Time in Stream Processing)

流处理系统会区分三种不同的时间概念:事件时间(Event time)摄取时间(Ingestion time)处理时间(Processing time)
区分这些时间对于定义窗口(window)和正确处理乱序数据非常重要。

幻灯片用《星球大战(Star Wars)》系列电影的上映顺序来说明这个区别:

  • 事件时间(Event Time):是事件在现实世界中实际发生的时间。
    比如在星战宇宙中,“第四部”的剧情发生在时间线上最早,但它在现实上映时是 1977 年;
    后来拍摄的“第一部”(1999 年)反而在事件时间上更早。
    → 所以事件时间描述的是“逻辑顺序”或“发生时间”。

  • 处理时间(Processing Time):是系统处理数据的时间。
    对应到这个例子,就是电影真实上映的时间顺序:IV、V、VI、I、II、III、VII、VIII、IX(1977–2019)。
    → 系统可能按这个顺序接收和处理数据。

这说明:

  • 事件时间与处理时间不一定相同。
  • 数据可能乱序到达(out-of-order processing),系统必须能处理这种情况。
  • 我们可以选择按事件时间或处理时间定义窗口,取决于我们想要分析的逻辑。

事件时间与水位线(Event Time and Watermarks)

当流处理系统基于“事件时间”运行时,它需要有一种机制来衡量事件时间的进展。
因为事件的到达顺序不一定与它的时间戳顺序一致。

  • 事件时间(Event Time) 可以独立于 处理时间(Processing Time) 前进。
    例如,系统当前时间可能是下午 3 点,但仍在处理上午 10 点的事件。
    系统时钟(wall clock)并不反映事件流的真实“逻辑时间”。

  • 关键挑战:

    1. 乱序事件(Out-of-Order Events):事件到达顺序与事件时间不符;
    2. 延迟数据(Late Data):事件到达得太晚,可能落在已关闭的窗口之后。

水位线(Watermark)的作用

为了解决上述问题,流处理引擎(如 Flink)引入了 Watermark(时间水位线) 概念。

  • 水位线是一种声明(declaration):
    表示“截至此时(watermark 的时间戳),系统认为所有事件时间早于这个时间戳的事件都已经到达”。

  • 当一个算子(operator)收到水位线后,它可以:

    • 将自己的内部事件时间时钟(event-time clock)推进到水位线的时间;
    • 触发那些窗口结束时间早于该水位线的计算。

换句话说:
水位线是一种机制,用来告诉系统“现在可以安全地认为某一时间段的事件都到齐了”。

  • 数据流乱序到达(out of order);
  • 水位线 w(11) 表示系统认为 “时间 ≤ 11” 的事件都到齐;
  • 所以可以安全地计算窗口 [0, 11] 的聚合;
  • 后续的 w(17) 表示系统推进到 “时间 ≤ 17” 的阶段。

示例:Apache Flink 中的 Watermark 处理

Flink 的事件时间处理逻辑通过时间戳和水位线一起工作:

  1. 事件进入流中,并带有自己的事件时间戳;

  2. Watermark 策略(WatermarkStrategy) 会定期生成水位线;

    • 可以是固定周期;
    • 或在检测到某些“标点符号(punctuation)”时触发;
    • 或基于“允许最大延迟(allowed lateness)”计算。
  3. 晚到事件(late events):在水位线之后才到的事件,可以丢弃或特殊处理。

Flink 代码示例:

env.assignTimestampsAndWatermarks(WatermarkStrategy.for_bounded_out_of_orderness(Duration.ofSeconds(5))
)result = stream.window(TumblingEventTimeWindows.of(Duration.ofSeconds(10))).allowedLateness(Duration.ofSeconds(5)).sideOutputLateData(lateOutputStream)

解释:

  • 每 5 秒生成一次水位线;
  • 定义了一个 10 秒的滚动事件时间窗口
  • 系统允许事件最多延迟 5 秒;
  • 超过 5 秒仍未到的事件被认为是“晚到”,放到 lateOutputStream 里单独处理。

总结:

  • Watermark 让系统能在乱序环境中判断“何时窗口可以关闭”;
  • 同时允许对延迟数据设置一定容忍度,保证既不丢数据,也不阻塞计算。

流连接(Stream Joins):将流与其他数据结合

在流处理中,Join 是关键操作之一,用于将不同来源的数据结合起来。常见三种类型:

1. 传统表连接(Conventional table joins)

两个独立的数据流(Stream1、Stream2)分别对应两张表(Table1、Table2),
然后用传统数据库式 Join 算法产生结果。
→ 这适合“流入表”的批式场景,不是真实时流。

2. 丰富化(Enrichment)

使用静态的参考数据表来补充流数据。
比如:

  • 实时交易流(stream)输入;
  • 静态商品信息存储在 Redis 或数据库;
  • 实时连接两者,得到交易+商品详情的组合结果。

3. 流与流连接(Stream-to-Stream Joining)

两个实时流同时流入,一个专门的 Stream Join Processor 负责匹配。
例如订单流与支付流,或者传感器流与告警流。


流与表的连接(Stream-Table Join, Enrichment)

通过将流式数据与静态参考数据结合,可以进行更丰富的分析。

  • 挑战
    如何既能访问最新的参考数据,又不影响实时性能?
    因为直接查数据库会延迟很高。

  • 解决方案
    使用内存缓存(in-memory store)或外部高性能存储(如 Redis)加速查找。

  • 示例
    把实时交易流与 Redis 中的商品表关联(join)。

  • 最佳实践

    • 高频访问的数据放内存;
    • 大规模数据放外部存储;
    • 避免直接读取生产数据库(以免拖慢主系统)。

流与流的窗口连接(Stream-Stream Join, Windowed)

右侧表格演示了一个 15 秒窗口的流-流连接

假设:

  • 每条记录都有相同的连接键;
  • 所有记录按时间戳顺序处理;
  • 窗口长度为 15 秒。

工作机制:

  • 当左流(Left Stream)在时间戳 3 到达记录 A;
  • 右流(Right Stream)在时间戳 4 到达记录 a;
  • 它们都落在同一个窗口内,于是输出 [A, a];
  • 时间戳 5、6 的 B、b 同理;
  • 超过窗口范围的旧事件会被清除,不再参与匹配。

这种连接方式在实时分析中很常用,比如:

  • 实时匹配用户点击流与广告展示流;
  • 关联交易事件与支付确认事件。

总结(Summary)

  • 数据流查询(Data Stream Querying)

    • 查询是持续执行的(continuous querying);
    • 困难在于:流是无界的(unbounded),可能乱序(out-of-order)。
  • 窗口机制(Windowing)

    • 是从无限流中提取有限关系的机制;
    • 为聚合、连接等操作提供上下文边界。
  • 系统必须应对的挑战

    • 数据速率可能非常高、不稳定(variable/bursty);
    • 数据可能不可预测(unpredictable),时间乱序,延迟到达。

流处理工具(Tools for Stream Processing)

1. 概念回顾

Kafka 或 MQTT 自身 不是流处理引擎
它们只是消息传递(Pub/Sub)和数据存储系统。

真正的“流处理”是由 计算引擎(Stream Processor) 完成的。
最常见的流处理引擎是:

  • Apache Spark Streaming
  • Apache Flink

数据流处理架构(Data Stream Processing)

Flink 示例

  • Kafka 提供数据流的持久化和分发;
  • Flink 负责计算与一致性;
  • 输出结果可以写入 HDFS、Elasticsearch 或前端可视化。

Spark 示例

  • Spark Streaming 从 Kafka、Flume、HDFS、Kinesis、Twitter 等读取数据;
  • 执行实时计算;
  • 输出结果到 HDFS、数据库或仪表盘(Dashboards)。

使用 Apache Spark Streaming 的流处理(Data Stream Processing with Apache Spark Streaming)

  • Spark Streaming 是 Spark RDD API 的扩展

    • RDD(Resilient Distributed Dataset)是一种“弹性分布式数据集”。
  • 输入数据流被划分为多个 微批次(micro batches)
    Spark Engine 以批的方式处理这些小块。

  • 支持多种窗口:固定窗口、滑动窗口、翻转窗口。

  • 高层抽象:

    • Spark Streaming 中的流称为 DStream(Discretized Stream)
    • 实际上是由一系列按时间划分的 RDD 组成。

数据流经过的路径:

输入数据流 → Spark Streaming → Spark Engine → 处理后的输出流

这是一种“准实时(near real-time)”架构:
虽然不是逐条处理(像 Flink 那样是真正流式),但微批次的延迟通常很低,适用于大部分实时分析场景。

示例:Spark 实现流式 WordCount(Example: Data Stream WordCount with Spark)

这是一个使用 Spark Streaming 实现的实时单词计数示例。

代码逻辑说明:

from pyspark import SparkContext
from pyspark.streaming import StreamingContext# 创建本地 StreamingContext(两线程,每 1 秒一个批次)
sc = SparkContext("local[2]", "NetworkWordCount")
ssc = StreamingContext(sc, 1)# 从指定主机端口读取实时流(如 localhost:9999)
lines = ssc.socketTextStream("localhost", 9999)# 对每行进行分词
words = lines.flatMap(lambda line: line.split(" "))# 统计每个词出现的次数
pairs = words.map(lambda word: (word, 1))
wordCounts = pairs.reduceByKey(lambda x, y: x + y)# 打印每个批次的前几条结果
wordCounts.pprint()# 启动计算
ssc.start()# 等待任务终止
ssc.awaitTermination()

流程说明:

  1. 设定计算任务(setup computation)

    • 初始化 Spark Streaming 环境;
    • 连接网络输入流;
    • 定义处理逻辑(分词 → 映射 → 聚合)。
  2. 执行计算任务(execute computation)

    • 启动流处理;
    • 程序持续运行,直到手动停止。

示例输出说明(Example: Data Stream WordCount with Spark (output))

DStream(离散化流)由一系列按时间分割的 RDD 组成,每个 RDD 代表 1 秒的数据片段:

  • lines DStream:存储从 socket 读取的文本;
  • words DStream:经过 flatMap 分词后的单词流;
  • 每个时间段(time 0→1、1→2、2→3 等)都会生成新的 RDD。

输出示例:

终端 1(数据源)

$ nc -lk 9999
hello world

终端 2(运行 Spark 程序)

$ ./bin/spark-submit examples/src/main/python/streaming/network_wordcount.py localhost 9999
...
Time: 2014-10-14 15:25:21
-------------------------
(hello,1)
(world,1)

每一秒钟,Spark 会收集输入流的内容并输出每个词的计数。
这种方式属于 微批次(micro-batch)流处理:输入数据流按短时间片分批计算。


使用 Apache Flink 进行流数据处理(Data Stream Processing with Apache Flink)

Apache Flink 更贴近“真正的流式计算”,因为它在整个系统中都采用**流水线(pipelining)**机制。

主要特征:

  • Flink 的每个操作符都会立即将数据传递给下一个操作符;

  • 数据一到达就被处理,而不是等到批次结束;

  • 这使得 Flink 实现毫秒级低延迟处理

  • 与 Spark 的关键区别:

    • Spark 的处理阶段是分开的(stage by stage);
    • Flink 的阶段是重叠的(overlapping),属于连续数据流模式。

Flink 的结构包括:

  • DataStream API(用于流处理);
  • DataSet API(用于批处理);
  • 底层运行时 Runtime 是一个分布式流式数据流系统;
  • 可在单机、本地集群或云平台上运行。

示例:Flink 窗口聚合(Example: Window Aggregation with Flink)

目标: 每 10 秒计算一次股票价格的平均值、最高值、最低值。

数据流结构:

输入流:Stock Stream
窗口:10 秒滚动窗口,每 5 秒滑动一次
输出:MinBy PriceMaxBy PriceMean Price

代码逻辑:

// 定义时间窗口
WindowedDataStream<StockPrice> windowedStream = stockStream.window(Time.of(10, TimeUnit.SECONDS)).every(Time.of(5, TimeUnit.SECONDS));// 计算窗口内统计量
DataStream<StockPrice> lows = windowedStream.groupBy("symbol").minBy("price");DataStream<StockPrice> highs = windowedStream.groupBy("symbol").maxBy("price");DataStream<StockPrice> means = windowedStream.groupBy("symbol").mapWindow(new WindowMean()).flatten();

自定义函数 WindowMean

public final class WindowMean implements WindowMapFunction<StockPrice, StockPrice> {public void mapWindow(Iterable<StockPrice> values, Collector<StockPrice> out) {double sum = 0;int count = 0;String symbol = "";for (StockPrice sp : values) {sum += sp.price;symbol = sp.symbol;count++;}out.collect(new StockPrice(symbol, sum / count));}
}

该示例展示了如何通过窗口机制在实时流上计算统计指标。


Apache Flink 支持的三种时间概念(Apache Flink Supports Three Notions of Time)

Flink 完全支持三种时间语义:

  1. 事件时间(Event Time):事件实际发生的时间;
  2. 摄取时间(Ingestion Time):事件进入 Flink 数据源的时间;
  3. 处理时间(Processing Time):Flink 操作符处理该事件的系统时间。

流程图:

  • 数据由事件生产者产生;
  • 经过消息队列(如 Kafka)的不同分区;
  • 被 Flink Data Source 接收;
  • 进入窗口算子(Window Operator);
  • 每个阶段都可能基于不同时间语义来驱动计算。

Flink 示例:时间定义(Flink Example: Time Definition)

在 Flink 中,可以灵活定义流处理使用的时间语义:

final StreamExecutionEnvironment env =StreamExecutionEnvironment.getExecutionEnvironment();// 使用处理时间(默认)
env.setStreamTimeCharacteristic(TimeCharacteristic.ProcessingTime);// 也可以选择:
// env.setStreamTimeCharacteristic(TimeCharacteristic.IngestionTime);
// env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);DataStream<MyEvent> stream = env.addSource(new FlinkKafkaConsumer09<>(topic, schema, props));stream.keyBy(event -> event.getUser()).timeWindow(Time.hours(1)).reduce((a, b) -> a.add(b)).addSink(...);

含义:

  • 可以根据需要设定时间类型;
  • 以事件时间为基准可获得精确的逻辑窗口;
  • 以处理时间为基准可获得最快的实时响应;
  • 以摄取时间为中间折中方案。

Spark 与 Flink 的差异(Differences between Spark and Flink)

特性Apache SparkApache Flink
原理基于阶段的集合式数据转换基于流水线的连续数据流
数据抽象RDDDataSet
处理阶段各阶段分离阶段重叠
优化器SparkSQL 模块集成于 API 内部
批处理使用 RDD使用 DataSet
流处理微批次(micro-batching)真正的流式处理(pipelining, DataStream API)

总结:

  • Spark 更偏向批处理思维;
  • Flink 更偏向低延迟流计算;
  • Spark 适合复杂批量分析;
  • Flink 适合实时计算与持续数据流。

总结(Summary)

数据流处理的基本原理(Data Stream Processing Principles)

  • 包括窗口聚合(window aggregation)和多种时间语义;
  • 核心在于:如何在无限流中提取有限片段做分析。

流处理架构(Stream Processing Architectures)

  • 基于消息的发布/订阅系统:Apache KafkaMQTT

  • 流处理引擎:

    • Apache Spark:通过 Spark Streaming 实现流式处理(基于 RDD 微批次);
    • Apache Flink:真正的实时流处理框架,支持流水线并行和低延迟。

二者互补:

  • Spark 更适合批+流一体场景;
  • Flink 更适合实时、高吞吐、低延迟的连续数据流应用。
http://www.dtcms.com/a/540152.html

相关文章:

  • AOI在传统汽车制造领域中的应用
  • 搭建网站复杂吗微信公众号怎么做链接网站
  • 网站优化推广招聘wordpress后台打开超慢
  • Linux软件编程笔记三——标准IO(二进制)文件IO
  • 如何使用 TinyEditor 快速部署一个协同编辑器
  • pgsql常用函数
  • 企业落地 NL2SQL,需要的是 AI-ready data 和小模型
  • 最好的购物网站排名厦门的推广公司有哪些
  • PyTorch2 Python深度学习 - 初识PyTorch2,实现一个简单的线性神经网络
  • 外贸网站建设gif制作软件app
  • 我回来了,依然关注新能源汽车研发测试,
  • Go 语言数组
  • Go语言-->sync.WaitGroup 详细解释
  • 从“造机器”到“造生态”:中国智能时代的系统跃迁——从宇树实训平台到视频神经系统的启示
  • YOLOV5_TensorRT_C++部署
  • 海南省住房和城乡建设官方网站网站域名不备案
  • 网络空间引擎
  • VANCHIP射频芯片:智能汽车的“第六感”觉醒
  • C++——二叉搜索树——数据结构进阶——附加超详细解析过程/代码实现
  • 网站页面两侧漂浮的怎样做电商网站前端页面内容编写
  • PCIE学习
  • API Key 管理与计费系统模块(API Gateway 模块)需求文档
  • 2024-2025年技术发展趋势深度分析:AI、前端与后端开发的革新之路
  • vue3 实现贪吃蛇 电脑版01
  • 做网站带后台多少钱东莞做网站 动点官网
  • 郑州做网站建设wordpress数据控查看密码
  • 数据采集-BeautifulSoup库
  • 帝国cms的阅读量增加的api接口示例
  • RDF 实例
  • 面向对象编程:继承从理论到实战