Flink VS Spark Streaming

Flink VS Spark Streaming

数据处理模式

Apache Flink是一个用于分布式流和批处理数据处理的开源平台。Flink的核心是流数据引擎,为数据流上的分布式计算提供数据分发,通信和容错,可对有限数据流和无限数据流进行有状态计算。Flink在流引擎之上构建批处理,覆盖本机迭代支持,托管内存和程序优化。

img

Spark Streaming是Spark的一大应用方向,它基于Spark高效的批处理能力,对流数据划分为多个小批数据,再分别对这些数据进行处理,即微批处理模式,运行的时候需要指定批处理的时间,每次运行job时处理一个批次的数据。

Spark Streaming

  • Flink的计算模型抽象是有状态的流,即源源不断没有边界的数据,并且数据的状态可以改变,对于批处理则认为是有边界的流进行处理
  • Spark的计算模型抽象是批,所有数据的表示本质上都是RDD抽象,对于流处理的支持,则是基于时间将流划分为多个批次,依次进行处理

两种模式的对比

item Micro-batching Distributed snapshots
典型代表 Apache Spark Streaming Apache Flink
语义保证 Exactly once Exactly once
延迟
吞吐
计算模型 微批
容错开销
流控 较差
业务灵活性 (业务和容错分离) 紧耦合 分离
原理 连续的数据流不要切分到 record 级别,而是收敛切分为一批一批微批的、原子的数据进行类似 Batch 的计算。每个 batch 的数据可能会成功或者失败处 理,我们就对当前失败的 这一小批数据进行处理即 可 确定当前流式计算的状态 (包括正在处理的数据,以及 Operator 状态),生成该状态 的一致快照,并存储在持久存储中

运行时结构

Spark Streaming 运行时的角色(standalone 模式)主要有:

  • Master:主要负责整体集群资源的管理和应用程序调度;
  • Worker:负责单个节点的资源管理,driver 和 executor 的启动等;
  • Driver:用户入口程序执行的地方,即 SparkContext 执行的地方,主要是 DAG 生成、stage 划分、task 生成及调度;
  • Executor:负责执行 task,反馈执行状态和执行结果。

Flink 运行时的角色(standalone 模式)主要有:

  • JobManager: 协调分布式执行,他们调度任务、协调 checkpoints、协调故障恢复等。至少有一JobManager,高可用情况下可以启动多个 JobManager,其中一个选举为 leader,其余为 standby;
  • TaskManager: 负责执行具体的 tasks、缓存、交换数据流,至少有一个 TaskManager;
  • Client:程序的提交者,用于准备,生成并优化DataFlow,然后发送给JobManager
  • Slot: 每个 task slot 代表 TaskManager 的一个固定部分资源,Slot 的个数代表着 taskmanager 可并行执行的 task 数。

部署环境支持

部署环境 Spark Flink
Local(Single JVM) ✔️ ✔️
Standalone Cluster ✔️ ✔️
Yarn ✔️ ✔️
Mesos ✔️ ✔️
Kubernetes ✔️ ✔️

编程模型

Flink编程模型

image-20190428155747345

  • 最底层的抽象提供了对有状态流的支持,用户可以自由的处理和管理事件状态,并基于此开发新的算子
  • 实际上,大多数应用并不需要上述的底层抽象,而是针对 核心API(Core APIs) 进行编程,比如DataStream API(有界或无界流数据)以及DataSet API(有界数据集)。这些API为数据处理提供了通用的构建模块,比如由用户定义的多种形式的转换(transformations),连接(joins),聚合(aggregations),窗口操作(windows),状态(state)等等。
  • Table API是以表为中心的声明式DSL,Table API遵循(扩展的)关系模型:表有二维数据结构(schema)(类似于关系数据库中的表),同时API提供可比较的操作,例如select、project、join、group-by、aggregate等
  • Flink提供的最高层级的抽象是 SQL 。这一层抽象在语法与表达能力上与Table API类似,但是是以SQL查询表达式的形式表现程序。SQL抽象与Table API交互密切,同时SQL查询可以直接在Table API定义的表上执行。

Spark Streaming编程模型

Spark Streaming编程模型是DStream(Discretized Streams),离散化数据流,其本质是对一批RDD的抽象。然后对每一批的RDD进行处理,使用spark core API。

image-20190428105225200

Flink的编程模型更适用于流式计算场景,并且未来将会向流处理和基于流的批处理进行统一。而Spark Streaming的编程模型依赖于底层Spark自身的处理特性,针对RDD进行批处理。

API

API Spark Flink
底层API RDD Process Function
核心API DataFrame/DataSet/Structured Streaming DataStream/DataSet
SQL Spark SQL Table API & SQL
机器学习 MLlib FlinkML
图计算 GraphX Gelly
其他 CEP

从 API 上来看,Spark 和 Flink 提供的功能领域大致相当。当然具体看各个方向支持的程度会有差异。总体来看 Spark 的 API 经过几轮迭代,在易用性,特别是机器学习的集成方面,更强一些。Flink 在流计算方面更成熟一些。

支持语言 Spark Flink
Java ✔️ ✔️
Scala ✔️ ✔️
Python ✔️ ✔️
R ✔️ 第三方
SQL ✔️ ✔️

API使用,以对SocketStream进行WordCount代码为例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// Spark wordcount
object StreamingWordCount {

def main(args: Array[String]): Unit = {
val conf = new SparkConf().setAppName("NetworkStream").setMaster("local[*]")
val ssc = new StreamingContext(conf, Seconds(10))

val DStream = ssc.socketTextStream("localhost", 9999)
val words = DStream.flatMap(_.split("\\s+"))
val pairs = words.map((_, 1))
pairs.reduceByKey(_ + _).print()

ssc.start()
ssc.awaitTermination()
}
}

// Flink wordcount
object StreamingWordCount {

def main(args: Array[String]) {
// set up the streaming execution environment
val env = StreamExecutionEnvironment.getExecutionEnvironment

val source = env.socketTextStream("localhost", 10000)
val words = source.flatMap(_.split("\\s+"))
val pairs = words.map((_, 1))
pairs.keyBy(0).timeWindow(Time.seconds(10)).sum(1).print()

env.execute("Flink Streaming SocketText WordCount")
}

可以看到二者在API上也很接近,最大的区别是spark streaming在一开始便指定了切分流数据的方式val ssc = new StreamingContext(conf, Seconds(10)) 即10秒切分一次,然后对这一批进行处理。

而Flink是后面自己通过timeWindow算子timeWindow(Time.seconds(10))来指定每10秒作为一个数据窗口进行处理。

从这个简单的例子上可以看出Spark Streaming的底层为micro batch处理方式,Flink为流处理方式。

不过它们大多数API,诸如map,flatMap,filter之类的算子基本用法都一样,这样也方便开发者从一个框架切换到另一个框架来开发应用。

Streaming处理特性

对Time的支持

Flink支持三种time

image-20190428155810631

EventTime

  • 事件生成时的时间,在进入Flink之前就已经存在,可以从event的字段中抽取
  • 必须指定watermarks的生成方式
  • 优势:确定性,乱序、延时、或者数据重放等情况,都能给出正确的结果
  • 弱点:处理无序事件时性能和延迟受到影响

IngestTime

  • 事件进入flink的时间,即在source里获取的当前系统的时间,后续操作统一使用该时间
  • 不需要指定watermarks的生成方式(自动生成)
  • 弱点:不能处理无序事件和延迟数据

ProcessingTime

  • 执行操作的机器的当前系统时间(每个算子都不一样)
  • 不需要流和机器之间的协调
  • 优势:最佳的性能和最低的延迟
  • 弱点:不确定性 ,容易受到各种因素影像(event产生的速度、到达flink的速度、在算子之间传输速度等),压根就不管顺序和延迟

Flink支持这三种时间机制,并且有watermark机制来处理时间乱序,滞后的数据

Spark Streaming仅支持ProcessingTime,不过在Spark的Structured streaming中支持ProcessingTime和EventTime,同时支持 watermark 机制处理滞后数据。

对Window的支持

Window是一种切割无限数据集为有限块并进行相应计算的处理手段。

因为Spark的微批处理机制,对window的支持十分有限,仅支持基于ProcessingTime的Sliding Window(滑动窗口)

Spark Streaming

Flink 支持的window分为两大类:基于事件数count的window和基于时间(可以是上面提到的那三种时间)的window

Count-based window:根据元素个数对数据流进行分组切片

  • Tumbling CountWindow:翻滚窗口
  • Sliding CountWindow :滑动窗口

Time-based window :根据时间对数据流进行分组切片

  • Tumbling Window:翻滚窗口
  • Sliding Window:滑动窗口
  • Session Window:类似于Web编程里的session,以不活动间隙作为分隔

除此之外还有一种特殊的Global Window,即全局Window,没有进行划分,各个Window详细介绍查看https://ci.apache.org/projects/flink/flink-docs-release-1.8/dev/stream/operators/windows.html#windows

在这方面基于纯粹流处理引擎的Flink比Spark Streaming功能更加强大

生态集成

Flink支持的Connectors:

  • Apache Kafka (source/sink)
  • Apache Cassandra (sink)
  • Amazon Kinesis Streams (source/sink)
  • Elasticsearch (sink)
  • Hadoop FileSystem (sink)
  • RabbitMQ (source/sink)
  • Apache NiFi (source/sink)
  • Twitter Streaming API (source)

Spark集成的生态:

Spark - Apache Spark

Spark与Flink都能对接大部分常用的系统,如果没有支持还可以自定义实现一个connector。

除此之外还有一个开源项目Apache Bahir,它提供了spark与flink向外扩展的多个连接,并且在不断完善中。

image-20190428144723382

总结

Spark的应用更为广泛,spark streaming只是spark其中的一大应用方向,它在生态总体上更完善一些,尤其是在机器学习的集成和易用性上面。

不过Flink在流式计算上有明显的优势,这主要是它们两者底层不同的执行模型带来的差别。Flink将真正意义上的纯流式计算带入了大数据时代。

目前spark针对流式计算处理的发展也在借鉴flink的一些设计思路,例如spark 2.0 引入的Structured Streaming,不过micro batch的执行方式依然存在一些局限性,特别在数据量达到一定规模时会有性能的问题。

二者都有各自擅长的应用方向,需要根据场景和应用方向来合理选择工具。