SparkStreaming StructuredStreaming Flink Storm 对比

1. Spark Streaming

  1. Spark Streaming 是Spark Core 的扩展,可实现实时数据的快速扩展,高吞吐量,容错处理。数据可以从很多来源(如 Kafka、Flume、Kinesis 、HDFS、Twitter等)中提取,并且可以通过很多函数(能够和Spark Core、Spark SQL来进行混合编)来处理这些数据,处理完后的数据可以直接存入数据库或者 Dashboard 等。
  2. 是这条日志数据真正到达计算框架中被处理的时间点,简单的说,就是你的Spark程序是什么时候读到这条日志的
  3. Spark Streaming能怎么处理数据?
    1. 无状态的转换(前面处理的数据和后面处理的数据没啥关系)
    2. 有转换转换(前面处理的数据和后面处理的数据是有关系的,比如叠加关系)
  4. Spark Streaming 的内部实现原理是接收实时输入数据流并将数据分成批处理,然后由 Spark 引擎处理以批量生成最终结果流,也就是常说的 micro-batch 模式。
  • 优点:
    1. Spark Streaming 内部的实现和调度方式高度依赖 Spark 的 DAG 调度器和 RDD,这就决定了 Spark Streaming 的设计初衷必须是粗粒度方式的,也就无法做到真正的实时处理。
    2. Spark Streaming 的粗粒度执行方式使其确保“处理且仅处理一次”的特性,同时也可以更方便地实现容错恢复机制。
    3. 由于 Spark Streaming 的 DStream 本质是 RDD 在流式数据上的抽象,因此基于 RDD 的各种操作也有相应的基于 DStream 的版本,这样就大大降低了用户对于新框架的学习成本,在了解 Spark 的情况下用户将很容易使用 Spark Streaming。
  • 缺点:
    1. Spark Streaming 的粗粒度处理方式也造成了不可避免的数据延迟。在细粒度处理方式下,理想情况下每一条记录都会被实时处理,而在 Spark Streaming 中,数据需要汇总到一定的量后再一次性处理,这就增加了数据处理的延迟,这种延迟是由框架的设计引入的,并不是由网络或其他情况造成的。
    2. 使用的是 Processing Time 而不是 Event Time。

2. Structured Streaming

一种基于 Spark SQL 引擎的可扩展且容错的流处理引擎,它最关键的思想是将实时数据流视为一个不断增加的表,从而就可以像操作批静态数据一样来操作流数据。相较于spark streaming,Structured Streaming为事件驱动型, 就是数据真正发生的时间,比如用户浏览了一个页面可能会产生一条用户的该时间点的浏览日志。

Structured Streaming将实时流抽象成一张无边界的表,输入的每一条数据当成输入表的一个新行,同时将流式计算的结果映射为另外一张表,完全以结构化的方式去操作流式数据。
【图1】
会对输入的查询生成“结果表”,每个触发间隔(例如,每 1 秒)新行将附加到输入表,最终更新结果表,每当结果表更新时,能够将更改后的结果写入外部接收器去。

一共有三种Output模式:

  • Append模式:只有自上次触发后在Result Table表中附加的新行将被写入外部存储器。重点模式,一般使用它。

  • Complete模式: 将整个更新表写入到外部存储。每次batch触发计算,整张Result Table的结果都会被写出到外部存储介质。

  • Update模式:只有自上次触发后在Result Table表中更新的行将被写入外部存储器。注意,这与完全模式不同,因为此模式不输出未更改的行。

2
事件时间在此模型中非常自然地表示,来自设备的每个事件都是表中的一行,事件时间是该行中的一个列值。这允许基于窗口的聚合(例如每分钟的事件数)仅仅是时间列上的特殊类型的分组和聚合 - 每个时间窗口是一个组,并且每一行可以属于多个窗口/组。因此,可以在静态数据集(例如,来自收集的设备事件日志)以及数据流上一致地定义这种基于事件时间窗的聚合查询。
在这里插入图片描述

延迟数据处理Watermark

Structured Streaming基于Event time能自然地处理延迟到达的数据,保留或者丢弃。

由于Spark正在更新Result Table,因此当存在延迟数据时,它可以完全控制更新旧聚合,以及清除旧聚合以限制中间状态数据的大小。

使用Watermark,允许用户指定数据的延期阈值,并允许引擎相应地清除旧的状态。
在这里插入图片描述

容错性

  1. 流式数据处理系统的可靠性通常是通过系统可以处理每个记录的次数来定义的。系统可以在所有可能的操作情形下提供三种类型的保证(无论出现何种故障):
    • At most once:每个记录将被处理一次或不处理。
    • At least once: 每个记录将被处理一次或多次。 这比“最多一次”更强,因为它确保不会丢失任何数据。但可能有重复处理。
    • Exactly once:每个记录将被精确处理一次 - 不会丢失数据,并且不会多次处理数据。 这显然是三者中最强的保证。

如果假设正好在process的过程中,系统挂掉了,那么数据就会丢了,但因为 Structured Streaming 如果是complete模式,因为是全量数据,所以其实做好覆盖就行,也就说是幂等的。

如果是append 模式,则可能只能保证at-least once ,而对于其内部,也就是result table 是可以保证exactly-once 的。

  1. 容错机制
    在故障或故意关闭的情况下,用户可以恢复先前进度和状态,并继续在其停止的地方,简称断点续传。这是通过使用检查点checkpoint和预写日志write ahead logs来完成的。

    用户可以指定checkpoint的位置,Spark将保存所有进度信息(如每个触发器中处理的offset偏移范围)和正在运行的聚合到checkpoint中。任务重启后,使用这些信息继续执行。

StructuredStreaming+Kafka使用教程:https://blog.csdn.net/lovechendongxing/article/details/81748553

3. Flink

相较于spark streaming,Flink是事件驱动型,它从一个或多个事件流提取数据,并根据到来的事件触发计算、状态更新或其他外部动作。比较典型的就是以kafka为代表的消息队列几乎都是事件驱动型应用。

流处理的特点是无界、实时, 无需针对整个数据集执行操作,而是对通过系统传输的每个数据项执行操作,一般用于实时统计。

在flink的世界观中,一切都是由流组成的,离线数据是有界限的流,实时数据是一个没有界限的流,这就是所谓的有界流和无界流。

  • 无界数据流:无界数据流有一个开始但是没有结束,它们不会在生成时终止并提供数据,必须连续处理无界流,也就是说必须在获取后立即处理event。对于无界数据流我们无法等待所有数据都到达,因为输入是无界的,并且在任何时间点都不会完成。处理无界数据通常要求以特定顺序(例如事件发生的顺序)获取event,以便能够推断结果完整性。
  • 有界数据流:有界数据流有明确定义的开始和结束,可以在执行任何计算之前通过获取所有数据来处理有界流,处理有界流不需要有序获取,因为可以始终对有界数据集进行排序,有界流的处理也称为批处理。

Flink 分层 API

分层
分为三层,最底层级的抽象仅仅提供了有状态流,它将通过过程函数(Process Function)被嵌入到DataStream API中。底层过程函数(Process Function) 与 DataStream API 相集成,使其可以对某些特定的操作进行底层的抽象,它允许用户可以自由地处理来自一个或多个数据流的事件,并使用一致的容错的状态。

大多数应用并不需要上述的底层抽象,而是针对核心API(Core APIs) 进行编程,比如:

  1. DataStream API(有界或无界流数据)以及DataSet API(有界数据集)。T
  2. Table API 是以表为中心的声明式编程,其中表可能会动态变化(在表达流数据时)。Table API遵循(扩展的)关系模型:表有二维数据结构(schema)(类似于关系数据库中的表),同时API提供可比较的操作,例如select、project、join、group-by、aggregate等,同时也可以通过UDF进行扩展。
  3. Flink提供的最高层级的抽象是 SQL 。这一层抽象在语法与表达能力上与 Table API 类似,但是是以SQL查询表达式的形式表现程序。

使用示例


 //定义流处理环境
 
final StreamExecutionEnvironment env = StreamExecutionEnvironment
                .getExecutionEnvironment();
 
		// 非常关键,一定要设置启动检查点!!
		env.enableCheckpointing(5000);
		env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
//配置kafka信息
Properties props = new Properties();
		props.setProperty("bootstrap.servers",
				"hadoop01:9092,hadoop02:9092");
		props.setProperty("zookeeper.connect",
				"hadoop01:2181,hadoop02:2181");
		props.setProperty("group.id", "kafka_to_hdfs");
//读取数据
		FlinkKafkaConsumer010<String> consumer = new FlinkKafkaConsumer010<>(
				"test1", new SimpleStringSchema(), props);
//设置只读取最新数据
		consumer.setStartFromLatest();
//添加kafka为数据源
		DataStream<String> stream = env.addSource(consumer);
//定义输出sink
		BucketingSink<String> hdfs_sink = new BucketingSink<String>(
				"hdfs:///data/flink/fromKafka");
		hdfs_sink.setBatchSize(1024 * 1024 * 400);
		hdfs_sink.setBucketer(new DateTimeBucketer<String>("yyyy-MM-dd"));
		hdfs_sink.setBatchRolloverInterval(3600000);
		//存到hdfs
		stream.addSink(hdfs_sink);
		env.execute("Kafka-to-HDFS");

3.场景

对于Storm来说:

  1. 纯实时–实时金融系统,金融交易和分析
  2. 事务机制和可靠性机制
  3. 如果还需要针对高峰低峰时间段,动态调整实时计算程序的并行度,以最大限度利用集群资源(通常是在小型公司,集群资源紧张的情况),也可以考虑用Storm
  4. 不需要在中间执行SQL交互式查询、复杂的transformation算子等,那么用Storm是比较好的选择

对于Spark Streaming来说:

  1. 还包括了离线批处理、交互式查询等业务功能
  2. 涉及到高延迟批处理、交互式查询等功能

对于Flink来说:

  1. 对于复杂的计算需求,对稳定性要求不高的行业,可以用Flink替代Storm。

总结
在这里插入图片描述
如果对延迟要求不高的情况下,可以使用 Spark Streaming,它拥有丰富的高级 API,使用简单,并且 Spark 生态也比较成熟,吞吐量大,部署简单,社区活跃度较高,在新版本还引入了 Structured Streaming。

如果对延迟性要求非常高的话,可以使用流处理框架 Flink,采用原生的流处理系统,保证了低延迟性,在 API 和容错性方面做的也比较完善,使用和部署相对来说也是比较简单。

猜你喜欢

转载自blog.csdn.net/weixin_42526352/article/details/105317112