Spark Streaming 架构:
    1,Spark Streaming为每个输入源启动对应的接收器。接收器以任务的形式运行在应用的执行器进程中,从输入源收集数据并保存为 RDD。
    2,收集到输入数据后会把数据复制到另一个执行器进程来保障容错性(默 认行为)。数据保存在执行器进程的内存中,和缓存 RDD 的方式一样。
    3,驱动器程序中的 StreamingContext 会周期性地运行 Spark 作业来处理这些数据,把数据与之前时间区间中的 RDD 进行整合。
    4,每个接收器都以 Spark 执行器程序中一个长期运行的任务的形式运行,因此会占据分配给应用的 CPU 核心。
    5,我们还需要有可用的 CPU 核心来处理数据。这意味着如果要运行多个接收器,就必须至少有和接收器数目相同的核心数,还要加上用来完成计算所需要的核心数(最少一个)。

pyspark distinct去重_pyspark distinct去重

自定义 接收器
package Day3

import java.io.{BufferedReader, InputStreamReader}
import java.net.Socket

import org.apache.spark.storage.StorageLevel
import org.apache.spark.streaming.receiver.Receiver

class Streaming_(host: String, port:Int) extends Receiver[String](StorageLevel.MEMORY_ONLY){
  // 接收器启动的时候调用
  override def onStart(): Unit = {
    // 接收器是线程来实现的
    new Thread("receiver"){
      override def run(): Unit = {
        print("---------------------")
        // 接受数据提交给 框架
        receive()
      }
    }.start()
  }
  def receive(): Unit ={
    var sockt:Socket = null
    var input:String = null
    try{
      // 使用 Socket 监听端口
      sockt = new Socket(host,port)
      // 生成输入流
      val reader = new BufferedReader(new InputStreamReader(sockt.getInputStream))

//      // 数据传递给 executor
//      store(input)
      while (!isStopped()&& (input=reader.readLine())!=null){
        store(input)
        input=reader.readLine()
      }
      restart("restart")

    }catch {
      case e:java.net.ConnectException => restart("restart")
      case t:Throwable => restart("restart")
    }
  }
  // 接收器关闭调用
  override def onStop(): Unit = {

  }
}
使用无状态接收器(没有使用自定义接收器)
package Day3
import org.apache.spark.SparkConf
import org.apache.spark.streaming.{Seconds, StreamingContext}
object Wc {
  def main(args: Array[String]): Unit = {
      val conf = new SparkConf().setMaster("local[*]").setAppName("wc")
      val ssc = new StreamingContext(conf,Seconds(5))
      //接受的数据方式,返回的是一行一行的数据, 接受 master:9999 端口
      val lineDstream = ssc.socketTextStream("master",9999)
      val wordsDstream = lineDstream.flatMap(_.split(" "))
      val k2vDstream = wordsDstream.map((_,1))
      val results = k2vDstream.reduceByKey(_+_)
      results.print()
      // 开启 Stream 启动消息采集和处理
      ssc.start()
    /*
    -------------------------------------------
    Time: 1561649120000 ms
    -------------------------------------------
    (da,1)
    (DA,1)
    (ad,2)
    (AD,3)
    */
      ssc.awaitTermination()
  }}
使用有状态接收器,实际使用了 checkpoint 保存了上次 状态
package Day3
import org.apache.spark.SparkConf
import org.apache.spark.streaming.{Seconds, StreamingContext}
object Wc {
    def main(args: Array[String]): Unit = {
        val conf = new SparkConf().setMaster("local[2]").setAppName("wc")
        val ssc = new StreamingContext(conf,Seconds(5))
        ssc.checkpoint("./check")
        //接受的数据方式,返回的是一行一行的数据, 接受 master:9999 端口
        //      val lineDstream = ssc.socketTextStream("master",9999)
        // 使用自定义的接收器
        val lineDstream = ssc.receiverStream(new Streaming_("master",9999))
        val wordsDstream = lineDstream.flatMap(_.split(" "))
        val k2vDstream = wordsDstream.map((_,1))
        val updateFuc = (v:Seq[Int],state:Option[Int])=>{
            val preStatus = state.getOrElse(0)
            Some(preStatus+v.sum)
        }
        val results = k2vDstream.updateStateByKey(updateFuc)
        results.print()
        // 开启 Stream 启动消息采集和处理
        ssc.start()
        /*
-------------------------------------------
Time: 1561799425000 ms
-------------------------------------------
(4,1)
(ss,1)
(55,1)
(2,1)
(,3)
(s,8)
(234,1)
(3,3)
(q,3)
(12,1)
...
        */
        ssc.awaitTermination()
    }}

/*
SparkStreaming是准实时的处理框架(微批处理),按照时间段进行收集数据
以上代码运行说明

* */
以上代码运行说明

pyspark distinct去重_数据_02

使用 Window Operations 来获取 Streaming运行状态
package Day3
import org.apache.spark.SparkConf
import org.apache.spark.streaming.{Seconds, StreamingContext}
object Wc {
    def main(args: Array[String]): Unit = {
        val conf = new SparkConf().setMaster("local[2]").setAppName("wc")
        val ssc = new StreamingContext(conf,Seconds(5))
        ssc.checkpoint("./check")
        //接受的数据方式,返回的是一行一行的数据, 接受 master:9999 端口
        //      val lineDstream = ssc.socketTextStream("master",9999)
        // 使用自定义的接收器
        val lineDstream = ssc.receiverStream(new Streaming_("master",9999))
        val wordsDstream = lineDstream.flatMap(_.split(" "))
        val k2vDstream = wordsDstream.map((_,1))
//        val updateFuc = (v:Seq[Int],state:Option[Int])=>{
//            val preStatus = state.getOrElse(0)
//            Some(preStatus+v.sum)
//        }
//        val results = k2vDstream.updateStateByKey(updateFuc)

        // 使用窗口函数 (reduce 函数,窗口大小,步长)
      //  每次重新计算,重复的部分删掉
//         val results = k2vDstream.reduceByKeyAndWindow((x:Int,y:Int)=>x+y,Seconds(15),Seconds(10))

      // 使用窗口函数 (reduce 函数,减去多余的(前五秒的),窗口大小,步长)
      // 这种方式更加优化,针对重复次数来计算
        val results = k2vDstream.reduceByKeyAndWindow((x:Int,y:Int)=>x+y,(a:Int,b:Int)=>a-b,Seconds(15),Seconds(10))
        results.print()
        // 开启 Stream 启动消息采集和处理
        ssc.start()
        /*
-------------------------------------------
Time: 1561866450000 ms
-------------------------------------------
(2,8)
(,1)
(22,1)
(1,3)
*/
        ssc.awaitTermination()
    }}
以上代码运行说明

pyspark distinct去重_pyspark distinct去重_03