Spark Streaming详解


内容

  • sparkStreaming简介
  • spark Streaming和Storm区别
  • Spark Streaming算子
  • Spark checkpointing
  • Spark和kafka整合

Spark Streaming

  • SparkStreaming是一种流式处理框架,是SparkAPI的扩展,支持可扩展、高吞吐、容错的准实时数据处理,实时数据的来源可以事:
    • Kafka、Flume、Twitter,zeroMQ或者TCP sockets;
  • 并且可以使用高级功能的复杂算子来处理流数据,例如:map,reduce,jion,window;最终处理后的数据可以来存放在文件系统,数据库,方便实时展现;
1228818-20180510200107994-1902710699

SparkStreaming与Storm的区别

  • Storm是纯实时的流式处理框架,SparkStreaming是准实时的处理框架(微批处理);因为微批处理,SparkStreaming的吞吐量比Storm要高;
  • Storm的事务机制要比SparkStreaming的要完善;
  • Storm支持的动态资源调度(Spark1.2及以后也支持)
  • SparkStreaming擅长复杂的业务处理,Storm不擅长复杂的业务处理,擅长简单的汇总计算

SparkStreaming初始


SparkStreaming初始理解

Spark的各个子框架,都基于核心Spark的,SparkStreaming在内部的机制如下:SparkStreaming接收到实时input数据流,并将数据分批成batch,然后由Spark Engine进行处理最后生成batch的输出结果流

streaming-flow

Spark Streaming将产生高度分离的数据流叫DStream(discretized Stream);DStream既可以从输入数据源创建得来,(如Kafka、Flume或者Kinesis)也可以从其他DStream经过一些算子操作得来;

在内部,一个DStream就包含一系列的RDDs
(对python来说,有部分API尚不支持,或者和Scala、Java不同

图片1
  • receiver task是一直在执行的,一直在接受数据,将一段时间内接收到的数据保存到batch中(默认为5秒)那么会将接受来的数据每隔5秒封装到一个batch中,batch没有分布式计算的特性,这一个batch的数据又被封装到一个RDD中最终封装到一个DStream中
  • 例如:
    • 假设批处理间隔(batchInterval)为5秒,每隔5秒通过SparkStreaming将得到的一个DStream,在第6秒的时候开始计算这个DStream;假设执行任务的时间事3秒,那么第6-9秒一边接受数据,一边计算任务,一边在计算任务,9~10秒只是在接收数据。然后在第11秒的时候重复上面的操作
  • 如果job的执行的时间大于批处理间隔,接收到的数据会越积越多,最好可能导致OOM;

DStream 它表示的事连续数据流,可以是源数据接收的输入流,也可以事通过转换输入流生成的已处理的数据流;在内部,DStream由一系列的RDD组成;DStream中的每个RDD都包含来自特定间隔的数据


streaming-dstream

任何作用于DStream的算子,其实都会被转化为对其内部RDD的操作。例如,我们将 lines 这个DStream转成words DStream对象,其实作用于lines上的flatMap算子,会施加于lines中的每个RDD上,并生成新的对应的RDD,而这些新生成的RDD对象就组成了words这个DStream对象。其过程如下图所示

streaming-dstream-ops

Spark Streaming主要的两种内建的流式数据源:

  • 基础数据源:在StreamingContext API中可以直接使用源:如文件系统,套接字连接或者Akka actor
  • 高级数据源:需要依赖额外工具类的源,如:Kafka、Flume;

SparkStreaming算子


  • foreachRDD
    • output operation算子,必须对抽去出来的RDD执行action类算子,代码才能执行
  • transfor
    • transformation类算子
    • 可以通过transform算子,对Dstream做RDD到RDD的任意操作
    • updateStateByKey
      • 为SparkStreaming中的每一个key维护一份state状态,state类型可以事任意类型,可以是一个自定义的对象,更新函数也是自定义的
      • 通过更新函数对该key的状态不断更新,对每个新的batch而言,SparkStreaming会在使用updateStateByKey的时候为已经存在的key进行state的状态更新;
    • 使用updateStateByKey要开启checkpoint机制和功能
    • 如果批处理间隔设置的时间小于10,那么10秒写入磁盘一份
    • 如果批处理间隔设置的大于10秒,就会在批处理间隔时间写入磁盘一份

窗口操作(Window Operations)

Spark Streaming提供了窗口操作,你可以在滑动的窗口对数据使用transformations算子进行操作

streaming-dstream-window

每次窗口滑动时,DStream中落入窗口的RDD就会被合并计算成新的windowed DStream

  • 参数:
    • window length:窗口覆盖的时间长度
    • sliding interval:窗口启动的时间间隔
  • 注意 : 这两个参数必须事batchInterval的整数倍;

窗口优化

图片2

优化后的window操作要保存状态所以要设置checkpoint路径,没有优化的window操作可以不设置chekpoint路径

//Reduce last 30 seconds of data, every 10 seconds

val windowedWordCounts = pairs.reduceByKeyAndWindow((a:Int,b:Int) => (a + b), Seconds(30), Seconds(10))

Driver HA(Standalone或者Mesos)

因为SparkStream是7*24小时运行的,Driver只是一个简单的进程,有可能挂掉,所以实现Driver的HA就又必要(如果使用Client模式就无法实现DriverHA)Yarn平台cluster模式提交任务,AM(AplicationMaster)相当于Driver,如果挂掉会自动启动AM。这里所说的DriverHA针对的是Spark standalone和Mesos资源调度的情况下。实现Driver的高可用有两个步骤:

  • 提交任务层面,在提交任务的时候加上选项 --supervise,当Driver挂掉的时候会自动重启Driver;
  • 代码层面,使用JavaStreamingContex。getOrCreate(checkpoint)路径,JavaStreamingContextFactory
    • Driver中元数据包括:
      1. 创建应用程序的配置信息;
      2. DStream的操作逻辑;
      3. job中没有完成的批次数据,也就是job的执行进度

SparkStreaming2.2以前+Kafka


receiver模式

在SparkStreaming程序运行后,Executor中会又receiver task接收kafka推送过来的数据,数据会被持久化,默认级别为MEMORY_AND_DISK_SER_2,这个级别可以修改;receiver task对接收到的数据进行存储和备份,这个过程会又节点之间的数据传输,备份完成后zookeeper中更新偏移量,然后向Driver中的receiver tracket汇报数据的位置,最后Driver根据数据本地化将task分发到不同节点上执行;

kafka receiver
  • receiver模式采用了Receiver接收器模式,需要一个线程一直接受数据,将数据接收到Executor中,默认存储级别是MEMORY_AND_DISK_SER_2
  • receiver模式自动使用zookeeper管理消费者offset
  • receiver模式底层读取kafka采用High Level Consumer API实现,这种模式不关心offset,只要数据;
  • receiver模式当Driver挂掉时有数据丢失问题,可以开启WAL机制,避免丢失数据,但是开启后加大数据延迟,并存在数据重复消费等风险;
  • receiver模式并行度由spark.stream.blockInterbal=200ms,可以减少这个参数增大并行度,最小不能低于50ms;
  • Receiver模式不被使用
    • 被动将数据接受到Executor,当有任务堆积实,数据存在问题
    • 这种模式不能手动维护消费者offset

Direct模式

kafka receiver

无接收器(receiver-less)的直接(driect)方式,以确保更强的端对端传输;该方法不需要接收器来接收数据,而是定期向kafka查询每个topic和partition中的最新偏移量,并且相应定义了每个批次要处理的偏移量范围;

  • direct模式没有receiver,每批次处理数据直接获取当前批次数据处理;
  • direct模式没有使用zookeeper管理消费者offset,使用的是Spark自己管理,默认存在内存中,也可以设置checkpoint,也会保存到checkpoint中一份;
  • 简化并行性:无需创建多个Kafka流并将它们合并,使用directStream,Spark Streaming将创建(partition)与要使用的Kafka分区(topic)一样多的RDD分区,这些分区一一对应;
  • direct模式底层读取kafka使用Simple Consumer API,可以手动维护消费者offset
  • 可以使用设置chechpoint的方式管理消费着offset,使用StreamingContext.getOrCreate(ckDir,CreateStreamingContext)恢复
    • 当代码逻辑改变时,无法从checkpoint来恢复offset
      • 将偏移量输出到外部系统,如redis,hbase
    • 当从checkpoint中恢复数据时,有可能造成重复的消费,需要我们写代码来保证数据的输出幂等;
      • 保证输出的幂等性或使用事务

Kafka0.11

kafka0.8.2消费者offset存储在zookeeper中,对于zookeeper而言每次操作代价很昂贵的,而且zookeeper集群实不能扩展写能力,kafka0.11版本默认使用新等消费者api,消费者offset会更新到一个kafka自带等topic[__consumer_offsets]中

SparkStream2.3 + Kafka0.11

  • 丢掉receiver模式
  • 采用了新消费者api实现:类似于0.8中等Diect Stream方式;(API未来可能会发生更改)

LocationStrategies(路由策略):

  • 新等kafka api将消息预存到缓冲区中,因此出于性能考虑,Spark将消费者产生等消息存在在excutors上
  • 大多数情况下,SparkStreaming读取数据使用LocationStrategies.PreferConsistent,可以在可用的Executor平均分配分区;
  • 如果你Executor和Kafka代理在同一台主机上,请使用PreferBrokers,它将首选在Kafka leader上为数据计划分区,如果分区间等复合存在明显差异等话请使用PreferFixed,可以通过一个map(explicit mapping 显式映射)将topic分区指定到对应哪些主机(hosts);
  • 默认等消费者缓存大小为64Kb,默认缓存在Executor中:
    • spark.streaming.kafka.consumer.cache.maxCapacity :增大缓存
    • spark.streaming.kafka.consumer.cache.enabled : 设置成false关闭缓存机制

消费者策略(ConsumerStrategies.Subscribe)

即使从checkpoint重新启动,spark也可以获取正确配置等消费者

  • ConsumerStrategies.Subscribe:允许你订阅topics的固定collection,
  • SubscribePattern运行你使用正则表达式来指定特定的topics;
  • 与0.8不同在运行期间使用Subscribe或SubscribePattern应该响应(respond)添加的分区
  • Assign:允许指定固定等分区集合;

偏移量(Offset)

  • 如果设置了checkpoint,offset就会存储在checkpoint中:

    • 当代码逻辑改变实,无法从checkpoint中恢复offset;
    • 当从checkpoint中恢复数据时,有可能造成重复等消费,需要我们写代码来保证输出幂等
  • 依靠kafka来存储消费者offset,kafka中有一个特殊等topic来存储消费者offset,新的消费者api中,会定期提交offset,自动提交offset等频率由参数auto.commit.interval.ms决定,默认5s;为了保证消费者数据的精准性,我们可以关闭自动提交,改成异步等手动提交消费者offset;

    • offset存储在kafka中由参数offsets.retention.minutes=1440控制是否过期参数(60247=1440,默认7天删除),如果停机没有消费达到时长,存储在kafka中等消费者组会被清空连同offset;
    • 无法保证有且仅有一次语义,因为偏移量等提交时异步的,所以结果等输出依然要自己实现幂等性;
  • 自己存储offset:处理逻辑时,保存数据处理等事务;如果在失败等情况下,就不保存offset,处理成功则保存offset,这样就可以做到数据等一致性;

你可能感兴趣的:(Spark Streaming详解)