Spark Streaming

来源:互联网 发布:真实快递单号软件 编辑:程序博客网 时间:2024/04/30 01:38

概要

许多大数据应用要处理实时数据(real time),然而现有开源组件大部分是low-level的,开发者需要关心数据一致性和错误恢复(fault recovery)。即使部分组件提供了错误恢复,也要求备份或者较长的恢复时间。Spark Streaming提出了新的模型:
D-Streams(discretized streams),提供high-level API,强一致性和错误恢复,D-Streams支持新的更高效的恢复机制,并行恢复(parallel recovery),同时streaming能够和交互查询融合。

简介

实时数据需要及时处理,也是在数据产生时价值最大。例如,社交网站想在分钟内确定交流话题的趋势,广告服务商想根据用户点击事件训练模型,服务者想通过挖掘日志秒级找到错误信息。

目前分布式流处理系统(Yahoo的S4和Twitter的Storm等),基于一次消费一条数据模型(a-record-at-a-time),节点收到一条数据,处理并返回结果,这个模型有几个问题(a-record-at-a-time模型的不足):

  • 容错
    a-record-at-a-time系统可以通过备份(replication)恢复,每个计算节点保留两份拷贝,或者上游缓存(upstream backup),缓存已发送数据并在发生问题时重发。这两种方式在大型集群中表现不好,备份需要2x的硬件,一旦两个备份节点都宕掉,彻底失败;上游备份花费较长时间来恢复,整个系统等待失败节点recove
  • 一致性
    基于上面所有系统,保证整体一致性有困难。例如,一个男女pv比率的统计,一个节点统计男性用户的pv,另一个节点统计女性用户,如果一个节点出现数据积压了,则结果有出入。
  • 和批处理不兼容
    现有的流处理系统是事件驱动的(event-driven),和批处理API差别巨大,所以用户需要写两个不同的程序分别处理。此外,同时合并流式数据和历史数据也不是很顺利的。

基于此,D-streams模型被提出,来解决这些问题。主要的思路是将流式计算处理成一系列小时间间隔的批处理。例如,以秒为间隔将接收的数据分割,然后程序分别处理每个时间间隔内的数据(即每次处理1s接收的数据),同时,也提供了跨时间间隔的window操作。D-streams两个显而易见的优势:

  1. 使用了小间隔的批处理,一致性容易保障。
  2. 容易和批处理程序结合,可以使用批处理相似的数据恢复,比现有流式系统消耗低。

同时有两大挑战:

  1. 降低job延迟,例如间隔为1s,处理1s数据的时间
  2. 快速的错误恢复(parallel recovery)

D-Streams

D-streams主要思路是将流式计算处理成一系列离散的批处理,每个interval收到的数据使用RDD存储,提供了类似RDD的两类操作:1、transformation和2、output operator。D-streams重用了RDD中所有operator,包括map、reduce、groupBy、join等,

  • Wordcount
    val conf = new  SparkConf().setMaster("local[2]").setAppName("NetworkWordCount")    val ssc = new StreamingContext(conf, Seconds(1))    val lines = ssc.socketTextStream("localhost", 9999)    val words = lines.flatMap(_.split(" "))    val pairs = words.map(word => (word, 1))    val wordCounts = pairs.reduceByKey(_ + _)    wordCounts.print()    ssc.start()    ssc.awaitTermination()

上面的代码interval设置为1s,每秒收到的数据为一个batch,进行Wordcount计算。D-Streams采用RDD存储数据,数据的处理自然也是RDD的transformation和action。

此外,spark streaming提供了三种跨interval的操作,这部分是streaming的重点

  • window

    最基础的跨interval操作,使用window函数,第一个参数(上图10s)为window大小,第二个参数为window滑动的间隔。上图代码的含义就是,每隔2s,处理当前这1s及前9s的数据。

  • 增量聚合(Incremental aggregation)

    从命名上可以看出,这个操作只适合聚合操作(aggregation),如sum,并不适合对单条数据的操作,而window可以操作具体的每条记录,这也是增量聚合和window的区别所在。增量聚合又有以下两种:

    1. 朴素计算(naive evaluation)

      使用reduceByKeyAndWindow函数,和window函数相比,多了第一个参数,reduceFunction,执行过程如增量聚合下图中的(a)所示,和window也极为相似,最大不同的是,朴素计算是并行的聚合计算,使用第一个参数reduceFunction对位于window之内的每个interval执行并行计算,计算后的结果再合并得到结果,因为每个interval并行了,效率相对于window有提升,但只适用于聚合计算。

    2. 增量计算(incremental evaluation)

      可以看出,朴素计算中随着时间的变化,interval一直在被重复计算,基于此,提出了增量计算,增量计算是对于朴素计算的优化,执行过程如增量聚合下图中的(b)所示。增量计算也使用reduceByKeyAndWindow函数,和朴素计算不同在于多了一个参数(如上图箭头所指),这个参数称作invReduceFunc


      上图是spark中对应源码和图片,源码第二行的tempValue对应图片中previous window,后面的newValues、oldValues分别对应图片中new RDDs和old RDDs,不像朴素计算计算每个interval,现在以一个window的计算结果为基础,随着窗口的滑动,添加入新interval的值,减去过期值,如下

      current window=new RDDs + previous window - old RDD

      上图公式中的 + 和 -是根据我们给出的demo中的reduceFunction和invReduceFunc得来的,增量计算减少了不必要的interval粒度的计算,效率较朴素计算有提高。

  • Time-skewed joins

因为D-Streams就是用RDD存储数据,批处理是RDD的主要用途之一,所以D-Streams和批处理很好结合。

错误恢复(fault Recovery)

典型的流式处理系统使用replication或者upstream backup实现错误恢复,replication需要创建两个或更多副本,鉴于此增加硬件开销,此外,如果备份节点都宕掉了,系统则不可恢复,因此,replication不是好的选择。对于upstream backup模式,每个节点缓存发送的数据,直到收到计算完成的ack,当一个节点挂掉,upstream 节点传播所有没有ack的数据到standby节点,此节点接管fail over节点的角色并重新计算,这个模式的缺点是recovery耗时长,因为要等standby节点catch up。

为了处理这个问题,D-Streams使用新策略:parallel recovery,系统间隔性的checkpoint RDD的数据,异步的备份到其他节点,当一个节点宕掉,系统检测出丢失的RDD,从最近的checkpoint恢复数据,利用RDD不同分区可以同时恢复,同时不影响其他正常分区计算,因此,parallel recovery恢复更快。

parallel recovery难以在典型的流式系统中实现,主要是因为a-record-at-a-time模型。相反,D-Streams依靠RDD,实现了恢复更快资源消耗少。最后,除了fail over,大型集群另一个重点是straggler(执行慢的节点),很幸运,D-Streams使用了和mapreduce相似的方式,通过推测执行,备份执行慢的任务很好的解决了这个问题。同样,在a-record-at-a-time系统中这也是难以解决的。

总结

D-Streams,一个强一致性、高效恢复、和批处理兼容的模型。主要思想是,将流式数据处理成一系列小间隔的批处理任务,同时尽可能降低job的延迟。由此带来了很多好处,包括简明的一致性语义,parallel recovery技术,具体的实现是spark streaming,已经成为spark全家桶中重要的一部分。

参考:spark streaming docDiscretized Streams: An Efficient and Fault-Tolerant Model forStream Processing on Large Clusters

2 0