10th lesson: Spark Streaming Source interpretation data constantly receiving full life cycle thorough research and thinking

Source: Internet
Author: User

In the previous lesson, we explained the process of receiver initiation. Receiver is initiated by the Start method of the Receiversupervisor:

/** Start the Supervisor */def start () {OnStart () Startreceiver ()}

The Receiversupervisor OnStart () method is called first,

Override protected Def onStart () {registeredblockgenerators.foreach {_.start ()}}

The registeredblockgenerators is assigned when the Receiversupervisor is instantiated:

Private Val defaultblockgenerator = Createblockgenerator (defaultblockgeneratorlistener) override Def Createblockgenerator (blockgeneratorlistener:blockgeneratorlistener): Blockgenerator = {//Cleanup BlockGenerators t Hat has already been stopped registeredblockgenerators--= registeredblockgenerators.filter{_.isstopped ()} Val NewBlo Ckgenerator = new Blockgenerator (Blockgeneratorlistener, Streamid, env.conf) registeredblockgenerators + = Newblockgenerator Newblockgenerator}


Call the Start method of Blockgenerator

/** Start block generating and pushing threads. */def start (): Unit = synchronized {if (state = = Initialized) {state = Active Blockintervaltimer.start () block Pushingthread.start () loginfo ("Started blockgenerator")} else {throw new Sparkexception (S "Cannot start Bloc Kgenerator as its not in the Initialized state [state = $state] ")}}

Blockintervaltimer is a timer that calls the Updatecurrentbuffer function when it's time.

Private Val Blockintervaltimer = new Recurringtimer (clock, Blockintervalms, Updatecurrentbuffer, "Blockgenerator")

Time interval default 200 milliseconds

Private Val Blockintervalms = conf.gettimeasms ("Spark.streaming.blockInterval", "200ms")

Blockpushingthread is a thread that continually writes data to Blockmanager

Private val blockpushingthread = new thread ()  { override def run ( )  { keeppushingblocks ()  } }/** Keep pushing blocks to the  Blockmanager. */private def keeppushingblocks ()  {  loginfo ("Started block  pushing thread ")   def areblocksbeinggenerated: boolean = synchronized  {    state != stoppedgeneratingblocks  }  try {     // while blocks are being generated, keep polling  for to-be-pushed blocks and push them.    while  ( areblocksbeinggenerated)  {      option (Blocksforpushing.poll (10,  timeunit.milliseconds))  match {        case some (block)  => pushblock (bLock)         case None =>       }    }    // at this point, state is  stoppedgeneratingblock. so drain the queue of to-be-pushed blocks.     loginfo ("pushing out the last "  + blocksforpushing.size ( )  +  " blocks")     while  (!blocksforpushing.isempty)  {       val block = blocksforpushing.take ()        Logdebug (S "pushing block  $block")       pushblock (block)        loginfo ("blocks left to push "  + blocksforpushing.size () )     }    loginfo ("Stopped block pushing thread")    } catch&nbSp {    case ie: interruptedexception =>       loginfo ("block pushing thread was interrupted")     case e:  exception =>      reporterror ("error in block  Pushing thread ",  e)   }}


As can be seen from the code, each 10ms removes all blocks from the blocksforpushing queue, calling the Pushblock method

Private def pushblock (Block:block) {Listener.onpushblock (block.id, Block.buffer) Loginfo ("pushed block" + block.id)}

The listener here are in Receiversupervisorimpl.

Private Val Defaultblockgeneratorlistener = new Blockgeneratorlistener {def onadddata (Data:any, metadata:any): Unit = {} def ongenerateblock (blockid:streamblockid): Unit = {} def onError (message:string, throwable:throwable) {repo Rterror (Message, Throwable)} def onpushblock (Blockid:streamblockid, arraybuffer:arraybuffer[_]) {Pusharraybuffer ( ArrayBuffer, None, Some (Blockid))}}

So the Pusharraybuffer method is called, and the following method is called:

/** store block and report it to driver */def pushandreportblock (     receivedblock: receivedblock,    metadataoption: option[ any],    blockidoption: option[streamblockid]  )  {  val  blockid = blockidoption.getorelse (Nextblockid)   val time =  System.currenttimemillis  val blockstoreresult = receivedblockhandler.storeblock ( Blockid, receivedblock)   logdebug (S "pushed block  $blockId  in ${( System.currenttimemillis - time)} ms ")   val numRecords =  Blockstoreresult.numrecords  val blockinfo = receivedblockinfo (streamId,  Numrecords, metadataoption, blockstoreresult)   trackerendpoint.askwithretry[boolean] ( Addblock (Blockinfo))   logdebug (S "reported block&nbSP; $blockId ")} 

This method, the data is given to the Receiverblockhandler store, and the metadata is reported to the Receivertracker.

Receiverblockhandler is implemented in two ways:

private val receivedblockhandler: receivedblockhandler = {  if  ( Writeaheadlogutils.enablereceiverlog (env.conf))  {    if  ( Checkpointdiroption.isempty)  {      throw new sparkexception (          "Cannot enable receiver write-ahead log  without checkpoint directory set.  " +            "Please use streamingcontext.checkpoint ()  to set the  checkpoint directory.  " +          " see  Documentation for more details. ")     }    new writeaheadlogbasedblockhandler (Env.blockManager,  receiver.streamId,      receiver.storageLevel, env.conf,  Hadoopconf, cHeckpointdiroption.get)   } else {    new  Blockmanagerbasedblockhandler (Env.blockmanager, receiver.storagelevel)   }}

The data will eventually be handed to Blockmanager.


Blocksforpushing is defined as follows:

Private Val blockqueuesize = Conf.getint ("Spark.streaming.blockQueueSize", ten) private Val blocksforpushing = new Arrayblockingqueue[block] (blockqueuesize)

The blocksforpushing data is written by the Blockintervaltimer timer periodically to the data in the Blockgenerator Currentbuffer.

/** change the buffer to which single records are added to.  */private def updatecurrentbuffer (Time: long):  unit = {  try  {    var newBlock: Block = null     synchronized {      if  (Currentbuffer.nonempty)  {         val newBlockBuffer = currentBuffer         currentBuffer = new ArrayBuffer[Any]         val blockid = streamblockid (Receiverid, time - blockintervalms )         listener.ongenerateblock (Blockid)          newblock = new block (Blockid, newblockbuffer)        }   &nbsP;}     if  (newblock != null)  {       Blocksforpushing.put (Newblock)   // put is blocking when queue is  full    }  } catch {    case ie:  Interruptedexception =>      loginfo ("Block updating timer  thread was interrupted ")     case e: Exception =>       reporterror ("Error in block updating thread",  e)    }}


Let's go back and look at Supervisor's Startreceiver () method:

/** start receiver */def startreceiver (): unit = synchronized {   try {    if  (Onreceiverstart ())  {       Loginfo ("Starting receiver")       receiverState = Started       receiver.onstart ()       loginfo ("Called  Receiver onstart ")     } else {      //  The driver refused us      stop ("Registered unsuccessfully  because Driver refused to start receiver  " + streamid, none )     }  } catch {    case nonfatal (t)  = >      stop ("error starting receiver "  + streamId,  some (t))  &nbsP;}} 

Call receiver's OnStart method, we take socketreceiver as an example:

Def onStart () {//Start the thread that receives data over a connection new thread ("Socket Receiver") {Setdaemon (tr UE) override def run () {receive ()}}.start ()}

In this function, a new thread "Socket Receiver" is generated, and the thread initiates the call to Socketreceiver's receive () method

 def receive ()  {    var socket: Socket = null     try {      loginfo ("connecting to "  +  host +  ":"  + port)       socket = new  Socket (Host, port)       loginfo ("connected to "  + host  +  ":"  + port)       val iterator =  Bytestoobjects (Socket.getinputstream ())       while (!isStopped &&  iterator.hasnext)  {        store (iterator.next)        }      if  (!isstopped ())  {         restart ("Socket data stream had no more data")       }&nbsP;else {        loginfo ("stopped receiving")        }    } catch {      case  e: java.net.connectexception =>        restart (" error connecting to  " + host + ": " + port, e"        case nonfatal (e)  =>         Logwarning ("Error receiving data",  e)         restart (" Error receiving data ",  e)     } finally {       if  (socket != null)  {         Socket.close ()         loginfo ("closed socket to "   + host +  ":"  + p ort)       }    }  }} 

A socket object is built, and the data is continuously received from the InputStream, and the store method is called every time it is received.

def store (dataitem:t) {Supervisor.pushsingle (DataItem)}

The data is managed by Receiversupervisor and calls Supervisor.pushsingle to write the data.

def pushsingle (Data:any) {defaultblockgenerator.adddata (data)}

Defaultblockgenerator is defined as follows

Private Val defaultblockgenerator = Createblockgenerator (defaultblockgeneratorlistener) override Def Createblockgenerator (blockgeneratorlistener:blockgeneratorlistener): Blockgenerator = {//Cleanup BlockGenerators t Hat has already been stopped registeredblockgenerators--= registeredblockgenerators.filter{_.isstopped ()} Val NewBlo Ckgenerator = new Blockgenerator (Blockgeneratorlistener, Streamid, env.conf) registeredblockgenerators + = Newblockgenerator Newblockgenerator}


It is a blockgenerator, and the AddData function saves the data in the Currentbuffer object in Blockgenerator

/** * push a single data item into the buffer. */def  AddData (Data: any): unit = {  if  (state == active)  {     waittopush ()     synchronized {       if  (state == active)  {        currentbuffer + = data      } else {         throw new sparkexception (           "cannot  add data as blockgenerator has not been started or has  been stopped ")       }    }  } else  {    throw new sparkexception (       "cannot  add data aS blockgenerator has not been started or has been stopped ")    }}


As the data flows in, each 200ms writes the data in the Currentbuffer to the blocksforpushing queue, and then instantiates a currentbuffer. The blocksforpushing queue is written to Blockmanager every 10ms.




Note:

1. DT Big Data Dream Factory public number Dt_spark
2, the IMF 8 o'clock in the evening big data real combat YY Live channel number: 68917580
3, Sina Weibo: Http://www.weibo.com/ilovepains


This article is from the "Ding Dong" blog, please be sure to keep this source http://lqding.blog.51cto.com/9123978/1774426

10th lesson: Spark Streaming Source interpretation data constantly receiving full life cycle thorough research and thinking

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.