大数据之Spark(四)--- Dependency依赖,启动模式,shuffle,RDD持久化,变量传递,共享变量,分布式计算PI的值

一、Dependency:依赖:RDD分区之间的依存关系
---------------------------------------------------------
    1.NarrowDependency: 子RDD的每个分区依赖于父RDD的少量分区。
         |
        / \
        ---
         |---- OneToOneDependency      //父子RDD之间的分区存在一对一关系。
         |---- RangeDependency         //父RDD的一个分区范围和子RDD存在一对一关系。
         |---- PruneDependency         //删减依赖--在PartitionPruningRDD和其父RDD之间的依赖,子RDD包含了父RDD的分区子集。。

    2.ShuffleDependency                 //混洗依赖,在shuffle阶段输出时的一种依赖。

二、SparkContext创建调度器的过程
------------------------------------------------------------------
   [SparkContext.scala:501行]
    val (sched, ts) = SparkContext.createTaskScheduler(this, master, deployMode)
    _schedulerBackend = sched
    _taskScheduler = ts
    _dagScheduler = new DAGScheduler(this)


三、Spark启动模式
--------------------------------------------------
    1.[本地模式,通过线程模拟]
        本地后台调度器
        spark local
        spark local[3]                   //3线程,模拟cluster集群
        spark local[*]                   //匹配cpu个数,
        spark local[3,2]                  //3:3个线程,2表示每个分区重试1次[0和1等价,不重试]

        conf.seetMaster[3]
        conf.seetMaster[*]
        conf.seetMaster[3,2]

    2.[相当于伪分布式]
        StandaloneSchedulerBackend
        spark local-cluster[N, cores, memory]  //模拟spark集群。

    3.[完全分布式]
        StandaloneSchedulerBackend
        spark spark://s201:7077                //连接到spark集群上.

    4.代码演示
        
import org.apache.spark.{SparkConf, SparkContext}

        object Test8 {

            def main(args: Array[String]): Unit = {

                val sparkConf: SparkConf = new SparkConf()
                sparkConf.setAppName("Test-1")
                sparkConf.setMaster("local[2]")
                sparkConf.setMaster("local[*]")
                sparkConf.setMaster("local[2,3]")
                sparkConf.setMaster("local[*]")
                val sc: SparkContext = new SparkContext(sparkConf)

                val data = List(1,2,3,4,5,6,7,8,9,10);
                val rdd1 = sc.parallelize(data)
                val rdd2 = rdd1.map(
                    e => {
                        val s = Thread.currentThread().getName();
                        println(s);
                        e
                    }
                )

                val rdd3 = rdd1.repartition(4);
                val rdd4 = rdd3.map(
                    e => {
                        val s = Thread.currentThread().getName();
                        println(s);
                        e
                    }
                )
                rdd4.collect()
            }
        }


四、shuffle操作
--------------------------------------------------
    1.跨分区再分发数据的一种机制

    2.触发shuffle的操作:groupByKey reduceByKey...  reparatition coalesce...  join cogroup

    3.shuffle对性能的影响
        a.shuffle涉及到磁盘或者网络io,所以成本很高
        b.shuffle为了数据重用,在磁盘上生成大量的中间文件
        c.垃圾回收如果不及时,长时间的shuffle会占用大量的磁盘空间


五、RDD持久化
--------------------------------------------------
    1.数据在内存中持久化,可以跨操作

    2.持久化RDD时,节点上的每个分区的数据都会保存在内存中,以备在其他操作中进行重用

    3.这种缓存技术是迭代式计算和交互式查询的重要手段。

    4.可以使用persist()和cache(),来进行rdd的持久化,cache()是persist()一种,使用内存方式进行缓存
        a.首次Action计算时,会发生persist(),会将计算的数据保存在节点内存中
        b.spark的这种缓存机制,是容错的,如果rdd的任何一个分区丢失了,都可以通过最初创建rdd的进行重新计算出直到Action的RDD结果
        c.每个RDD都可以使用不同的存储级别进行持久化,可以通过storelevel进行设定
            MEMORY_ONLY          //只在内存
            MEMORY_AND_DISK
            MEMORY_ONLY_SER       //内存存储(串行化)
            MEMORY_AND_DISK_SER
            DISK_ONLY        //硬盘
            MEMORY_ONLY_2     //带有副本
            MEMORY_AND_DISK_2  //快速容错。
            OFF_HEAP

        d.级别选取建议
            如果想快速容错,就带副本:MEMORY_ONLY_2
            如果内存足够,选取MEMORY_ONLY
            如果内存不是很足够,选取MEMORY_ONLY_SER
            尽量不要缓存到磁盘,除非内存非常不够

    5.删除持久化数据
        rdd2.unpersist(isBlocking = true)

    6.代码演示
        
import org.apache.spark.storage.StorageLevel
        import org.apache.spark.{SparkConf, SparkContext}

        object TestPersist {

            def main(args: Array[String]): Unit = {
                val sparkConf: SparkConf = new SparkConf()
                sparkConf.setAppName("Test-1")
                sparkConf.setMaster("local")
                val sc: SparkContext = new SparkContext(sparkConf)

                val rdd1 = sc.parallelize(1 to 20)

                val rdd2 = rdd1.map(
                    e => {
                        println(e)
                        e * 2
                    }
                )
                //更改缓存地
                rdd2.persist(StorageLevel.DISK_ONLY)
                //rdd2.persist(StorageLevel.MEMORY_ONLY)
                //将rdd2的结果缓存到内存中
                //rdd2.cache()
                println(rdd2.reduce(_ + _))
                //移除缓存
                rdd2.unpersist(true)
                println(rdd2.reduce(_ + _))
            }
        }


六、变量传递过程中的串行化
----------------------------------------------------------
    因为是集群计算,所以map过程的代码和过程中的变量,会将变量的值拷贝,然后通过网络,分发到各个节点,[区别于共享变量:每次计算都要分发的]过程中需要进行串行和反串行,所以就要求过程中的变量要能串行化
        scala> class Dog
        scala> val d = new Dog
        scala> sc.parallelize(1 to 20).map( e=> {println(d);e}).reduce(_ + _)
        //会报错因为dog不能串行化
        //需要定义Dog的时候继承Serializable接口
        scala> case class Dog (name:String,age:Int)
        scala> val d = Dog("tom",1)
        scala> sc.parallelize(1 to 20).map( e=> {println(d);e}).reduce(_ + _)


七、共享变量
---------------------------------------------------
    1.在所有的节点间共享一个变量。

    2.Spark通过广播变量和累加器实现变量的共享

    3.广播变量
        a.一个只读的变量,在创建的时候广播一次[也必须继承了串行化接口],然后在每个节点进行缓存。而不是跟随任务进行网络间传递

        b.使用方式
            scala> val broadcastVar = sc.broadcast(Array(1,2,3))
            broadcastVar: org.apache.spark.broadcast.Broadcast[Array[Int]] = Broadcast(3)

            scala> broadcastVar.value
            res7: Array[Int] = Array(1, 2, 3)

    4.累加器
        a.一个只能增加的变量,高效并行。通常用于MR的Counter和Sum。UI可见

        b.使用方式
            scala> val ac1 = sc.longAccumulator("ac1")
            ac1: org.apache.spark.util.LongAccumulator = LongAccumulator(id: 288, name: Some(ac1), value: 0)

            scala> ac1.value
            res8: Long = 0

            scala> sc.parallelize(1 to 20).map(_ * 2).map(e=>{ac1.add(1) ; e}).reduce(_+_)
            res9: Int = 420

            scala> ac1.value
            res10: Long = 20

        c.自定义累加器
            class MyAccumulatorV2 extends AccumulatorV2[V,T]{
                private val v:V = ...

                def reset():
                def add():
                def sum():
                def count():
                def value():
                ...
            }

八、Spark分布式计算PI的值
----------------------------------------------------------
    scala> sc.parallelize(1 to 999999999).map(e=>{
            val a = 1f / (2 * e - 1) ;
            val b = if (e % 2 == 0) -1 else 1 ;
            a * b * 4
        }
    ).reduce(_+_)

    res19: Float = 3.1415954








猜你喜欢

转载自blog.csdn.net/xcvbxv01/article/details/83823006