大数据实时阶段----【Spark02之ip地址查询、topN、PV、UV实战】

spark笔记之通过Spark实现ip地址查询 1. 需求分析         在互联网中,我们经常会见到城市热点图这样的报表数据,例如在百度统计中,会统计今年的热门旅游城市、热门报考学校等,会将这样的信息显示在热点图中。         因此,我们需要通过日志信息(运行商或者网站自己生成)和城市ip段信息来判断用户的ip段,统计热点经纬度。 2. 技术调研         因为我们的需求是完成一张报表信息,所以对程序的实时性没有要... 阅读详情

spark02_学习笔记

1、目标
  • 1、掌握RDD的底层原理
  • 2、掌握RDD的常用的算子操作
  • 3、掌握RDD的宽窄依赖
  • 4、掌握RDD的缓存机制
  • 5、掌握划分stage
  • 6、掌握spark任务运行架构和调度流程
2、RDD概述
2.1 什么是RDD
RDD(Resilient Distributed Dataset)叫做弹性分布式数据集,是Spark中最基本的数据抽象,它代表一个不可变、可分区、里面的元素可并行计算的集合。

Dataset:它是一个集合,集合里面有很多个元素
Distributed:rdd中的数据是进行了分布式存储,后期方便于进行分布式计算。
Resilient:弹性,可以意味着rdd的数据可以保存在内存或者是磁盘中。
2.2 RDD的五大属性

在这里插入图片描述

(1) A list of partitions
一个分区列表
	它表示一个rdd中有很多个分区,后期spark任务的计算是以分区为单位进行计算。一个分区就对应上一个task线程。
	val rdd=sc.textFile(文件)
	该文件的block个数小于等于2,这个时候rdd的分区数就是2
	该文件的block个数大于2,  这个时候rdd的分区数就跟block个数相等
	
	

(2) A function for computing each split
  作用在每一个分区中的函数
  var rdd2=rdd1.map(x=>(x,1))


(3) A list of dependencies on other RDDs
  一个RDD会依赖于其他多个RDD,这里就涉及到RDD与RDD之间的依赖关系,后期spark任务的容错机制就是根据这个特性而来。
   var rdd2=rdd1.map(x=>(x,1))

(4) Optionally, a Partitioner for key-value RDDs (e.g. to say that the RDD is hash-partitioned)
    (可选性) 一个分区函数,针对于一个kv类型的RDD才会有分区函数(必须要产生shuffle)。对于不是kv类型的RDD,它的分区函数是None.  spark提供了2种shuffle机制,第一种默认值:hashPartitioner ------->  key.hashcode % 分区数=分区号,
    第二种RangePartitioner: 基于一个范围的分区策略。


(5) Optionally, a list of preferred locations to compute each split on (e.g. block locations for an HDFS file)
    (可选性)   一个优先的数据分区列表,这里就涉及到数据本地性和数据位置最优(指的是哪个节点上有数据 , 就优先考虑哪个节点)。
    spark后期再进行任务分配的时候,会优先考虑存有数据的worker节点来进行任务的计算。

当任务运行到reduceByKey的时候 , 此时产生了shuffle , 因此每个shuffle中的内容有可能来自于多个分区 .

2.3 创建RDD
  • 1、通过一个已经存在的scala集合去构建
    • val rdd1=sc.parallelize(List(1,2,3,4),2)
  • 2、通过加载外部的数据源去构建
    • val rdd2=sc.textFile("/words.txt")
  • 3、通过一个已经存在的rdd去构建
    • val rdd3=rdd2.flatMap(x=>x.split(" "))
3、RDD中算子操作
  • rdd中算子一共可以分为2类

  • transformation(转换)

    • 它是一个转换,可以实现把一个rdd转换生成一个新的rdd,它不会立即触发任务的运行,它是延迟加载。
      • 它只是记录下作用在rdd的上转换操作
      • 比如
        • flatMap/map/reduceByKey/sortBy
  • action (动作)

    • 它会触发任务的真正运行

      • 比如

        • collect/saveAsTextFile
  • 常用的Transformation:
转换含义
map(func)返回一个新的RDD,该RDD由每一个输入元素经过func函数转换后组成
filter(func)返回一个新的RDD,该RDD由经过func函数计算后返回值为true的输入元素组成
flatMap(func)类似于map,但是每一个输入元素可以被映射为0或多个输出元素(所以func应该返回一个序列,而不是单一元素)
mapPartitions(func)类似于map,但独立地在RDD的每一个分片上运行,因此在类型为T的RDD上运行时,func的函数类型必须是Iterator[T] => Iterator[U]
mapPartitionsWithIndex(func)类似于mapPartitions,但func带有一个整数参数表示分片的索引值,因此在类型为T的RDD上运行时,func的函数类型必须是 (Int, Interator[T]) => Iterator[U]
union(otherDataset)对源RDD和参数RDD求并集后返回一个新的RDD
intersection(otherDataset)对源RDD和参数RDD求交集后返回一个新的RDD
distinct([numTasks]))对源RDD进行去重后返回一个新的RDD
groupByKey([numTasks])在一个(K,V)的RDD上调用,返回一个(K, Iterator[V])的RDD
reduceByKey(func, [numTasks])在一个(K,V)的RDD上调用,返回一个(K,V)的RDD,使用指定的reduce函数,将相同key的值聚合到一起,与groupByKey类似,reduce任务的个数可以通过第二个可选的参数来设置
sortByKey([ascending], [numTasks])在一个(K,V)的RDD上调用,K必须实现Ordered接口,返回一个按照key进行排序的(K,V)的RDD
sortBy(func,[ascending], [numTasks])与sortByKey类似,但是更灵活
join(otherDataset, [numTasks])在类型为(K,V)和(K,W)的RDD上调用,返回一个相同key对应的所有元素对在一起的(K,(V,W))的RDD
cogroup(otherDataset, [numTasks])在类型为(K,V)和(K,W)的RDD上调用,返回一个(K,(Iterable,Iterable))类型的RDD
coalesce(numPartitions)减少 RDD 的分区数到指定值。
repartition(numPartitions)重新给 RDD 分区
repartitionAndSortWithinPartitions(partitioner)重新给 RDD 分区,并且每个分区内以记录的 key 排序
  • 常用Action类
动作含义
reduce(func)reduce将RDD中元素前两个传给输入函数,产生一个新的return值,新产生的return值与RDD中下一个元素(第三个元素)组成两个元素,再被传给输入函数,直到最后只有一个值为止。
collect()在驱动程序中,以数组的形式返回数据集的所有元素
count()返回RDD的元素个数
first()返回RDD的第一个元素(类似于take(1))
take(n)返回一个由数据集的前n个元素组成的数组
takeOrdered(n, [ordering])返回自然顺序或者自定义顺序的前 n 个元素
saveAsTextFile(path)将数据集的元素以textfile的形式保存到HDFS文件系统或者其他支持的文件系统,对于每个元素,Spark将会调用toString方法,将它装换为文件中的文本
saveAsSequenceFile(path)将数据集中的元素以Hadoop sequencefile的格式保存到指定的目录下,可以使HDFS或者其他Hadoop支持的文件系统。
saveAsObjectFile(path)将数据集的元素,以 Java 序列化的方式保存到指定的目录下
countByKey()针对(K,V)类型的RDD,返回一个(K,Int)的map,表示每一个key对应的元素个数。
foreach(func)在数据集的每一个元素上,运行函数func
foreachPartition(func)在数据集的每一个分区上,运行函数func
  • RDD常用的算子操作

    Spark Rdd的所有算子操作,请见《sparkRDD函数详解》

    启动spark-shell 进行测试:

    spark-shell --master spark://node1:7077

    也可本地操作spark-shell --master local[2]

    练习1:map、filter

    //通过并行化生成rdd
    val rdd1 = sc.parallelize(List(5, 6, 4, 7, 3, 8, 2, 9, 1, 10))
    
    //对rdd1里的每一个元素乘2然后排序
    val rdd2 = rdd1.map(_ * 2).sortBy(x => x, true)
    
    //过滤出大于等于5的元素
    val rdd3 = rdd2.filter(_ >= 5)
    
    //将元素以数组的方式在客户端显示
    rdd3.collect
    

    练习2:flatMap

    val rdd1 = sc.parallelize(Array("a b c", "d e f", "h i j"))
    //将rdd1里面的每一个元素先切分在压平
    
    val rdd2 = rdd1.flatMap(_.split(" "))
    rdd2.collect
    

    练习3:交集、并集

    val rdd1 = sc.parallelize(List(5, 6, 4, 3))
    val rdd2 = sc.parallelize(List(1, 2, 3, 4))
    
    //求并集
    val rdd3 = rdd1.union(rdd2)
    
    //求交集
    val rdd4 = rdd1.intersection(rdd2)
    
    //去重
    rdd3.distinct.collect
    rdd4.collect
    

    练习4:join、groupByKey

    val rdd1 = sc.parallelize(List(("tom", 1), ("jerry", 3), ("kitty", 2)))
    val rdd2 = sc.parallelize(List(("jerry", 2), ("tom", 1), ("shuke", 2)))
    
    //求join
    val rdd3 = rdd1.join(rdd2)
    rdd3.collect
    
    //求并集
    val rdd4 = rdd1 union rdd2
    rdd4.collect
    
    //按key进行分组
    val rdd5=rdd4.groupByKey
    rdd5.collect
    

    练习5:cogroup

    val rdd1 = sc.parallelize(List(("tom", 1), ("tom", 2), ("jerry", 3), ("kitty", 2)))
    val rdd2 = sc.parallelize(List(("jerry", 2), ("tom", 1), ("jim", 2)))
    //cogroup
    val rdd3 = rdd1.cogroup(rdd2)
    //注意cogroup与groupByKey的区别
    rdd3.collect
    

    练习6:reduce

    val rdd1 = sc.parallelize(List(1, 2, 3, 4, 5))
    //reduce聚合
    val rdd2 = rdd1.reduce(_ + _)
    rdd2.collect
    

    练习7:reduceByKey、sortByKey

    val rdd1 = sc.parallelize(List(("tom", 1), ("jerry", 3), ("kitty", 2),  ("shuke", 1)))
    val rdd2 = sc.parallelize(List(("jerry", 2), ("tom", 3), ("shuke", 2), ("kitty", 5)))
    val rdd3 = rdd1.union(rdd2)
    //按key进行聚合
    val rdd4 = rdd3.reduceByKey(_ + _)
    rdd4.collect
    
    //按value的降序排序
    val rdd5 = rdd4.map(t => (t._2, t._1)).sortByKey(false).map(t => (t._2, t._1))
    rdd5.collect
    

    练习8:repartition、coalesce

    val rdd1 = sc.parallelize(1 to 10,3)
    //利用repartition改变rdd1分区数
    //减少分区
    rdd1.repartition(2).partitions.size
    //增加分区
    rdd1.repartition(4).partitions.size
    //利用coalesce改变rdd1分区数
    //减少分区
    rdd1.coalesce(2).partitions.size
    

注意:repartition可以增加和减少rdd中的分区数 , 可用于小文件的整合 , 将多个小文件放在一个分区中,coalesce只能减少rdd分区数,增加rdd分区数不会生效。

4、通过spark实现点击流日志分析案例
4.1 统计PV
package cn.itcast.rdd

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

//todo:利用spark实现点击流日志数据分析----------------PV
object PV {
  def main(args: Array[String]): Unit = {
       //1、创建SparkConf
      val sparkConf: SparkConf = new SparkConf().setAppName("PV").setMaster("local[2]")

      //2、创建SparkContext
      val sc = new SparkContext(sparkConf)
      sc.setLogLevel("warn")

     //3、读取数据文件
     val data: RDD[String] = sc.textFile("E:\\data\\access.log")

    //4、统计pv
    val pv: Long = data.count()
    println("PV:"+pv)

    //5、关闭
    sc.stop()

  }
}
4.2 统计UV
package cn.itcast.rdd

import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.rdd.RDD

//todo:利用spark实现点击流日志数据分析----------------UV
object UV {
  def main(args: Array[String]): Unit = {
    //1、创建SparkConf
    val sparkConf: SparkConf = new SparkConf().setAppName("UV").setMaster("local[2]")

    //2、创建SparkContext
    val sc = new SparkContext(sparkConf)
    sc.setLogLevel("warn")

    //3、读取数据文件
    val data: RDD[String] = sc.textFile("E:\\data\\access.log")

    //4、切分每一行,获取所有的ip地址
      val ips: RDD[String] = data.map(x=>x.split(" ")(0))

    //5、根据ip地址去重
      val distinctRDD: RDD[String] = ips.distinct()

    //6、统计UV
       val uv: Long = distinctRDD.count()
      println("UV:"+uv)

    //7、关闭
      sc.stop()
  }
}

4.3 统计TopN
package cn.itcast.rdd

import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.rdd.RDD

//todo:利用spark实现点击流日志数据分析----------------TopN(把访问url出现次数最多的前N位获取得到)
object TopN {
  def main(args: Array[String]): Unit = {
    //1、创建SparkConf
    val sparkConf: SparkConf = new SparkConf().setAppName("TopN").setMaster("local[2]")

    //2、创建SparkContext
    val sc = new SparkContext(sparkConf)
    sc.setLogLevel("warn")

    //3、读取数据文件
    val data: RDD[String] = sc.textFile("E:\\data\\access.log")

    //4、先过滤出丢失的字段的记录
    val urlAndOne: RDD[(String, Int)] = data.filter(x=>x.split(" ").length >10).map(x=>x.split(" ")(10)).map(x=>(x,1))

   //5、相同url出现的1累加
   val result: RDD[(String, Int)] = urlAndOne.reduceByKey(_+_)
      
   //将输出的结果去掉"-"的项
   val fresult: RDD[(String, Int)] = result.filter(x=>x._1!="\"-\"")

   //6、按照url出现的次数降序
   val sortedRDD: RDD[(String, Int)] = fresult.sortBy(x=>x._2,false)

    //7、取出出现次数最多的前5位
    val finalResult: Array[(String, Int)] = sortedRDD.take(5)

      finalResult.foreach(println)

    //8、关闭
    sc.stop()

  }
}
5、通过spark实现ip地址查询
package cn.itcast.rdd

import java.sql.{Connection, DriverManager, PreparedStatement}

import org.apache.spark.broadcast.Broadcast
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

//todo:利用spark来实现ip地址查询
object Iplocation {

   //把String类型的ip转换成Long类型的数字   192.168.200.100
  def ip2Long(ip: String): Long ={
      val ips: Array[String] = ip.split("\\.")
      var ipNum:Long=0L

      for(i <- ips){
         ipNum= i.toLong  |  ipNum << 8
      }

    ipNum

  }

  def binarySearch(ipNum: Long, broadCastValue: Array[(String, String, String, String)]): Int = {
      var start=0
      var end=broadCastValue.length-1

      while(start <= end){
           val middle=(start+end)/2

        if(ipNum >=broadCastValue(middle)._1.toLong && ipNum <= broadCastValue(middle)._2.toLong){
            return middle
        }

        if(ipNum < broadCastValue(middle)._1.toLong){
           end=middle-1
        }

        if(ipNum >broadCastValue(middle)._2.toLong){
          start=middle+1
        }

      }
    -1
  }

   //把数据写入到mysql表中
  def data2mysql(iter:Iterator[((String,String), Int)])= {
    //定义数据库连接
      var conn:Connection=null
    //定义PrepareStatement
      var ps:PreparedStatement=null

    //定义sql语句
      val sql="insert into iplocation(longitude,latitude,total_count)  values(?,?,?)"

    //获取数据库连接
    conn= DriverManager.getConnection("jdbc:mysql://192.168.200.100:3306/spark","root","123456")
    //获取PrepareStatement
    ps=conn.prepareStatement(sql)

    //遍历迭代器
      try {
        iter.foreach(line => {
          //给?占位符赋值
          ps.setString(1, line._1._1)
          ps.setString(2, line._1._2)
          ps.setLong(3, line._2)

          ps.execute()
        })
      } catch {
        case e:Exception => println(e)
      } finally {

        if(ps!=null){
           ps.close()
        }

        if(conn!=null){
          conn.close()
        }

      }

  }

  def main(args: Array[String]): Unit = {
       //1、创建SparkConf
      val sparkConf: SparkConf = new SparkConf().setAppName("Iplocation").setMaster("local[2]")
      //2、创建SparkContext
      val sc = new SparkContext(sparkConf)
      sc.setLogLevel("warn")

     //3、读取城市ip信息数据文件   获取ip开始数字,ip结束数字,经度,维度
       val city_ip_rdd: RDD[(String, String, String, String)] = sc.textFile("E:\\data\\ip.txt").map(x=>x.split("\\|")).map(x=>(x(2),x(3),x(x.length-2),x(x.length-1)))

      //把城市ip信息数据通过广播变量下发到每一个worker节点  ,broadcast方法中需要给定rdd的真实数据,不能够直接把rdd传进去
       val city_ip_broadcast: Broadcast[Array[(String, String, String, String)]] = sc.broadcast(city_ip_rdd.collect())


    //4、读取运营商日志数据  获取所有的ip地址
        val ips: RDD[String] = sc.textFile("E:\\data\\20090121000132.394251.http.format").map(x=>x.split("\\|")(1))

    //5、遍历ips,获取每一个ip,然后把ip地址转换成Long类型,后期去匹配
    val result: RDD[((String, String), Int)] = ips.mapPartitions(iter => {
      //获取广播变量的值
      val broadCastValue: Array[(String, String, String, String)] = city_ip_broadcast.value
      //遍历迭代器,获取每一个ip地址
      iter.map(ip => {
        //把ip地址转换成Long类型数字
        val ipNum: Long = ip2Long(ip)

        //通过二分查询获取ipNum在broadCastValue数组中的下标
        val index: Int = binarySearch(ipNum, broadCastValue)

        //获取下标对应的元素
        val value: (String, String, String, String) = broadCastValue(index)

        //返回结果数据  ((经度,维度),1)
        ((value._3, value._4), 1)
      })

    })
    //6、把相同经度和维度出现的1累加
    val finalResult: RDD[((String, String), Int)] = result.reduceByKey(_+_)

    //7、打印结果数据
      finalResult.foreach(println)

     //把结果数据写入到mysql表中
      finalResult.foreachPartition(data2mysql)

    //8、关闭
    sc.stop()
  }
}

扩展 : 广播变量图解

在这里插入图片描述

广播变量极大地减少了内存的开销 , 保证了程序的正常运行

6、RDD的依赖关系

在这里插入图片描述

  • rdd与rdd之间有依赖关系

    • 窄依赖

      窄依赖指的是每一个父RDD的Partition最多被子RDD的一个Partition使用
      总结:窄依赖我们形象的比喻为独生子女
      
      窄依赖不会产生shuffle
      flatMap filter map....
      
    • 宽依赖

      宽依赖指的是多个子RDD的Partition会依赖同一个父RDD的Partition
      总结:宽依赖我们形象的比喻为超生 
      
      宽依赖会产生shuffle
      reduceByKey  groupByKey  sortBy....
      
7、lineage(血统)
	rdd后期会进行大量的转换操作,我们把rdd的这些操作行为记录下来,记录下来的信息我们就称为lineage(血统)
血统好处:
	当前某一个rdd的分区数据丢失了,可以通过血统这一层关系来重新计算恢复得到。这里spark的任务容错机制就是根据血统而来。
8、RDD的缓存机制
8.1 RDD的缓存是什么
可以把一个rdd的结果数据进行缓存,后续有其他的job需要依赖于前面rdd的结果数据,这个时候可以直接从缓存中获取得到,避免重复计算。
8.2 如何设置缓存
rdd中提供了设置缓存的2种方式

cache:默认是将数据缓存在内存中,其本质是调用persist方法
设置方式 : rdd.cache
persist:可以把数据缓存内存或者是磁盘中,它里面可以设置丰富的缓存级别,这些缓存级别都封装
在一个object 中,这个object的名称Storagelevel
设置方式 : rdd.persist(org.apache.spark.storage.StorageLevel)

以上这个2个方法并不是调用之后就立即执行,后续是需要一个action操作,才会触发缓存真正执行。
8.3 如何清除缓存
调用rdd的unpersist 清除缓存数据。

 手动清除缓存:rdd1.unpersist(true) 
 自动清除:对于程序来说,如果我们设置了缓存,后期程序结束了,它会自动清除
8.4 什么时候设置缓存
  • 1、一个rdd后期被使用了多次

    val rdd2=rdd1.flatMap(_.split(" "))
    val rdd3=rdd1.map(x=>(x,1))
    
    上面的rdd1被使用了多次,每一次使用都需要先把rdd1的结果数据先计算一下,这个时候就可以对rdd1设置缓存,避免后续的rdd需要前面的结果。
    
  • 2、某一个rdd的数据来之不易

    val rdd2=rdd1.flatMap(_.split(" ")).map().xxxxx.xxxxxxx.xxxxxxx.xxxxxxx.xxx.xxx
    
9、DAG有向无环图和划分stage
9.1 什么是DAG
DAG就是按照rdd的一系列操作最后生成了一个有方向无闭环的图,这个图我们就称为DAG有向无环图。按照操作逻辑划分成不同的stage(不同的调度阶段)

在这里插入图片描述

(1) 为什么要划分stage?

​ 在每一个stage中都是窄依赖 , 并没有宽依赖 , spark的任务task就是以分区为单位 , 这些task都是可以并行的运行 , 互不影响

(2) 如何划分stage? 划分stage的依据就是宽依赖

  1. 从最后一个rdd往前推 , 先创建一个stage , 然后把最后一个rdd加入到该stage中 , 它就是最后一个stage
  2. 如果遇到了窄依赖 , 就把该rdd加入到本stage中 , 如果遇到了宽依赖 , 就从宽依赖切开 , 最后一个stage也就结束了
  3. 重新创建一个新的stage , 按照第二步的操作 , 继续往前推 , 一直推到开始 , 整个划分stage也就结束了

(3) stage的内部逻辑

每一个stage中都有很多可以并行运行的task , 这些task被封装在一个taskSet集合中


扩展 : rdd与rdd之间有依赖关系 , stage与stage之间也有依赖关系 , 比如前面的stage中的task先运行 , 后面的stage中的task后运行 , 也就是说stage中输入数据是前面stage输出结果

后期开发好的代码中 , 一个action就是一个job , 一个application中包括了客户端的所有代码 , 也就是说一个application中很多个job , 一个job中会存在rdd的一系列操作 , 一个job会生成一个DAG有向无环图 , 一个job中有可能有多个宽依赖 , 按照宽依赖切分 , 这个时候也就意味着一个job中有很多个stage , 每一个stage内部都有很多可以并行跑的task

10、spark任务调度

在这里插入图片描述

(1)Driver会运行客户端main方法中的代码,代码就会构建SparkContext对象,在构建SparkContext对象中,会创建DAGScheduler和TaskScheduler,然后按照rdd一系列的操作生成DAG有向无环图。最后把DAG有向无环图提交给DAGScheduler。

(2)DAGScheduler拿到DAG有向无环图后,按照宽依赖进行stage的划分,这个时候会产生很多个stage,每一个stage中都有很多可以并行运行的task,把每一个stage中这些task封装在一个taskSet集合中,最后提交给TaskScheduler。

(3)TaskScheduler拿到taskSet集合后,依次遍历每一个task,最后提交给worker节点的exectuor进程中。task就以线程的方式运行在worker节点的executor进程中。
11、spark的容错机制之checkpoint
11.1 什么是checkpoint
对rdd设置缓存有2种方式:
(1)cache:默认是把数据缓存在内存中,后续操作起来速度比较快,但是由于进程或者是服务器挂掉了,这个时候内存中的数据肯定是丢失,也就是说cache不是非常安全,数据丢失的概率比较大。

(2)persist:有丰富的缓存级别,可以把数据缓存在磁盘中,然后需要用到该数据,可以进行磁盘io操作获取得到,这一点比cache速度会慢点,但是比cache安全点,这里同样也有数据丢失的可能性(磁盘损坏、系统管理员由于误操作把本地数据清除掉了)

checkpoint:它是提供了一个相对而言更加可靠的持久化数据的方式,它可以把rdd的数据写入到分布式文件系统(HDFS)去保存,利用了hdfs高可靠,多个副本机制最大程度保证数据不丢失。
11.2 如何使用checkpoint
  • 1、通过sparkContext对象设置checkpoint目录,用于保存rdd的数据
    • sc.setCheckpointDir("/ck2018")
  • 2、对需要持久化的rdd调用一个方法checkpoint方法
    • val rdd1=sc.textFile("/words.txt")
    • rdd1.checkpoint
  • 3、后续需要有个action操作,触发checkpoint的执行
    • rdd1.collect
11.3 cache/persist/checkpoint区别
cache和persist:
	这2个方法都可以将rdd的数据进行缓存,后续都要有一个action操作,才会触发缓存任务的执行,它不会改变rdd的血统。整个程序结束之后,这些缓存数据自己被清除了。
	
	
checkpoint:
	可以把数据持久化到hdfs上,这个时候先rdd.checkpoint操作,然后也需要一个action。
	一个action操作就是一个job,在这里首先它会执行action这个job,执行完成之后,它会开启一个新的job来执行checkpoint操作,也就是说在这里比cache和persist多了一个job。它会改变rdd的血统。
11.4 数据丢失之后的恢复顺序
1、首先看一写有没有设置cache,如果有,直接从cache获取得到					     
2、如果没有cache,看一下有没有做checkpoint,如果有就直接从checkpoint获取得到	    
3,如果没有checkpoint,利用血统这层关系来重新计算恢复得到。
12、spark的运行架构

在这里插入图片描述

  1.   构建Spark Application的运行环境(启动SparkContext),SparkContext向资源管理器(可以是Standalone、Mesos或YARN)注册并申请运行Executor资源;
    
  2.  资源管理器分配Executor资源并启动Executor,Executor运行情况将随着心跳发送到资源管理器上;
    
  3. SparkContext构建成DAG图,将DAG图分解成Stage,并把Taskset发送给Task Scheduler。Executor向SparkContext申请Task,Task Scheduler将Task发放给Executor运行同时SparkContext将应用程序代码发放给Executor。
    
  4. Task在Executor上运行,运行完毕释放所有资源。
    
13. Spark运行架构特点

Spark运行架构特点:

  • 每个Application获取专属的executor进程,该进程在Application期间一直驻留,并以多线程方式运行tasks。
  • Spark任务与资源管理器无关,只要能够获取executor进程,并能保持相互通信就可以了。
  • 提交SparkContext的Client应该靠近Worker节点(运行Executor的节点),最好是在同一个Rack里,因为Spark程序运行过程中SparkContext和Executor之间有大量的信息交换;如果想在远程集群中运行,最好使用RPC将SparkContext提交给集群,不要远离Worker运行SparkContext。
  • Task采用了数据本地性和推测执行的优化机制。
spark案例---实现ip地址查询 通过Spark实现ip地址查询 1.需求分析 ​ 在互联网中,我们经常会见到城市热点图这样的报表数据,例如在百度统计中,会统计今年的热门旅游城市、热门报考学校等,会将这样的信息显示在热点图中。 通过日志信息(运行商家或者网站自己生成)和城市ip段信息来判断用户的ip段,统计热点经纬度。 2.技术调研 因为我们的需求是完成一张报表信息,所以对程序的实时性没有要求,所以可以选择内存计算s... 阅读详情

相关推荐

用Spark Streaming实时计算海量用户UV

提出需求 实时统计业务系统(web,APP之类)的访问人数,即所谓UV,或者DAU指标. 这个需求怕是流计算最最最常见的需求了. 计算UV的关键点就在于去重,即同一个人访问两次是只计一个UV的.在离线计算中统计UV比较容易想到的方法就是用group或distinct机制来去重.但是在实时计算场景,还用group就不太科学了,一个是全量数据的group是比较费时的,第二个是全量数据的group...

Liam's Blog (AI & BigData) 5695

网站PV、UV以及查看方法

网站PV、UV以及查看方法 一、名词解释 PV:PV 是Page Views的缩写,即页面浏览量,用户每一次对网站中的每个网页访问均被记录一次。注意,访客每刷新一次页面,pv就增加一次。 UV:UV是Unique Visitor的缩写,即独立访客数。指访问某个站点的不同IP地址的人数。在同一天的00:00-24:00内,uv只记录第一次进入网站的具有独立IP的访问者, 在同一天内再次或多次...

weixin_33814685的博客 1575

【信息科学与工程学】计算机科学与自动化——第三百零四篇 高性能系统开发指南01

高并发:限流、熔断、降级高性能:红包拆分、多级缓存、大Key/热Key拆分、Pipeline、线程池、RocketMQ零丢失、幂等、分布式锁、集群缩容、分批入库海量数据处理:日志分表分片、跨表查询、冷热分层、大数据引擎服务器选型系统安全:网关安全、服务器安全、云存储安全、风控、监控、测试数据一致性:缓存与数据库一致性、大厂方案、蓝绿回滚、流量一致性、流程一致性项目与团队管理:流程问题、管理问题(风险、成本、人员、文档、培训)稳定性建设:上线三板斧、线上五步闭环、混沌工程、容量规划。

weixin_49199313的博客 249

Spark- 使用第三方依赖解析IP地址

使用 github上已有的开源项目1)git clone https://github.com/wzhe06/ipdatabase.git 2)编译下载的项目: mvn clean package- DskipTests 3)安装jar包到自己的 maven仓库   mvn install: install-file -Dfile=${编译的jar包路径}/target/ipdatabase...

weixin_34101229的博客 331

基于Hadoop的网站流量日志分析系统设计与实现

网站流量日志分析是大数据领域最常见的应用场景之一。面对海量Nginx/Apache日志,传统工具难以高效处理,而Hadoop生态提供了完整的解决方案:HDFS负责分布式存储原始日志,MapReduce实现清洗、解析与指标统计,YARN进行资源调度,Hive则支持辅助查询校验。通过合理设计分层架构与统计口径,可有效提取PV、UV、热门页面等运营指标,并利用Combiner、自定义Partitioner等手段优化数据倾斜与Shuffle性能。该技术路线不仅适用于课程设计与毕业设计,也是理解大数据离线批处理流程的

weixin_34341117的博客 397

DIY音频必备:手把手教你用AB类功放模块打造高保真桌面音响(含电路图)

本文详细指导如何利用AB类功放模块DIY高保真桌面音响,涵盖选型指南、核心元器件清单、电路搭建与焊接工艺,以及系统调试与音质优化技巧。AB类功放以其接近A类功放的音质和B类功放的效率,成为音频爱好者的理想选择,适合有一定电子基础的实践者。

weixin_42665725的博客 444

Spark_通过Spark实现ip地址查询

标题1.需求分析2.数据准备3.代码思路4.代码 1.需求分析 在互联网中,我们经常会见到城市热点图这样的报表数据,例如在百度统计中,会统计今年的热门旅游城市、热门报考学校等,会将这样的信息显示在热点图中。我们根据每个用户的IP地址,与我们的IP地址段进行比较,确认每个IP落在哪一个IP端内,获取经纬度,然后绘制热力图 我们需要通过日志信息(运行商或者网站自己生成)和城市ip段信息来判断用户的ip段,统计热点经纬度。 2.数据准备 ip日志信息: 在ip日志信息中,只需要关心ip这一个维度就可以了

weixin_44449054的博客 970

保姆级教程:在mmdetection中手动计算并可视化P、R、F1值(附完整代码)

本文提供了一份详细的mmdetection教程,指导开发者如何手动计算并可视化精确率(P)、召回率(R)和F1值。通过完整的代码示例和清晰的步骤说明,帮助用户深入理解目标检测模型的性能评估方法,特别适合需要精细分析模型表现的计算机视觉研究人员和工程师。

weixin_29038303的博客 400

spark通过ip计算IP所在省份,以及广播变量的使用

其中需要一个IP段对应的码表内容大体如下(已经上传到csdn,下载地址:点击跳转下载页面):1,3708713472,3708715007,"河南省","信阳市","联通","221.14.122.0","221.14.127.255" 2,3708649472,3708813311,"河南省",,"联通","221.13.128.0","221.15.255.255" 3,3720390656,3

allen的博客 1995

Unity中URP下的菲涅尔效果实现(个性化修改)

在上篇文章中,我们实现了 URP 下的菲涅尔基础效果,我们在这篇文章中,对其进行自定义化修改。

楠溪泽岸的博客 2063

有限元分析必看:如何用ANSYS检查关键区域的网格质量(附操作截图)

本文聚焦有限元分析中决定仿真精度的关键环节,详细讲解了如何利用ANSYS Workbench对关键区域进行网格质量检查与优化。文章提供了从思维转变、实战操作到指标解读的完整流程,强调通过命名选择、Worksheet过滤器等工具实现定向检查,并给出了针对结构分析的关键区域网格质量阈值建议,帮助工程师提升仿真结果的可靠性与效率。

weixin_29200741的博客 466

大数据平台笔试题复盘:从MapReduce到Spark的底层能力考察

在分布式系统成为数据基础设施底座的今天,理解MapReduce的执行流程、Spark的宽窄依赖与Stage划分、Kafka的消息投递语义,是每位大数据工程师的基本功。这些概念不仅决定了离线计算与实时计算的性能边界,也直接影响数据倾斜治理、任务调度稳定性和故障排查效率。无论是Hadoop生态的日常运维,还是大模型时代的数据管道设计,掌握分布式计算原理、消息队列机制与存储引擎特性,都是解决真实工程问题的关键。本文以一份典型的基础平台开发笔试卷为线索,梳理从框架原理到场景设计的核心考点,帮助准备校招或希望夯实底层

weixin_30920853的博客 369

运行codex时出现登录失败:failed to start login server: 以一种访问权限不允许的方式做了一个访问套接字的尝试。 (os error 10013) 解决方案

本文主要介绍了运行codex时出现登录失败:failed to start login server: 以一种访问权限不允许的方式做了一个访问套接字的尝试。 (os error 10013) 解决方案,希望能对使用xx的同学们有所帮助。 文章目录 1. 问题描述 2. 解决方案

weixin_43178406的博客 10万+

爱奇艺秋招大数据笔试题解析:从Java到Spark的考点与备考策略

大数据开发岗位的技术栈覆盖广泛,从Java基础到分布式计算引擎,再到数据仓库建模,每一个环节都直接影响着海量数据的处理效率。理解Hadoop生态中HDFS的存储原理、MapReduce的Shuffle机制,以及Kafka在日志采集链路中的可靠性保障,是构建扎实基本功的关键。数据倾斜作为分布式计算中的经典难题,其定位与优化思路更是笔试和面试中的高频考点。在实际业务场景中,从数据采集、离线计算到结果输出的端到端设计能力,往往能体现工程师的真实水平。本文以爱奇艺秋招大数据开发方向笔试题为切入点,系统梳理了Java

weixin_30820077的博客 407

YOLO11涨点优化:Loss魔改 | WIoU (Wise-IoU) v3版本全面替换,基于动态非单调聚焦机制,让模型更聪明地学习

YOLOv11目标检测中的WIoU v3损失函数改进 本文探讨了YOLOv11目标检测模型中CIoU损失函数的局限性,并提出了WIoU v3改进方案。关键发现包括: CIoU的缺陷:在低质量样本(小目标/遮挡目标)上过度惩罚,导致模型优化方向偏离,小目标AP往往比大目标低30%左右。 WIoU v3的创新: 动态非单调聚焦机制:根据样本"离群度"智能分配梯度 让模型重点优化中等质量样本,减少对低质量样本的无效关注 采用指数移动平均来自适应调整质量评判标准 实际效果:WIoU v3在保持大

2601_95807009的博客 422

半导体设备系列(2) 半导体设备与工厂控制仿真器Demo编写

基于C/S架构用C++编写半导体设备仿真器与工厂控制仿真器

追赶时代的博客 610

spark数据分析之ip归属地查询

前一段时间,在项目中,领导要求实时查看来自各个省份的ip访问的详情,根据这一需求,通过flume/logstack实时采集nginx的日志到生产到kafka,再通过spark实时消费分析保存到redis/mysql中,最后前端通过百度的echart图实时的显示出来。

tianjun2012的专栏 3097

【YoloV8改进策略】上采样改进|EUCB,轻量高效的上采样模块|即插即用

YOLOv8作为当前最先进的实时目标检测与实例分割模型之一,其在速度与精度之间取得了出色的平衡。然而,在资源受限的边缘设备或对实时性要求极高的应用场景中,YOLOv8的计算开销,尤其是在特征金字塔网络(FPN)和路径聚合网络(PAN)中用于特征融合的上采样操作,仍然是一个瓶颈。YOLOv8的颈部(Neck)结构中广泛使用nn.Upsample进行上采样,该操作虽然简单,但缺乏对特征内容的感知能力,且后续通常需要标准卷积来修复因插值带来的伪影,这增加了不必要的计算负担。

m0_47867638的博客 752

基于Spark下查询ip详细信息Demo

本demo全是模拟现实的案例 所需的数据源文件链接: https://pan.baidu.com/s/1dd4AeNv4SiEToE81P6PPfA 提取码: 4qqi  import java.io.{BufferedReader, FileInputStream, InputStreamReader} import scala.collection.mutable.ArrayBuffe...

小东升职记 436

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

spark scala 使用ip2region解析ip地址详细信息

需求场景如下: 现需要将ip地址解析并提取对应的省份信息 感谢xxh的推荐 开源 IP 地址定位库 ip2region ip2region 是准确率 99.9% 的 IP 地址定位库,0.0x毫秒级查询,数据库文件大小只有 2.7M,提供了 Java、PHP、C、Python、Node.js、Golang 的查询绑定和 Binary、B树、内存三种查询算法 下载地址: 码云 git 引入maven...

王天一的博客 1480

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

【大数据spark SQL项目实战】日志分析(三):ip地址解析

这里使用github上二叉树快速搜索IP地址数据库生成Jar包,通过scala调用解析IP 1、将Java项目下载下来打成Jar包,并将Jar包放入scala项目中 ipdatabase-1.0-SNAPSHOT.jar 2、编辑intall-ipdatabase.bat文件,将Jar包install到本地仓库 mvn install:install-file -Dfile=ipdatabase-1.0-SNAPSHOT.jar -DgroupId=com.ggstar -DartifactId=i

846

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Spark实现ip地址查询

文章目录需求分析技术调研创建mysql数据库表思路代码开发实现 需求分析 在互联网中,我们经常会见到城市热点图这样的报表数据,例如在百度统计中,会统计今年的热门旅游城市、热门报考学校等,会将这样的信息显示在热点图中。我们根据每个用户的IP地址,与我们的IP地址段进行比较,确认每个IP落在哪一个IP端内,获取经纬度,然后绘制热力图 因此,我们需要通过日志信息(运行商或者网站自己生成)和城市ip段信息来判断用户的ip段,统计热点经纬度。 技术调研 因为我们的需求是完成一张报表信息,所以对程序的实时性没有要求

WGS. 839

Spark Streaming实战对论坛网站动态行为pv,uv,注册人数,跳出率的多维度分析,实时统计每天pv,uv的sparkStreaming结合redis结果存入mysql供前端展示

论坛数据运行代码自动生成,该生成的数据会作为Producer的方式发送给Kafka,然后SparkStreaming程序会从Kafka中在线Pull到论坛或者网站的用户在线行为信息,进而进行多维度的在线分析 数据格式如下: date:日期,格式为yyyy-MM-dd timestamp:时间戳 userID:用户ID pageID:页面ID chanelID:板块的ID action:点击和注册 ...

qq_36864672的博客 1224
上一篇: sparkRDD函数详解
下一篇: 大数据实时阶段----【Spark03之dataFrame、dataSet、schema】
CoderBoom
博客等级 码龄8年 62粉丝 75原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值