2015年,Twitter在SIGMOD发表论文宣布了一个令人震惊的数据:他们用新系统Heron替换了运行多年的Storm后,吞吐量提升了14倍,延迟降低了10倍,资源消耗却减少了三分之二。这不仅仅是性能数字的跃升,更揭示了流处理系统设计哲学的根本性分歧。

流处理并非新技术。早在1992年,Tapestry系统就首次提出了流式查询的概念。但真正让流处理成为企业基础设施核心组件的,是过去二十年开源生态的爆发式演进。从Apache Storm的开创性工作,到Spark Streaming的微批处理模型,再到Apache Flink的原生流处理架构,每一次范式转变背后都蕴含着深刻的技术权衡。

无限流的有限处理:流处理的本质问题

流处理面对的核心挑战可以用一个数学问题来描述:如何在一个无界(unbounded)无序(unordered)的数据流上,产生确定(deterministic)、**一致(consistent)**的计算结果?

传统批处理假设数据是有限的、静态的——查询执行完毕后,结果就固定了。但流处理面对的是一条永不停息的数据河流,结果需要随着新数据的到达持续更新。更棘手的是,分布式系统中网络延迟、时钟漂移、故障恢复等因素会导致数据乱序到达,如何保证计算结果的正确性?

Google在2013年发表的Millwheel论文中提出了三个核心概念,奠定了现代流处理的理论基础:**事件时间(Event Time)处理时间(Processing Time)**的分离、水位线(Watermark)机制、以及Exactly-once语义。这三个概念成为后续所有流处理系统必须回答的问题。

graph TD
    subgraph "事件时间 vs 处理时间"
        E1[事件发生<br/>Event Time: 10:00:00] --> D1[网络延迟]
        D1 --> E2[事件到达<br/>Processing Time: 10:00:05]
        
        E3[事件发生<br/>Event Time: 10:00:02] --> D2[网络延迟更短]
        D2 --> E4[事件到达<br/>Processing Time: 10:00:03]
    end
    
    style E1 fill:#e1f5fe
    style E3 fill:#e1f5fe
    style E2 fill:#fff3e0
    style E4 fill:#fff3e0

第一代:Apache Storm的开创与困境

2011年,Nathan Marz在Twitter开源了Storm,这是第一个真正意义上被大规模工业采用的分布式流处理系统。Storm的设计哲学可以用一句话概括:流是无界的元组序列,计算是拓扑图上的持续流动

Storm的核心抽象是Topology(拓扑)——一个由Spout(数据源)Bolt(处理节点)组成的有向无环图。Spout从外部数据源(如Kafka)读取数据并发射Tuple(元组),Tuple沿着拓扑图流动,经过各个Bolt的处理后输出结果。

graph LR
    subgraph "Storm拓扑架构"
        S[Spout<br/>数据源] --> B1[Bolt 1<br/>过滤]
        B1 --> B2[Bolt 2<br/>聚合]
        B1 --> B3[Bolt 3<br/>转换]
        B2 --> B4[Bolt 4<br/>输出]
        B3 --> B4
    end
    
    style S fill:#4caf50,color:#fff
    style B1 fill:#2196f3,color:#fff
    style B2 fill:#2196f3,color:#fff
    style B3 fill:#2196f3,color:#fff
    style B4 fill:#ff9800,color:#fff

Storm的可靠性保证依赖于其独特的Acker机制。每个Tuple在Spout发射时被赋予一个唯一的消息ID,后续每个Bolt在处理并发射新Tuple时,会将新Tuple与输入Tuple"锚定"(anchor)。一棵Tuple树就这样在拓扑中生长,当整棵树被成功处理完毕,Acker会通知Spout进行确认(ack);如果处理失败或超时,Spout会重发该Tuple。

这个设计巧妙地实现了At-least-once语义,但也埋下了隐患。首先,Acker机制需要在内存中维护所有正在处理的Tuple树,在大吞吐场景下内存压力巨大。其次,Tuple重放会导致重复计算——如果一个聚合操作收到了重复的Tuple,结果就会错误。最后,Storm没有内置的状态管理机制,开发者需要自己处理状态的持久化和恢复。

Twitter在论文中披露的数据揭示了这些问题的代价:在处理每秒数百万条消息的生产环境中,Storm的垃圾回收停顿时间可以达到数秒,导致严重的延迟抖动。更关键的是,缺乏Exactly-once语义使得Storm无法用于金融、计费等对数据准确性要求极高的场景。

第二代:Spark Streaming的微批处理折中

2013年,AMPLab在Spark基础上推出了Spark Streaming,提出了一种完全不同的设计思路:既然无限流难以处理,为什么不把它切成有限的小批次?

Spark Streaming的核心抽象是DStream(Discretized Stream)。系统按照固定的时间间隔(如1秒、5秒)将到达的数据切分成一个个微批次(Micro-batch),每个批次内的数据被封装成一个RDD,然后使用Spark的批处理引擎进行处理。

graph TD
    subgraph "微批处理模型"
        S[数据流] --> B1[批次 1<br/>t=0~1s]
        S --> B2[批次 2<br/>t=1~2s]
        S --> B3[批次 3<br/>t=2~3s]
        S --> B4[批次 4<br/>t=3~4s]
        
        B1 --> P1[Spark RDD处理]
        B2 --> P2[Spark RDD处理]
        B3 --> P3[Spark RDD处理]
        B4 --> P4[Spark RDD处理]
    end
    
    style S fill:#e8f5e9
    style B1 fill:#bbdefb
    style B2 fill:#bbdefb
    style B3 fill:#bbdefb
    style B4 fill:#bbdefb
    style P1 fill:#fff9c4
    style P2 fill:#fff9c4
    style P3 fill:#fff9c4
    style P4 fill:#fff9c4

这个设计带来的最大优势是复用Spark生态系统。开发者可以使用相同的API处理批数据和流数据,可以无缝地在流处理作业中使用Spark SQL、MLlib等组件。更重要的是,由于每个批次都是有限数据集,Spark Streaming可以轻松实现Exactly-once语义——只需在每个批次处理完毕后原子性地提交结果即可。

但微批处理模型有无法回避的代价。首先是延迟:系统必须等待一个完整的批次间隔才能开始处理数据,这意味着最小延迟就是批次大小。在实践中,为了保证吞吐量,批次大小通常设置在500毫秒到几秒之间,这对于需要亚秒级响应的场景是不可接受的。

其次是吞吐量的不均匀性。假设批次大小为1秒,如果某秒内的数据量突然激增,系统可能无法在下一个批次到来前处理完毕,导致延迟累积。Spark Streaming通过**背压(Backpressure)**机制动态调整消费速率来缓解这个问题,但本质上仍然是"头痛医头"。

Yahoo在2015年的基准测试中对比了Storm、Spark Streaming和Flink的性能。结果显示,在99%延迟指标上,Flink和Storm可以达到10-20毫秒级别,而Spark Streaming受限于批次大小,延迟在数百毫秒到数秒之间波动。

第三代:Apache Flink的原生流处理革命

Apache Flink的起源可以追溯到2010年柏林工业大学的Stratosphere研究项目。与Spark Streaming"用批模拟流"的思路相反,Flink的设计哲学是**“流是第一公民,批是流的特例”**。

Flink的核心抽象是DataStream——一个真正的、无边界的流。每条数据到达后立即被处理,不需要等待批次积累。这种**原生流处理(Native Streaming)**模型消除了微批处理的人为延迟,将端到端延迟降低到毫秒级别。

但Flink真正的突破在于状态管理容错机制的设计。

Chandy-Lamport算法的工程化

1985年,K. Mani Chandy和Leslie Lamport在ACM TOCS上发表了著名的论文《Distributed Snapshots》,提出了一种在分布式系统中获取一致快照的算法。Flink将这个算法改造为Barrier Snapshot机制,成为其容错能力的基石。

sequenceDiagram
    participant JM as JobManager
    participant S1 as Source 1
    participant S2 as Source 2
    participant OP as Operator
    participant SK as Sink
    
    JM->>S1: 触发Checkpoint
    JM->>S2: 触发Checkpoint
    
    S1->>S1: 保存状态
    S2->>S2: 保存状态
    
    S1->>OP: 发送Barrier
    S2->>OP: 发送Barrier
    
    Note over OP: 等待所有Barrier对齐
    
    OP->>OP: 保存状态
    OP->>SK: 发送Barrier
    
    SK->>SK: 保存状态
    SK->>JM: 确认Checkpoint完成

具体实现如下:当JobManager决定触发一次Checkpoint时,它会向所有数据源注入一个Barrier(屏障)。Barrier随数据流流动,当算子收到Barrier时,会暂停处理后续数据,将自己的状态写入持久化存储,然后向下游发射Barrier。当所有Barrier都流经整个拓扑并到达Sink后,一次全局一致的快照就完成了。

这个设计的精妙之处在于:不需要全局暂停。各个算子可以在不同时间点完成状态快照,只要保证Barrier对齐,最终就能得到一致的快照。这意味着Checkpoint过程对业务逻辑的影响被最小化。

增量Checkpoint与状态后端

对于有状态的计算(如窗口聚合、去重、Join),状态大小可能达到数十GB甚至TB级别。每次全量快照显然不可持续。Flink引入了增量Checkpoint机制:只记录自上次Checkpoint以来变化的状态数据。

配合RocksDB状态后端,Flink可以将状态存储在本地磁盘并异步上传到分布式存储。RocksDB是一个嵌入式LSM-tree数据库,其写入性能随着数据量增长保持稳定。这使得Flink能够处理几乎无限大小的状态。

阿里巴巴在2019年的技术博客中披露,他们的Flink集群管理的状态总量达到PB级别,单个作业的状态大小超过10TB。这在Storm时代是无法想象的。

两阶段提交实现端到端Exactly-once

Checkpoint解决了内部状态的容错问题,但流处理系统通常需要与外部系统交互——从Kafka读取数据,将结果写入数据库。如何保证整个链路的Exactly-once语义?

Flink采用了两阶段提交协议(Two-Phase Commit, 2PC)。以Kafka为例:

sequenceDiagram
    participant S as Source
    participant J as JobManager
    participant SK as Kafka Sink
    participant K as Kafka
    
    Note over S,K: 第一阶段:Pre-commit
    
    S->>S: 处理数据
    S->>SK: 发送数据
    
    SK->>K: 开启事务
    SK->>K: 写入数据(未提交)
    
    J->>SK: Checkpoint完成通知
    
    Note over S,K: 第二阶段:Commit
    
    SK->>K: 提交事务
    K->>K: 数据可见
    
    alt Checkpoint失败
        SK->>K: 回滚事务
        K->>K: 数据丢弃
    end

第一阶段(Pre-commit):当算子完成Checkpoint后,Kafka Sink会预提交事务,将数据写入Kafka但标记为"未提交"状态。

第二阶段(Commit):当所有算子的Checkpoint都成功完成后,JobManager通知所有Sink正式提交事务。如果任何一个算子的Checkpoint失败,所有Sink都会回滚事务。

这个设计要求外部系统支持事务或幂等写入。对于不支持事务的系统(如普通数据库),开发者需要实现幂等写入逻辑或接受At-least-once语义。

并行演进:Kafka Streams、Heron、Samza的三条路线

在Storm、Spark Streaming、Flink三大主流系统之外,几条并行的技术路线也在演进,各自针对不同的场景做出了独特的权衡。

Kafka Streams:轻量级的嵌入式方案

2016年,Confluent推出了Kafka Streams,这是一款轻量级流处理库——注意是"库"而非"框架"。开发者不需要部署独立的集群,流处理逻辑直接运行在应用程序进程中。

Kafka Streams的设计哲学是:既然大多数流处理应用都以Kafka作为数据源和数据汇,为什么不直接利用Kafka的能力?

其核心创新是流表对偶性(Stream-Table Duality):一个Kafka Topic既可以被视为追加写入的流,也可以被视为持续更新的表。Kafka Streams通过Changelog Topic实现状态持久化——所有状态变更都写入一个内部Topic,恢复时从该Topic重放。这与数据库的Write-Ahead Log异曲同工。

Kafka Streams支持Exactly-once语义,实现方式是利用Kafka的事务机制。在一个事务中,应用可以原子性地消费输入、更新状态、生产输出。这种设计的代价是只能与Kafka深度绑定,但好处是架构简洁、运维成本低。

LinkedIn在技术博客中披露,他们使用Kafka Streams处理超过10000个流处理任务,涵盖了用户画像更新、广告投放、推荐系统等核心业务。

Twitter Heron:Storm的继承者

面对Storm在生产环境中暴露的问题,Twitter在2015年推出了Heron。Heron的核心设计目标是在保持与Storm API完全兼容的前提下,解决Storm的可扩展性、调试性和资源效率问题。

Heron的架构创新在于进程级隔离。每个处理实例(Heron称之为Instance)运行在独立的进程中,而不是像Storm那样所有实例共享一个JVM。这样做的好处是:

  1. 单个实例的故障不会影响其他实例
  2. 可以精确监控每个实例的资源消耗
  3. 内存泄漏等问题更容易定位

Heron还引入了Backpressure机制:当下游处理不过来时,会向上游发送信号减慢数据发射速率,而不是简单地丢弃数据或让队列爆炸。

Twitter的论文显示,Heron在相同硬件配置下,吞吐量比Storm高2-14倍,延迟降低10-100倍。但Heron并没有解决Storm缺乏Exactly-once语义的核心问题,这限制了其在金融等高可靠性场景的应用。

Apache Samza:LinkedIn的中间路线

LinkedIn在开发Kafka的同时,也在构建自己的流处理系统Samza。Samza的设计哲学可以概括为:利用现有基础设施的能力,而不是重新发明轮子

Samza与Kafka、YARN深度集成:Kafka提供消息传递和状态持久化,YARN提供资源管理和进程隔离。这种设计使得Samza可以快速落地,但也限制了其灵活性。

Samza的一个重要创新是本地状态存储:每个任务维护一个嵌入式RocksDB实例作为状态存储,避免了跨网络访问状态的延迟。状态变更通过Kafka Changelog Topic实现持久化和恢复。

LinkedIn的论文显示,Samza在生产环境中处理超过800亿条消息/天,支撑了消息推送、广告排序等核心业务。但随着Kafka Streams的推出,Samza的重要性有所下降。

核心技术突破:从概念到工程实现

流处理系统二十年演进的本质,是将学术概念转化为可大规模部署的工程实践。几个核心技术突破贯穿始终。

事件时间与水位线:处理乱序数据的数学方案

在理想世界中,数据按照事件发生的顺序到达处理系统。但在分布式系统中,网络延迟、时钟不同步、重试机制等因素会导致数据乱序到达。如果按照到达顺序(处理时间)进行窗口计算,结果将无法复现。

Google Millwheel论文提出的水位线(Watermark)机制优雅地解决了这个问题。水位线是一个时间戳标记,语义是:“所有事件时间小于等于该时间戳的数据都已经到达”

graph LR
    subgraph "水位线推进机制"
        D1[数据 t=3] --> D2[数据 t=5]
        D2 --> D3[数据 t=4<br/>迟到数据]
        D3 --> W1[水位线 W=4]
        W1 --> D4[数据 t=7]
        D4 --> D5[数据 t=6<br/>迟到数据]
        D5 --> W2[水位线 W=6]
        
        W1 -.->|触发| W1_T[窗口 [0,4]<br/>可以计算]
        W2 -.->|触发| W2_T[窗口 [4,6]<br/>可以计算]
    end
    
    style W1 fill:#4caf50,color:#fff
    style W2 fill:#4caf50,color:#fff
    style W1_T fill:#ffeb3b
    style W2_T fill:#ffeb3b
    style D3 fill:#f44336,color:#fff
    style D5 fill:#f44336,color:#fff

水位线的生成策略通常基于启发式假设。最常见的是**有界乱序(Bounded Out-of-Orderness)**策略:假设数据的乱序程度不会超过某个阈值D,那么当收到事件时间为T的数据时,可以认为事件时间小于T-D的数据都已经到达。

当水位线推进到某个窗口的结束时间,系统就可以安全地触发该窗口的计算并输出结果。对于迟到的数据(事件时间早于当前水位线),系统可以选择丢弃、侧输出或触发更新计算。

Flink将水位线机制实现为数据流中的特殊元素,随数据流动并触发计算。这使得开发者可以专注于业务逻辑,而不必关心乱序处理的复杂性。

窗口操作的演进:从固定到动态

窗口(Window)是流处理的核心概念——将无限流切分为有限块以便聚合计算。不同窗口类型适用于不同场景:

graph TD
    subgraph "窗口类型对比"
        subgraph "滚动窗口 Tumbling"
            T1[窗口1<br/>0-5s] --> T2[窗口2<br/>5-10s] --> T3[窗口3<br/>10-15s]
        end
        
        subgraph "滑动窗口 Sliding"
            S1[窗口1<br/>0-10s] --> S2[窗口2<br/>2-12s] --> S3[窗口3<br/>4-14s]
        end
        
        subgraph "会话窗口 Session"
            E1[事件组1] --- G1[间隔]
            G1 --- E2[事件组2] --- G2[间隔]
            G2 --- E3[事件组3]
        end
    end
    
    style T1 fill:#e3f2fd
    style T2 fill:#e3f2fd
    style T3 fill:#e3f2fd
    style S1 fill:#fff3e0
    style S2 fill:#fff3e0
    style S3 fill:#fff3e0
    style E1 fill:#e8f5e9
    style E2 fill:#e8f5e9
    style E3 fill:#e8f5e9

滚动窗口(Tumbling Window):固定大小、不重叠。适用于周期性报告,如每5分钟的UV统计。

滑动窗口(Sliding Window):固定大小、按步长滑动。适用于移动平均计算,如每1分钟计算过去1小时的平均值。

会话窗口(Session Window):基于数据活动动态划分大小。适用于用户行为分析,如一次会话中的所有点击。

窗口操作的工程实现面临两个挑战:状态管理和**触发器(Trigger)**设计。

状态管理方面,每个窗口需要维护中间状态。当窗口数量巨大时(如按用户ID分组,每个用户一个会话窗口),状态可能爆炸。Flink通过状态TTL(Time-To-Live)机制自动清理过期状态,以及增量聚合(Incremental Aggregation)减少状态大小。

触发器设计方面,何时触发窗口计算需要权衡延迟和完整性。水位线到达时触发可以保证正确性,但延迟可能较长;提前触发可以降低延迟,但结果可能不完整。Flink允许开发者自定义触发策略,如"水位线到达时触发,之后每收到一个迟到数据更新一次"。

反压机制:流量控制的系统工程

当数据生产速率超过消费速率时,系统需要某种机制防止资源耗尽。这被称为反压(Backpressure)流量控制(Flow Control)

Storm的早期版本缺乏内置反压机制,当下游处理不过来时,数据会在上游队列中堆积,最终导致OOM。Spark Streaming通过动态调整批次大小来应对,但本质上是"事后补救"。

Flink在1.5版本引入了基于信用的流量控制(Credit-based Flow Control),这是一个精巧的设计:

sequenceDiagram
    participant U as 上游算子
    participant N as 网络
    participant D as 下游算子
    
    D->>U: 发送信用 Credit=3<br/>(有3个可用缓冲区)
    
    Note over U: 收到信用,可以发送数据
    
    U->>N: 发送数据包1
    U->>N: 发送数据包2
    U->>N: 发送数据包3
    
    Note over U: 信用耗尽,停止发送
    
    N->>D: 数据包1到达
    N->>D: 数据包2到达
    N->>D: 数据包3到达
    
    D->>D: 处理数据,释放缓冲区
    
    D->>U: 发送新信用 Credit=3
    
    Note over U: 可以继续发送
  1. 下游算子向上游发送"信用"(Credit),表示自己有多少缓冲区可用
  2. 上游只在收到足够信用后才发送数据
  3. 下游处理数据后释放缓冲区,信用恢复

这种设计将反压的传播延迟降低到网络往返级别,而不是等待队列填满。更关键的是,它可以精确控制每个连接的数据量,避免全局锁竞争。

流批一体的愿景与实践

2015年,Google发表了《The Dataflow Model》论文,提出了一个激进的观点:批处理和流处理可以统一在同一个编程模型下,批处理只是流处理的一个特例——有界的流

这个愿景的吸引力是显而易见的:企业只需要维护一套代码、一套基础设施,就可以处理历史数据和实时数据。Apache Beam项目就是这一愿景的开源实现,它定义了一套统一的编程模型,可以在Flink、Spark、Google Cloud Dataflow等引擎上运行。

Flink的流批一体实践

Flink从一开始就设计为流批一体的系统。在Flink中,数据集(DataSet)API和流(DataStream)API共享相同的运行时引擎。执行计划优化器可以根据数据源是否为有界流,自动选择不同的执行模式:

  • 对于无界流:采用流模式,持续执行
  • 对于有界流:采用批模式,可以启用优化(如排序合并Join而非流式Join)

阿里巴巴的Blink团队进一步增强了Flink的SQL能力,使其可以用同一套SQL语句处理流数据和批数据。这在他们2019年的技术博客中被称为"让SQL成为流批处理的统一语言"。

现实中的权衡

流批一体听起来美好,但实践中面临挑战:

首先是语义差异。流处理需要考虑迟到数据、水位线、增量更新,而批处理假设数据已经完整。同一份SQL在流模式和批模式下可能产生不同的结果。

其次是性能权衡。流式处理为低延迟优化,批处理为高吞吐优化。一个引擎很难在两个维度上都做到极致。

最务实的做法是:将流处理用于实时数据新鲜度要求高的场景,将批处理用于历史数据分析,通过数据湖架构(如Delta Lake、Iceberg)作为桥梁。

新一代流处理系统:云原生与流式数据库

随着云原生技术的发展和流式SQL的普及,新一代流处理系统正在涌现。

RisingWave:流式数据库的新范式

RisingWave是一个2021年启动的开源项目,它的定位是流式数据库(Streaming Database),而非传统的流处理引擎。

核心区别在于抽象层级。传统流处理引擎要求开发者思考流、算子、状态等概念;RisingWave将流处理结果呈现为物化视图(Materialized View)——一个持续更新的表。用户可以用标准SQL查询物化视图,就像查询普通表一样。

RisingWave的架构设计针对云原生环境进行了优化:

  1. 存算分离:计算节点无状态,状态存储在共享存储(如S3)中
  2. 弹性伸缩:可以根据负载动态增减计算节点,无需迁移状态
  3. 简化运维:无需手动配置状态后端、Checkpoint路径等

这种设计的代价是延迟略高于Flink(通常在毫秒到秒级),但换来了显著降低的运维复杂度。

云托管服务的兴起

除了开源项目,云厂商也在推出托管的流处理服务:

  • AWS Kinesis Data Analytics
  • Google Cloud Dataflow
  • Azure Stream Analytics

这些服务的共同特点是:屏蔽底层基础设施复杂性,用户只需上传代码或SQL,服务自动处理资源分配、故障恢复、弹性伸缩。

选择的艺术:没有银弹

流处理系统的选择本质上是在多个维度上进行权衡:

graph LR
    subgraph "流处理系统选型决策树"
        START[流处理需求] --> Q1{延迟要求}
        
        Q1 -->|毫秒级| Q2{是否深度绑定Kafka}
        Q1 -->|秒级可接受| Q3{是否需要Spark生态}
        
        Q2 -->|是| KS[Kafka Streams<br/>轻量级部署]
        Q2 -->|否| Q4{状态大小}
        
        Q4 -->|TB级| FL[Flink + RocksDB<br/>大状态支持]
        Q4 -->|GB级以下| FL_L[Flink + Heap<br/>低延迟]
        
        Q3 -->|是| SS[Spark Streaming<br/>生态复用]
        Q3 -->|否| Q5{SQL优先级}
        
        Q5 -->|高| RW[RisingWave<br/>SQL友好]
        Q5 -->|中| FL_ALL[Flink]
    end
    
    style START fill:#e1f5fe
    style KS fill:#c8e6c9
    style FL fill:#c8e6c9
    style FL_L fill:#c8e6c9
    style SS fill:#c8e6c9
    style RW fill:#c8e6c9
    style FL_ALL fill:#c8e6c9
维度 Storm Spark Streaming Flink Kafka Streams
延迟 毫秒级 秒级 毫秒级 毫秒级
吞吐量 中等
Exactly-once
事件时间处理 部分
状态管理 手动 自动 自动 自动
运维复杂度
生态系统 弱(绑定Kafka)

选择建议

  • 超低延迟场景(毫秒级风控、实时推荐):Flink
  • 高吞吐 + 兼容Spark生态:Spark Streaming(或考虑Spark Structured Streaming的连续处理模式)
  • 轻量级部署 + 深度绑定Kafka:Kafka Streams
  • SQL友好 + 简化运维:RisingWave或云托管服务
  • 已有Storm代码迁移:Heron

没有最优解,只有最适合特定场景的权衡。这正是流处理系统二十年演进的启示:技术进步不是线性的替代,而是问题空间的持续拓展和解决方案的持续细化

从Storm的开创,到Spark Streaming的工程务实,再到Flink的理论完备,每一步都在解决前一代系统的核心痛点,同时也引入了新的复杂度。新一代系统又在这些复杂度上做减法,试图让流处理能力触达更多开发者。这个循环仍在继续。


参考文献

  1. Akidau, T., et al. “MillWheel: Fault-Tolerant Stream Processing at Internet Scale.” VLDB 2013.
  2. Akidau, T., et al. “The Dataflow Model: A Practical Approach to Balancing Correctness, Latency, and Cost in Massive-Scale, Unbounded, Out-of-Order Data Processing.” VLDB 2015.
  3. Carbone, P., et al. “Apache Flink: Stream and Batch Processing in a Single Engine.” Data Engineering Bulletin 2015.
  4. Kulkarni, S., et al. “Twitter Heron: Stream Processing at Scale.” SIGMOD 2015.
  5. Chandy, K.M., Lamport, L. “Distributed Snapshots: Determining Global States of Distributed Systems.” ACM TOCS 1985.
  6. Kreps, J., et al. “Kafka: A Distributed Messaging System for Log Processing.” NetDB 2011.
  7. Noghabi, S.A., et al. “Samza: Stateful Scalable Stream Processing at LinkedIn.” VLDB 2017.
  8. Zaharia, M., et al. “Spark Streaming: Fault-tolerant Scalable Stream Processing.” HotCloud 2012.
  9. Apache Flink Documentation. https://nightlies.apache.org/flink/
  10. Yahoo Streaming Benchmarks. https://github.com/yahoo/streaming-benchmarks
  11. Confluent Blog. “Exactly-Once Semantics are Possible: Here’s How Kafka Does it.” 2017.
  12. Alibaba Tech Blog. “Alibaba Blink: Real-Time Computing for Big-Time Gains.” 2018.
  13. Google Cloud Blog. “The stream processing model behind Google Cloud Dataflow.” 2024.
  14. RisingWave Documentation. https://docs.risingwave.com/
  15. Apache Beam Documentation. https://beam.apache.org/
  16. Kreps, J. “Questioning the Lambda Architecture.” O’Reilly Radar 2014.
  17. Marz, N., Warren, J. “Big Data: Principles and best practices of scalable realtime data systems.” Manning 2015.
  18. Stonebraker, M., et al. “The 8 Requirements of Real-Time Stream Processing.” ACM SIGMOD Record 2005.
  19. Golab, L., Özsu, M.T. “Issues in Data Stream Management.” ACM SIGMOD Record 2003.
  20. Babcock, B., et al. “Models and Issues in Data Stream Systems.” PODS 2002.