sparkRDD

来源:互联网 发布:ubuntu流量监控 编辑:程序博客网 时间:2024/05/16 18:42

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,然后启动相应的worker3、worker开始与master进行注册,把注册信息发送给master4、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:持久化到本地或者hdfsSpark速度快的原因:在不同操作中可以在内存中持久化或者缓存多个数据集(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个分区个tasktask的生成是依据stage,在stage中先划分pipeline(与分区个数相同),然后根据pipeline生成taskshuffle 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()  }}