思考是一件有意思的事情遇到问题, 思考出结论, 那么脑子里面的过程是什么呢, 或者脑子里面是什么呢我一直认为, 这团团的里面是一个模糊的 n 维空间理解一个复杂的系统公式算法, 都要在这个 n 维空间里具象化这个具象化的镜像的精确度就代表了理解的深入度想起了, 考研的时候, 太用力, 每天晚上脑袋里镜像不断刷新的画面
最近一直在折腾 spark, 项目赶得飞快, 理解上的问题也一直在积压今天慢慢梳理, 突然发现脑袋里面的镜像构建的不对
spark 的 rdd 是分布式的存储在内存中的, 每个 stage 的边界是宽依赖导致的 shuffle, 连续的窄依赖 (如 map) 在一个 stage 中流水线的执行之前脑中的镜像是图左, 窄依赖不必依赖其他的 node, 一个 node 的分区窄依赖变换时不必依赖其他 node, 所以可以连续执行; 宽依赖需要其他 node 的数据, 所以只能 shuffle 了
在这种镜像下, 我自己很多困惑没有得到解答, 比如 2 个 rdd 的笛卡尔积为什么是窄依赖呢? 笛卡尔积是全连接, 需要所有 node 上的数据知乎上有个问题是问这个的, 有个答案竟然是 spark 后来的实现打破了自己论文中的设计有次面试一位多年 spark 经验的开发, 也是这样被误导了
重新构建一下, 如图右 RDD 只是一个抽象的概念, 分区也是抽象的, 并不会存储在内存中, 只有调用了 cache 等明确要求存储的函数时, RDD 的分区才会存储到内存变成 blockspark 运行时并不存在分区, 而是对分区进行计算的任务每个任务其实就是一段执行代码, 代码中的内容是就是这一个 stage 中的连续窄依赖变换, 如果图右中的 map 和 groupBy
那么为什么要把一个 job 通过宽依赖划分为不同的 stage 呢? 其实很像我们优化一段代码, 想提升速度, 自然的, 开多线程但如果这段代码中, 有一些过程需要依赖前面过程全部执行完才能正确运行这时, 我们切分这段代码为(a,b,c),c 依赖 b 执行完, b 依赖 a 执行完然后, 把这段代码划分为 3 个 stage, 每个 stage 分别多线程运行 a,b,c 3 块代码 a,b,c 内部的操作就是窄依赖, 可以并行的执行, a,b,c 的边界就是宽依赖, 需要前一个 stage 执行完才可以运行
这样想, 清晰了很多, 一个变换是不是窄依赖的决定性因素是: 每个分区任务是否可以独立并行的执行是的话, 就可以和其他相邻窄依赖一起合并成任务并行执行那我们看一下笛卡尔积的例子吧
如上图, 笛卡尔积是可以独立并行执行的, 拿到父 RDD(2 位)的 2 个分区 (m,n) 变换出 a 分区不需要依赖父 RDD 的其他分区
笛卡尔积也并有打破论文中的定义: 窄依赖是独生家庭, 父 RDD 的一个分区只会唯一生成子 RDD 的一个分区假设 RDD1(M 个分区)和 RDD2(N 个分区)笛卡尔积得到的子 RDD 有 M*N 个分区父 RDD 为 2 个 RDD, 他的一个分区为 (m,n) 唯一生成子 RDD 中的一个分区 a, 是独生子女, 符合政策, 不用罚款
持续构建中
来源: https://www.cnblogs.com/fanmingchun/p/8423238.html