Spark 为什么快
聊spark必须聊rdd, rdd 全英文 Resilient Distributed Datasets,搞懂这三个单词就完事了其实。
Resilient
能复原的,弹回的,有弹性的。谈谈spark的内存机制,spark的内存整体分外堆内内存和对外内存,而在内存的使用上又分为数据内存和运行内存,就是数据存储和程序运行。
堆内内存的管理并不完全依托与jvm,jvm对于所有的对象都要序列化为二进制字节流,本质上是就是将不连续的空间转换为连续的空间并且需要的空间也会小,相应的也就有反序列化。序列化的方式可以节省空间,但增加了读取时候计算的开销。spark的对象由于是字节流的形式,其占用的内存大小可直接计算,而对于非序列化的对象,其占用的内存是通过周期性地采样近似估算而得,即并不是每次新增的数据项都会计算一次占用的内存大小,这种方法降低了时间开销但是有可能误差较大。
因为堆内内存会有诸多限制,所以spark通过JDK Unsafe API实现堆外内存。Spark 可以直接操作系统堆外内存,减少了不必要的内存开销,以及频繁的 GC 扫描和回收,提升了处理性能。堆外内存可以被精确地申请和释放,而且序列化的数据占用的空间可以被精确计算,所以相比堆内内存来说降低了管理的难度,也降低了误差。
再说说数据内存和运行内存。spark用的是动态管理机制。数据内存和运行内存可以相互借对方的内存使用。当内存都不足的时候就只能落地到盘了。俗话说有借有还,他两却不一样,数据内存可以有借有还,而运行内存只能有借无还,因为运行内存存在很多复杂的逻辑,不能随意的释放掉。
Distributed 分布式
就指的是spark的partition,spark就是将一整块特别大的数据按照一定规则分到各个机器上,然后将代码也发送过去,每个分区执行完逻辑后,最后将结果汇总到一块就是最终的结果,数据的分发规则也是一个重点,有时会出现数据倾斜就是因为分发不均衡,如果大部分数据数据都在一个机器上计算,那分布式计算就没有什么意义了,所以在处理数据的时候要避免数据倾斜,数据倾斜也分为好多种,计算时候的倾斜,存储时候的倾斜等等,在这里就不细说了。
Datasets
spark的数据处理快还要得益于他数据的处理方式,就像下电影一样,一般先下下来在看,总没有一遍下一遍看快啊,也是他为什么称为pipeline处理方式。但是要注意的是,并不是每处理完一个rdd就交给这个下一个节点,一般是小批量的方式传递,这一般也是优化考虑的地方。
lineage
spark 的血缘关系也是一大亮点,每一个上面的rdd, 不管他经历了什么map, group等等,spark都会知道他的来龙去脉,当出现问题的时候,很容易根据血缘关系重新计算出数据。
因为spark通常处理数据少则几分钟多则几小时,将它的执行图比如一张蜘蛛网,如果某一个点断了,整张蜘蛛网都会收到牵扯,引起这个点断了的因素有很多,网络原因,机器原因等等。这个时候假如需要从头开始计算每个节点的数据,那就会特别的耗时间,但是只修复这一个点就能解决问题,不用在重新计算已经计算好的数据那效率肯定很高了,这就是spark自动容错自动恢复的优点,这些中间数据通过checkpoint来落到盘中以便后续的恢复。具体的血缘关系的划分,根据宽窄依赖划分等,就不细说了。
总结:
Spark比MapReduce更快的各种原因:
- 在处理过程中,Spark使用RAM存储中间数据,而MapReduce使用磁盘存储中间数据。
- Spark非常有效地使用底层硬件缓存。除了RAM外,Spark还能有效地使用L1、L2和L3缓存,这些缓存比RAM更接近CPU。
- Spark使用内部Catalyst Optimizer来优化查询物理和逻辑计划。
- Spark使用Predicate Pushdown。
- Spark拥有自己的垃圾收集机制,而不是在内置的JAVA垃圾收集器中使用。
- Spark使用其自己的字节码生成器,而不是内置的JAVA生成器。最终的字节码始终在JRE环境中执行。
- Spark使用RDD,Transformation和Action进行数据转换,而MapReduce不使用。
- Spark有自己的专用序列化器和反序列化器,使其更高效。