总是学了就忘记,spark都学了几遍了 总是深入不进去 唉 头疼 这里再次学习一遍 谁有更好的深入学习spark的方法给推荐推荐
面试了大数据,盘点几个被问到的问题:
spark一定会把中间结果放在内存吗?当然不是 可以是内存,也可以是磁盘
spark包括work和master work和master之间的沟通通过网络RPC进行交流沟通
拷贝到其他节点 for i in {5..7}; do scp -r /bigdata/spark/conf/spark-env.sh node-$i:$PWD; done
spark是移动计算,而不移动数据 因为大量数据移动成本大
spark是Scala 编写 spark包本身有Scala编译器和库 但spark是运行在jvm上的 需要安装jdk
利用zookeeper实现高可用集群 zookeeper用来1选举 2保存活跃的master信息 3 保存worker的资源信息和资源使用情况(为了故障切换转移) 在env.sh中添加export SPARK_DAEMON_JAVA_OPTS="-Dspark .deploy.recoveryMode=ZOOKEEPER xxxzookeeper相关信息" 高可用的spark需要手动启动另一个(standby)spark-master 并不会随着spark-all.sh 启动master
一直搞不懂spark进程之间的关系 下面来理一下:
提交任务的机器(Driver)(spark-submit提交jar包的那个) 有SparkSubmit进程,有CoarseGrainedExecutorBackend(这个是executor,即worker的哦哦用来执行任务的进程),Worker进程(worker机器所在) 任务执行完成后 Executor进程会释放 jps不在拥有Executor进程
在没有集群的时候 master会负责资源调度 保存worker资源情况 根据客户端submit要求分配资源,即master和worker进行rpc通信,然后worker进程启动executor(CoarseGrainedExecutorBackend),将分区参数传递过去
真正的计算逻辑是在driver端(submit端),生成task,然后通过网络发送给各个executor进行执行。executor启动后会主动连接driver,然后driver才开始生成task。两者之间的通信当然是通过master到worker进而知道的executor在哪里
yarn和spark的stondalone对比
resourcemanager 对应 Master 都用来管理子节点和资源调度,接收任务请求
nodeManager 对应 Worker 管理当前节点,并管理子进程
yarnchild 对应 executor 用来运行真正的计算逻辑
applicationMaster用来管理yarnchild,,决定map reduce运行在哪一个yarnchild
yarn还有client用来提交任务 这两个综合起来相当于spark的SparkSubmit (提交app,管理度任务的executor并将task提交到executor)
RDD是弹性分布式数据集,rdd并不存储真正的数据,只是一个抽象,对rdd操作,会在driver端转换成task,下发到executor计算分在多台集群上的数据
rdd是一个代理,对代理进行操作,会生成task帮助你计算,操作这个代理就像操作本地集合一样方便
RDD有分区,是通过内部进行指定 分区里面记录的是位置变量(以后要读取哪部分数据),生成的task交给executor,每个分区交给一个task去执行 ,然后task读取数据去执行相应的操作
aggregate方法,aggregate(0)(_+_ , _+_) 聚合操作,执行操作,每个分区分别执行,返回的顺序不一定有序
aggregateByKey(0)(_+_ , _+_) 每个分区局部相加 再全部相加 假如说原RDD(pairRdd)有两个分区,经过转换后变成shuffledEdd(也有两个分区,但分区内容是shuffle后的)
reduceByKey(_+_)
countByKey()
task在executor运算完成后,收集最终的数据到driver端 现在如果收集数据到redis mysql 或者hbase,那么不应该先collect收集数据到driver端,因为数据量过大,容易使得driver端崩溃
Rdd 的map方法,真正的在executor中执行的时候,是一条一条的将数据拿出来处理
foldByKey()
filter()
action:
rdd.collectAsMap()
foreach(e =>println(e*100)) 一条一条的拿(一条一条的执行function)
foreachPartition() 每个分区拿(一个分区执行一个function)
combineByKey(x=>x,(m:int,n:int)=>m+n, (a:Int,b:Int)=>a+b) (m+n 是分区聚合 a+b 是全局聚合,key 保持不变,对value操作,最后生成shuffledRdd)
Spark执行流程:
这个图虽然是到处都有 但真的很重要 理解他 记住他 spark基础就完全ok了
1构建DAG(所谓的DAG就是描述的一个个RDD的转换过程)(开始通过SparkContext创建RDD,结束调用runJob(也就是触发action)就是一个完整的DAG过程了)(有多少个DAG,取决于触发了多少次action)
2将DAG切分成stage(DAGSheduler)(切分的依据是shuffle),将stage中生成的Task以taskset的形式给TaskSheduler 将多台机器上具有相同属性的数据聚合到一台机器上:shuffle 如果有shuffle,那么就意味着前面阶段产生结果后,才能执行下一个阶段,下一个阶段要依赖上一个阶段的数据,在同一个stage中,会有多个算子,我们称其为pipeline
shuffle的含义:父RDD的一个分区中的数据如果给了子RDD中的多个分区(只要存在这种可能,例如款依赖时候如groupbyKey,他也有可能前一个步骤分区全部到下一个步骤的一个分区,但他可能分配到分多个分区,那么也是shuffle),就是shuffle
宽依赖(shuffle) 窄依赖
rdd1=sc.parallelize(List(("tom",1),("ketty",2),("tom",2))) 这个过程是把一个list shuffle到
不同分区的过程,所以也被分成一个stage
当然并不是所有的join都是宽依赖 如果前面的rdd数据比较规整 不需要shuffle到不同的分区 那么就是窄依
然后执行完第一个阶段后会执行第二个阶段的task,同样是driver端生产task 然后序列化,网络传输到executor端进行反序列化,然后封装成Runnable实现放到线程池进行处理
对RDD操作实际上是对分区进行操作 ,分区再生成task到executor执行操作