sparkRDD

RDD

RDD弹性分布式数据集,spark最基本的数据抽象,代表一个不可变,可分区,里面元素可并行计算的集合。
具有数据流模型的特点:自动容错,位置感知性调度和可伸缩性。
RDD允许用户在执行多个查询时,显示地将工作集缓存在内存中,后续的查询能重用工作集,这极大提高查询速度
特点:一系列的分区,每一个函数作用于每个分区,RDD之间是一系列依赖,如果是k-v类型的RDD,会有一个分区器,分区器就是决定把数据放到哪个分区

一般Worker需要和DataNode节点部署在一起,这样可以有效的避免大量网络IO
一个分区一定在一个节点上,一个节点可以有多个分区
RDD由多个分区组成的分布式数据集
一个block块对应一个分区

启动spark-shell

./spark-shell 
--master spark://hadoop01:7077  master地址
--executor-memory 512m    内存
--total-executor-cores 2    cpu核数

提交任务

./spark-submit
.
--class org.apache... 类名
--master spark://hadoop01:7077  master地址
--executor-memory 512m    内存
--total-executor-cores 2    cpu核数
jar包路径
args 其它参数(需要传才写)

spark集群的启动流程

1、首先启动master进程
2、master开始解析slaves配置文件,找到worker的host,然后启动相应的worker
3、worker开始与master进行注册,把注册信息发送给master
4、master收到注册信息后,把注册信息保存到内存与硬盘中,然后master给worker发送注册成功的信息(masterurl)
5、worker收到master的url信息,开始与master建立心跳

spark集群提交流程

1、driver 端 的sparksubmit 进程与master进行通信,创建一个重要的对象(sparkcontext)
2、master收到任务信息后,开始资源调度,和所有的worker进行通信,找到比较空闲的worker,并通知worker启动excutor进程
3、executor进程启动后,开始与driver(client) 进行通信(反向注册),driver开始将任务提交到相应的executor,executor开始计算任务

RDD和它依赖的父RDD的依赖关系,窄依赖narrow dependency,宽依赖wide dependency

主要说的是partition  分区
窄依赖:一父分区只能对应一子分区        分组后join
宽依赖:一父分区可以对应多子分区,宽依赖与shuffle密不可分  没分组join

Lineage

RDD转换为RDD(只支持粗粒度转换),将创建RDD的一系列Lineage(即血统)记录下来,以便恢复分区
Lineage会记录元数据信息和转换行为,当RDD部分分区数据丢失时,通过Lineage保存的信息来重新运算和恢复丢失的数据分区

一系列一对一关系(窄依赖),会形成一个Pipeline。可以通过父分区来再运行计算丢失分区的数据,其它的Pipeline不受影响 

Lineage在开发中不如cache 然后checkpoint(缓存放到hdfs)

丢失分区数据后找回数据顺序:cache(内存中找),checkpoint(hdfs中恢复),Lineage(从父分区再运行计算)

它与集群容错机制有点像。
集群容错机制:当一个节点(Worker)突然宕机,Master(重新调度任务)会将宕机的节点Worker未完成的数据交给其它节点。其它节点再在自己上面启动一个Worker,然后Worker启动Executor运行

RDD 缓存 checkpoint

cache:重要RDD的缓存起来,里面调用的是persist,默认是内存缓存(可以选择缓存级别)
checkpoint:持久化到本地或者hdfs
Spark速度快的原因:在不同操作中可以在内存中持久化或者缓存多个数据集(RDD),当持久化后,每个分区都把计算的数据分片保存在内存中,在此RDD或者之后的计算中可以重用,使后续动作更加迅速。缓存是spark构建迭代式算法和快速交互式查询的关键。

为什么要checkpoint?
运行处的中间结果,往往很重要,所以为了保证数据的安全性,要把数据做检查点
最好把checkpoint 到RDFS,便于该集群所有节点访问到
在checkpoint之前,最好先cache一下,就是先把数据缓存到内存,这样便于运行程序时调用,也便于checkpoint时直接重缓存中获取数据

什么时候做checkpoint?
在发生shuffle之后做checkpoint,(shuffle速度慢,项目中shuffle越少越好)
checkpoint的步骤?
1、创建checkpoint储存目录  sc.checkpointDir("hdfs://...")
2、把数据cache起来  rdd.cache()
3、checkpoint   rdd.checkpoint()
### 注意:当数据很大时,慎用cache,也不要不用,(关键地方,数据集不是非常大就用)

rdd.unpersist() 清除cache(cache的rdd调用unpersist())

DAG 有向无环图 stage

stage划分:找到最后的RDD,向前找,以宽依赖划分(宽依赖前的)为一个stage,整体划为一个stage,直到所有RDD划分完。(每个宽依赖划)
Stage:根据RDD之间的依赖关系的不同将DAG划分为不同的Stage,对于窄依赖,partition的转换处理在stage中完成计算,对于宽依赖,由于有shuffle的存在,只能在parentRDD中处理完成后才开始接下来的计算,因此宽依赖是划分stage的依据。
划分stage是为了把RDD来生成一个个task提交到Executor中执行,所以需要把RDD 先划分stage再生成task。

一个Stage 生成n个分区个task

task的生成是依据stage,在stage中先划分pipeline(与分区个数相同),然后根据pipeline生成task
shuffle read :发生在shuffle后,把父RDD 的数据读取到子RDD中
shuffle write: 把中间结果数据写到磁盘,为了保证数据安全性。
shuffle write 为什么不写内存里?
1、避免结果集太大而占用太多的内存资源,造成内存溢出
2、保存到磁盘可以保证数据的安全性

任务执行流程 4个阶段

RDD的生成  :  RDD 依赖关系,
stage的划分  : DAG 划分stage(在sparkcontext中 调用了 DAGScheduler(划分stage的))
任务的生成  :在sparkcontext中 调用了 TaskSetScheduler
任务的提交  :多节点提交
在sparkcontext中  调用 actorSystem,DAGScheduler,TaskSetScheduler详情看sparkcontext源码

yarn提交任务和spark提交任务的对比

resoucemanager 相当于master,负责任务调度,nodemanage相当于worker,负责创建容器和启动自己的子进程。
client端相当于driver,提交任务
yarnchild 相当于executor,直接参与计算进程

JdbcRDD RDD与mysql的交互

//这是向mysql中数据库 bigdata下的location_info表中查询数据
object JdbcRDD {
  def main(args: Array[String]): Unit = {
    val conf =new SparkConf().setAppName("jdbcRDD").setMaster("local[*]")
    val sc =new SparkContext(conf)
    val conn=()=>{
      Class.forName("com.mysql.jdbc.Driver").newInstance()
      DriverManager.getConnection("jdbc:mysql://192.168.216.53:3306/bigdata?useUnicode=true&characterEncoding=utf8","root","root")
    }
    val sql="select id,location,counts,access_date from location_info where id >= ? and id <= ? order by counts"
    val jdbcRDD =new JdbcRDD(
      sc,conn,sql,0,100,2,
      res=>{
        val id=res.getInt("id")
        val location =res.getString("location")
        val counts=res.getInt("counts")
        val access_date=res.getDate("access_date")
        (id,location,counts,access_date)
      }
    )
    println(jdbcRDD.collect().toBuffer)
    sc.stop()
  }
}

自定义排序 比较两个或多个字段时

第一种有隐式转换,第二种就直接继承

object Mysort {
  implicit val girlOrdering = new Ordering[Girl] {
    override def compare(x: Girl, y: Girl) = {
      if (x.faceValue != y.faceValue) {
        x.faceValue - y.faceValue
      } else {
        y.age - x.age
      }
    }
  }
}
//case class Girl(val faceValue: Int, val age: Int) {}//第一种
case class Girl(val faceValue: Int, val age: Int) extends Ordered[Girl] {
  override def compare(that: Girl) = {
    if (this.faceValue != that.faceValue) {
      this.faceValue - that.faceValue
    } else {
      this.age - that.age
    }
  }
}
object CustimSort {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("jdbcRDD").setMaster("local[*]")
    val sc = new SparkContext(conf)
    val girlInfo = sc.parallelize(Array(("a", 80, 25), ("b", 84, 24), ("c", 85, 26)))
    //第一种排序方式
    //    import Mysort.girlOrdering
    //    val res: RDD[(String, Int, Int)] = girlInfo.sortBy(x=>Girl(x._2,x._3),false)
    //第二种
    val res: RDD[(String, Int, Int)] = girlInfo.sortBy(x => Girl(x._2, x._3), false)
    println(res.collect().toBuffer)
    sc.stop()
  }
}

累加器 Accumulator

task 只能对accumulator进行累加

spark提供的accumulator,主要用于多个节点对一个变量进行共享操作。
它提供了多个task对一个变量并行的操作功能,task只能对Accumutor进行累加的操作,不能读取其值
只有driver才能读取。
/**
  * 累加器,就是累加操作
  */
object Accumulator {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("jdbcRDD").setMaster("local[*]")
    val sc = new SparkContext(conf)
    val sum: Accumulator[Int] = sc.accumulator(0)
    val numbers = sc.parallelize(Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 0), 2)
    numbers.foreach(num => {
      sum += num
    })
    println(sum)
    sc.stop()
  }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值