Spark版本定制一:通过案例对SparkStreaming透彻理解三板斧之一

本期内容:

1 Spark Streaming另类在线实验

2 瞬间理解Spark Streaming本质

问:为什么从Spark Streaming来切入spark源码版本订制?
  1. Spark最开始的时候并没有Spark Streaming、Spark Sql、Spark ML、Spark R、Spark Graphx等相关的内容,就是很原始的Spark Core,Spark Streaming本身是Spark Core上的一个框架,透过一个框架的彻底研究可以彻底精通spark的方方面面;
  2. Spark用的最多的除了Spark Core之外,就是Spark Sql,Spark Sql由于涉及了太多的Sql语法细节的解析或优化,不适合作为一个具体的子框架来彻底研究Spark,而Spark R由于功能有限和不成熟,也排除掉,Spark Graphx最近发行的几个版本基本上没有改进,意味着Graphx基本上发展到尽头了,另外图计算有 很多数学计算算法,而Spark ML再封装了Vector(向量)、Matrix(矩阵)以及结合RDD构建了众多的库,ML也有很多的数学知识,所以综合下来选择了Spark Streaming来入手订制Spark版本;
  3. Spark Streaming是Spark工程师中应用最广、市场最好、最有吸引力的技术;
问:spark streaming到底有什么样的魔力呢?
  1. spark streaming是流式计算,这是一个流处理的时代,一切数据如果不是流失处理或者与流失处理不相关的话都是无效的数据;
  2. 流式处理才是真正对大数据的初步印象,数据流进来,立马给出反馈,而不是批处理、数据挖掘,当然它最强悍的地方,在于Spark Streaming可以在线的使用机器学习的成果或者图计算的结果或者Spark Sql、Spark R的结果,这是Spark一统江湖的根源;
  3. Spark的程序中,Spark Streaming是最容易出问题的!因为数据是不断的流进来,它要动态控制数据的流入、作业的切分还有数据的处理,最容易出错的地方,也是最容易体现个人价值的地方;
  4. Spark Streaming很像Spark Core之上的一个应用程序,如果精通了Spark Streaming,对于任何Spark问题都不在话下;
  5. Spark Streaming赢在转折点的趋势点上;它能感知程序下一步要做什么;
 

一、Spark Streaming另类在线实验

案例说明:
      广告点击的在线黑名单过滤:在广告点击计费系统中在线过滤掉黑名单的点击,进而保护广告商的利益只有效的广告点击计费
实验技巧:
      实战中我们一般会把Batch Interval设置的很小比如5s 10s 30s等,这里我们采用放大Batch Interval的技巧,把Batch Interval设置为300s,放大后对于job执行没有任何影响,但是更利于观察数据的流入、Job执行的过程等;
 
实验代码:
object OnlineBlackListFilter {
    def main(args: Array[String]){
      /**
       * 第1步:创建Spark的配置对象SparkConf,设置Spark程序的运行时的配置信息,例如说通过setMaster来设置程序要链接的Spark集群的Master的URL,如果设置
       * 为local,则代表Spark程序在本地运行,特别适合于机器配置条件非常差(例如只有1G的内存)的初学者
       */
      val conf = new SparkConf() //创建SparkConf对象
      conf.setAppName("OnlineBlackListFilter") //设置应用程序的名称,在程序运行的监控界面可以看到名称
      conf.setMaster("spark://Master:7077") //此时,程序在Spark集群
 
 
      //val ssc = new StreamingContext(conf, Seconds(30))
      //由30s改为300s
      val ssc = new StreamingContext(conf, Seconds(300))
 
      /**
       * 黑名单数据准备,实际上黑名单一般都是动态的,例如在Redis或者数据库中,黑名单的生成往往有复杂的业务逻辑,具体情况算法不同,但是在Spark Streaming进行处理的时候每次都能工访问完整的信息
       */
      val blackList = Array(("hadoop", true),("mahout", true))
      val blackListRDD = ssc.sparkContext.parallelize(blackList, 8)
 
      val adsClickStream = ssc.socketTextStream("Master", 9999)
 
      /**
       * 此处模拟的广告点击的每条数据的格式为:time、name 此处map操作的结果是name、(time,name)的格式
       */
      val adsClickStreamFormatted = adsClickStream.map { ads => (ads.split(" ")(1), ads) }
      adsClickStreamFormatted.transform(userClickRDD => {
        //通过leftOuterJoin操作既保留了左侧用户广告点击内容的RDD的所有内容,又获得了相应点击内容是否在黑名单中
        val joinedBlackListRDD = userClickRDD.leftOuterJoin(blackListRDD)
 
        /**
         * 进行filter过滤的时候,其输入元素是一个Tuple:(name,((time,name), boolean))
         * 其中第一个元素是黑名单的名称,第二元素的第二个元素是进行leftOuterJoin的时候是否存在在值
         * 如果存在的话,表面当前广告点击是黑名单,需要过滤掉,否则的话则是有效点击内容;
         */
        val validClicked = joinedBlackListRDD.filter(joinedItem => {
          if(joinedItem._2._2.getOrElse(false))
          {
            false
          } else {
            true
          }
        })
 
        validClicked.map(validClick => {validClick._2._1})
      }).print
 
      /**
       * 计算后的有效数据一般都会写入Kafka中,下游的计费系统会从kafka中pull到有效数据进行计费
       */
      ssc.start()
      ssc.awaitTermination()
    }
}

  

实验步骤:
      1、启动spark集群和spark history server进程(查看job的执行轨迹);
      2、在Master节点执行命令nc -lk 9999启动数据发送服务执行脚本SparkStreamingApps.sh启动job;
       3、观察执行结果:           
                在数据发送端口输入若干数据,比如:
                2255554 Spark
                455554444 Hadoop
                55555 Flink
                66666 Kafka
                6666855 RockySpark
                666638 Scala
                66666 DT_Spark
                通过浏览器查看Spark History Server信息:                
                
                点开第一个Job:
                Job0内幕:
                 
                    这边有5个完成的Job,我们实际执行的是一个Job,这里我们可以分析出很多内幕,5个job从上到下分别Revicer、print、print、print、start,点击进入start对应的DAG可视化视图:
                   
                    从Job0对应的DAG图和案例代码中可以看出此Job并不是我们对应的业务逻辑代码,从而可以得出如下结论:
                    Spark Streaming在运行的过程中,自己会启动一些job,比如我们点击Stage id下的Stage1进去,查看Aggregated Metrics by Executor部分
 
                    
                   
                       发现4个节点上都Job运行,最大化的利用了集群的资源,也充分说明了Spark Streaming就是一个应用程序;
             
                   Job1内幕:
              
                   
                   
                  问题:我们的应用程序没有1.5min中的Job,那为什么有1.5min中的Task呢?
                          是数据接收器Receiver,一直不断循环的接收数据,所以需要持续的运行!Receiver就是一个Job!Receiver通过Job启动!Receiver运行在Executor上,以一个Task运行,Receiver接收数据和普通的Job没有区别,
                          这给我们的启发是:Spark Application中可以启动很多的Job,不同的Job可以相互配合,为我们写复杂的应用程序奠定了良好的基础;而复杂的程序一定是有多个Job构成的!
 
                  从Tasks中的图中可以看到Locallty Level是PROCESS_LOCAL,没有从节点,Spark Streaming接收数据的方式,默认是MEMORY_AND_DISK_SER_2的
                  方式,再次说明数据量比较少,数据接收不会使用磁盘,而是直接使用内存中的数据;
 
                 Job2内幕:
                 
               
                 
                   从图中可以看出Job2主要负责执行程序的业务逻辑代码!Task分散在各个Executor上,充分利用了集群的资源!
 

二、 瞬间理解Spark Streaming本质

       

       图中的描述从上到下依次如下:

             Spark Streaming接收Kafka、Flume、HDFS和Kinesis等各种来源的实时输入数据,进行处理后,处理结果保存在HDFS、Databases等各种地方。

             Spark Streaming接收这些实时输入数据流,会将它们按批次划分,然后交给Spark引擎处理,生成按照批次划分的结果流。

             Spark Streaming提供了表示连续数据流的、高度抽象的被称为离散流的DStream。DStream本质上表示RDD的序列。任何对DStream的操作都会转变为对底层RDD的操作。

             Spark Streaming使用数据源产生的数据流创建DStream,也可以在已有的DStream上使用一些操作来创建新的DStream。

       

       DStream特性:

              DStream是一个没有边界的集合,没有大小的限制。

             DStream代表了时空的概念。随着时间的推移,里面不断产生RDD。

              锁定到时间段后,就是空间的操作。也就是对本时间段的对应批次的数据的处理

 

      下面介绍Spark Streaming内部实现原理:

      Spark Streaming程序转换为DStream Graph

      

         使用Spark Streaming编写的程序与编写Spark程序非常相似,在Spark程序中,主要通过操作RDD(Resilient Distributed Datasets弹性分布式数据集)提供的接口,如map、reduce、filter等,实现数据的批处理。

         而在Spark Streaming中,则通过操作DStream(表示数据流的RDD序列)提供的接口,这些接口和RDD提供的接口类似。

 

    DStream Graph转换为Spark jobs

        

Spark Streaming把程序中对DStream的操作转换为DStream Graph,对于每个时间片,DStream Graph都会产生一个RDD Graph;针对每个输出操作(如print、foreach等),Spark Streaming都会创建一个Spark action;对于每个Spark action,Spark Streaming都会产生一个相应的Spark job,并交给JobManager。JobManager中维护着一个Jobs队列, Spark job存储在这个队列中,JobManager把Spark job提交给Spark Scheduler,Spark Scheduler负责调度Task到相应的Spark Executor上执行。

Spark Streaming的另一大优势在于其容错性,RDD会记住创建自己的操作,每一批输入数据都会在内存中备份,如果由于某个结点故障导致该结点上的数据丢失,这时可以通过备份的数据在其它结点上重算得到最终的结果。

正如Spark Streaming最初的目标一样,它通过丰富的API和基于内存的高速计算引擎让用户可以结合流式处理,批处理和交互查询等应用。因此Spark Streaming适合一些需要历史数据和实时数据结合分析的应用场合。当然,对于实时性要求不是特别高的应用也能完全胜任。另外通过RDD的数据重用机制可以得到更高效的容错处理。

 

本章总结:

1.Spark Streaming本身很像Spark Core之上的一个应用程序,内部通过调用Spark Core的RDD接口对数据进行处理;

2.Spark Application中可以启动很多的Job,不同的Job可以相互配合,从而构建出复杂的、大型的应用程序;

3.DStream内部是转换为一系列的RDD去运行;

 

特别感谢王家林老师的独具一格的讲解:

王家林老师名片:

中国Spark第一人

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

微信公众号:DT_Spark

博客:http://blog.sina.com.cn/ilovepains

QQ:1740415547

YY课堂:每天20:00现场授课频道68917580

posted on 2016-05-05 15:23  Harvey.Sun  阅读(255)  评论(0编辑  收藏  举报

导航