Spark(2)——spark RDD中的partition和hdfs中的block的关系
hadoop的文件系统hdfs是一款非常优秀的分布式文件系统。hdfs为主从架构,主节点叫NameNode,从节点叫DataNode。主节点负责配合journalNode等完成fsimge完整性,从节点负责存储数据。节点之间通信。。。好吧跑题了!
hdfs文件是分布式存储,每个文件根据配置被切分成block(hadoop2.x默认128M)。为了达到容错的目的,根据配置每个block块存放N个副本,官方推荐正常系统存3份就可以了(同一个机架存两份,另一个机架再存一份)。当然,如果你的系统个节点不太稳定可以适当调整个数。多副本机制除了能达到容错目的,也为计算本地行提供了便捷。当数据所在节点计算资源不充足时,多副本机制可以不用迁移数据,直接在另一个副本所在几点计算即可。小A同学提问:如果所有副本所在节点,计算资源都紧张怎么办?好吧,老师承认你这个问题很好,如果所有副本所在节点的计算资源都紧张,在yarn环境下,会根据配置等待一会。当等待时长超过计算时长,则会考虑将数据复制到其他计算资源空闲的节点上,优先本地节点(同一个机架上),如果本地无法找到合适的几点,再等待默认3s如何资源还没有空余出来,就会启动数据迁移(这个代价有点大)。当然如果是使用yarn的公平调度抢占式资源模式,会强制干掉不属于当前用户队列的进程以空出资源。好吧,又一次跑题了。。。如果同学们想了解资源调度请查看下下篇关于hadoop yarn资源调度的博客。小A同学又要提问了:老师什么时候会写关于hadoop yarn的资源调度?。。。。呃。。。。老师也不知道什么时候会写,看心情!!!!
那么spark中的RDD又是什么呢?RDD全名是弹性分布式数据集,弹性并不是动态扩展而是血统容错机制(这个机制在sparkStream某些情况会导致栈溢出),分布式顾名思义一个RDD会在多个节点上存储。一个RDD可以切分多个块(partition),不同的块可能在集群的不同节点上。在spark读取hdfs的场景下,spark把hdfs的block块读到内存就会抽象成spark的partition,就是折磨简单。对于后续的操作,遇到需要shuffle的操作RDD中的块可以按照HashPartitioner(默认)或者rangePartitioner再次进行进行划分,一般pairRdd是使用key做hash再取余(hashpartitioner)来划分partition的。当然coalesce(更小的数字,false)这种不需要shuffle也能改变RDD中的partition数目。
在spark的计算末尾一般需要把数据持久化,可以选择hive,hbase,hdfs等等。今天单独说持久化到hdfs,spark的RDD调用save()算子,RDD中数据就会被保存到hdfs,这个时候的对应关系比上面要复杂一些。RDD中的每个partition都会被保存成hdfs上的一个文件,如果此文件小于128M,那么相当于RDD中的一个partition对应一个hadoop的block块。如果,这个文件大于128M,那么这个文件会被切分成多个block块,这样一个spark中partition就会对应hdfs上的多个block。
鉴于第二种情况,每个partition中的数据大于128M时,在做sparkStream做增量数据累加时一定要记得调整RDD的并行度。比如,第一次保存时RDD时10个分区且每个分区150M。那么,这个RDD被保存到hdfs上就会变成20个bloc块。下一批次重新读取hfds上这个数据到spark时,RDD就会变成20。在后续的操作如果有union,或者其他操作,导致parition增加,但是程序中又没有repartition或者在reduceBykey或者...bykey的操作中传入并行度。就会导致这块数据parition一致无限期增加,这块增量计算也会被这块小失误击垮。所以,对于需要读取合并再回写,这样的引用,在程序开发结束一定要审查需不需要重新调整分区。