第12课:Spark Streaming源码解读之Executor容错安全性

 作者:大数据技术研发人员:谢彪

    本节从安全角度来讲解sparkstreaming,因为sparkstreaming会不断的接收数据、不断的产生job、不断的提交job。所以有一个至关重要的问题就是数据安全性。

    由于sparkstreaming是基于sparkcore的之上的应用程序,如果借助于sparkcore之上的容错机制,保证数据安全性,sparkcoreRDD容错机制,保证了sparkstreaming的数据安全,但前提是sparkstreaming本身接收的数据是完整且安全的。

      如果我们可以确保数据安全可靠的话(sparkstreaming生产job的时候里面是基于RDD),即使运行的时候出现错误或者故障,也可以基于RDD的容错的能力自动进行恢复。所以要确保数据的安全性。

   对于executor的安全容错主要是数据的安全容错。Executor计算时候的安全容错是借助Spark coreRDD的,所以天然是安全的。

数据安全性的一种方式是存储一份副本,另一种方式是不做副本,但是数据源支持存放(也就是可以反复的读取数据源的数据),如果之前读取的数据出现问题,可以重新读取数据。

做副本的方式可以借助blockmanager做备份。Blockmanager存储数据的时候有很多storagelevelReceiver接收数据后,存储的时候指定storagelevelMEMORY_AND_DISK_SER_2的方式。Blockmanager早存储的时候会先考虑memory,只有memory不够的时候才会考虑disk,一般memory都是够的。所以至少两个executor上都会有数据,假设一个executor挂掉,就会马上切换到另一个executor

一、ReceiverSupervisorImpl在存储数据的时候会有两种方式,一种是WAL的方式,究竟是不是WAL得方式是通过配置修改的。默认是false。如果用WAL的方式必须有checkpoint的目录,因为WAL的数据是放在checkpoint的目录之下的。

def enableReceiverLog(conf:SparkConf): Boolean = {
  
conf.getBoolean(RECEIVER_WAL_ENABLE_CONF_KEY,false)
}

Storagelevel是在构建inputDstream的时候传入的,默认就是MEMORY_AND_DISK_SER_2

*@param storageLevel Storage level to use for storing the received objects
 *                     (default:StorageLevel.MEMORY_AND_DISK_SER_2)
 */

defsocketTextStream(
    hostname: String,
    port: Int,
    storageLevel: StorageLevel = StorageLevel.MEMORY_AND_DISK_SER_2
  
):ReceiverInputDStream[String] = withNamedScope("socket text stream") {
  socketStream[String](hostname, port, SocketReceiver.bytesToLines, storageLevel)
}

 

二、现在来看ReceiverSupervisorImpl在存储数据的另一种方式(副本方式)。根据指定的storagelevel把接收的blocks交给blockmanager。也就是通过blockmanager来存储。

/**
 * Implementation of a
[[org.apache.spark.streaming.receiver.ReceivedBlockHandler]]which
 * stores the received blocks into ablock manager with the specified storage level.
 */

private[streaming] class BlockManagerBasedBlockHandler(
    blockManager: BlockManager, storageLevel: StorageLevel)

 

       Blockmanager存储的时候会分为多种不同的数据类型,ArrayBufferBlockIteratorBlockByteBufferBlock

Receiver在接收到数据后除了在自己这个executor上面存储,还会在另外一个executor上存储。如果一个executor出现问题会瞬间切换到另一个executor

WAL的方式原理:在具体的目录下会做一份日志,假设后续处理的过程中出了问题,可以基于日志恢复,日志是写在checkpoint下。在生产环境下checkpoint是在HDFS上,这样日志就会有三份副本。

    不管是WAL还是直接交给blockmanager都是采用副本的方式。还有一种是数据源支持数据存放,典型的就是kafkaKafka已经成为了数据存储系统,它天然具有容错和数据副本。

       Kafkareceiverdirect的方式。Receiver的方式其实是交给zookeper来管理matadata的(偏移量offset),如果数据处理失败后,kafka会基于offset重新读取数据。为什么可以重新读取?如果程序崩溃或者数据没处理完是不会给zookeperackZookeper就认为这个数据没有被消费。实际生产环境下越来越多的使用directAPI的方式,直接去操作kafka并且是自己管理offset。这就可以保证有且只有一次的容错处理。DirectKafkaInputDstream,它会去看最新的offset,并把这个内容放入batch中。

获取最新的offset,通过最新的offset减去上一个offset就可以确定读哪些数据,也就是一个batch中的数据。

@tailrec
protected final def latestLeaderOffsets(retries:Int): Map[TopicAndPartition, LeaderOffset] = {
  val o = kc.getLatestLeaderOffsets(currentOffsets.keySet)
  // Either.fold would confuse @tailrec, do it manually
  if (o.isLeft){
    val err= o.left.get.toString
    if (retries<= 0) {
      thrownew SparkException(err)
    } else {
      log.error(err)
      Thread.sleep(kc.config.refreshLeaderBackoffMs)
      latestLeaderOffsets(retries - 1)
    }
  } else {
    o.right.get
  }
}

容错的弊端就是消耗性能,占用时间。也不是所有情况都不能容忍数据丢失。有些情况下可以不进行容错来提高性能

假如一次处理1000block,但是有1block出错,就需要把1000block进行重新读取或者恢复,这也有性能问题。


 

作者:大数据技术研发人员:谢彪

  • 资料来源于:DT_大数据梦工厂(Spark发行版本定制) 

  • DT大数据梦工厂微信公众号:DT_Spark 

  • 新浪微博:http://www.weibo.com/ilovepains

  • 王家林老师每晚20:00免费大数据实战

YY直播:68917580





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值