Job提交
下图展⽰示了driver program(假设在 master node 上运⾏行)如何⽣生成 job,并提交到 worker node 上执行。
当用户的 program 调用val sc = new SparkContext(sparkConf)
时,这个语句会帮助 program 启动诸多有关 driver 通信、job 执行的对象、线程、actor等,该语句确立了program的driver地位。
Task运行
下图展⽰示了 task 被分配到 worker node 上后的执⾏行流程及 driver 如何处理 task 的 result。
Executor 收到 serialized 的 task 后,先 deserialize 出正常的 task, 结果送driver那里。但是通过 Actor 发送的数据包不易过⼤大,如果result比较大(比如groupByKey的result)先把result存放到本地的“内存+磁盘”上,由blockManager来管理,只把存储位置信息(indirectResult)发送给driver,driver 需要实际的 result 的时候,会通过 HTTP 去 fetch。如果 result 不大(小于
spark.akka.frameSize=**10MB),那么直接发送给 driver。
Cache
- 问题:.用户怎么设定哪些RDD要cache?
因为⽤用户只与 driver program 打交道,因此只能用rdd.cache() 去cache 用户能看到的 RDD。所谓能看到指的是调用transformation() 后生成的 RDD,而某些在transformation() 中 Spark 自己生成的 RDD 是不能被⽤用户直接 cache 的,比如
reduceByKey() 中会生成的 ShuffledRDD、MapPartitionsRDD 是不能被⽤用户直接 cache 的。 - 问题:driver program 设定 rdd.cache()后,系统怎么对RDD 进行cache?
先不看实现,自己来想象一下如何完成 cache:当 task 计算得到 RDD 的某个 partition 的第一个record 后,就去判断该RDD 是否要被 cache,如果要被 cache 的话,将这个 record 及后续计算的到的records 直接丢给本地 blockManager 的memoryStore,如果 memoryStore 存不下就交给diskStore 存放到磁盘。 实际实现与设想的基本类似,区别在于:将要计算 RDD partition的时候(而不是已经计算得到第一个 record 的时候)就去判断 partition 要不要被 cache。如果要被 cache的话,先将 partition 计算出来,然后 cache 到内存。cache 只使用 memory,写磁盘的话那就叫checkpoint 了。
调用 rdd.cache() 后, rdd 就变成 persistRDD 了,其 StorageLevel为 MEMORY_ONLY。persistRDD 会告知 driver 说自己是需要被 persist 的。