面试问题求解

昨天面试,考官问我部署Hadoop集群的时候都装了那些服务,当时有点蒙,说了zookeeper和datanode 和namenode,考官看我实在回答不出来就举例说hbase,这个服务具体指什么?他还问了一个问题,MR当中reduce的具体算法实现时怎么实现的,怎么返回值的,这个问题是不是就要去读代码了?浅显的理解reduce的逻辑都是自己写的,他指的具体算法是啥,我有点蒙蒙的。
已邀请:

fish - Hadooper

自己动手部署的这些你都忘记了么,不能白被机器折磨这么久啊...?
hdfs中的服务:namenode、datanode,如果启动了HA,还有zookeeper、journalnode
yarn中的服务有:resourcemanager、nodemanager
mapreduce的服务:historyserver
hbase的服务:master、regionserver、zookeeper(之前可能已经装过)
 
具体的reduce实现最好阅读源码做理解。
但最基本的,reduce侧做了shuffle/sort、merge这些操作,在对原理的理解中是应该掌握的。

fish - Hadooper

写package的问题,参考org.apache.hadoop.hdfs.server.datanode.BlockReceiver的receiveBlock和receivePacket方法。
 
receiveBlock代码片段如下:
{{{void receiveBlock(
...
while (receivePacket() >= 0) { /* Receive until the last packet */ }
...
}}}}receivePacket代码片段:
{{{private int receivePacket() throws IOException {
// read the next packet
packetReceiver.receiveNextPacket(in);
...

//First write the packet to the mirror:
if (mirrorOut != null && !mirrorError) {
try {
packetReceiver.mirrorPacketTo(mirrorOut);
mirrorOut.flush();
} catch (IOException e) {
handleMirrorOutError(e);
}
}

...
}
}}} 
从receivePacket实现中可以看到,每次取一个package,向下一级完成写之后,再取下一个package。

fish - Hadooper

hdfs读的时候,第一个block读完之后,由client获取新的DataNode地址再读取下一个block数据。
可参考DFSInputStream.java中的readWithStrategy方法。

fish - Hadooper

首先,mapreduce.job.split.metainfo.maxsize跟hdfs中的元数据没有关系。这个参数用于指定mapreduce任务提交的时候,提交到hdfs的split信息的最大值。(回忆一下mapreduce的提交过程,客户端除了将应用代码job.jar提交到hdfs之外,还会把如何对输入数据进行分割的split信息提交到hdfs,这个配置就是用于限定这个split信息文件的上限的。)
 
其次,150byte是对于namenode中对象大小的估计,这些对象用于hdfs中文件、目录、block的信息,因为在hdfs执行过程中,namenode需要把当前hdfs中都有哪些文件和目录,这些文件所对应的block都是什么,载入到namenode的内存当中。hdfs不是和存储小文件,是因为,当系统的文件都是小文件的时候,文件数、block数都会大增,namenode在把所有这些信息都load出来时,内存会扛不住。这个跟上面那个mapreduce.job.split.metainfo.maxsize没关系。

fish - Hadooper

hdfs读和写是两个不太相同的过程。
 
写的过程,是以package为单位,把数据发向第一个datanode,datanode以package为单位,向pipeline中下一级datanode写数据,这个package,是写pipeline过程中的单位。而block,是存储管理的最小单位。
 
读的过程,client获取datanode列表,挑选最近的一个发起读请求(不是像写那样pipeline进行),使用InputStream的方式进行读取。真正读处实现方法是,每次读时,先判断buffer中是否有之前读的数据,有就直接从buffer获取,没有时,从磁盘读取或者远端datanode读取(远端实际最终也是落到磁盘上)。可以参看org.apache.hadoop.hdfs.BlockReaderLocalLegacy的read方法了解读的过程。(BlockReaderLocalLegacy是shortcircuit打开之后的读操作使用的BlockReader,普通读设计到rpc通信,简单参考看这个就可以。)

fish - Hadooper

跟mapreduce.job.split.metainfo.maxsize相关的代码:
{{{public static final String SPLIT_METAINFO_MAXSIZE = "mapreduce.job.split.metainfo.maxsize";}}}{{{public static JobSplit.TaskSplitMetaInfo[] readSplitMetaInfo(
JobID jobId, FileSystem fs, Configuration conf, Path jobSubmitDir)
throws IOException {
long maxMetaInfoSize = conf.getLong(MRJobConfig.SPLIT_METAINFO_MAXSIZE,
MRJobConfig.DEFAULT_SPLIT_METAINFO_MAXSIZE);
Path metaSplitFile = JobSubmissionFiles.getJobSplitMetaFile(jobSubmitDir);
String jobSplitFile = JobSubmissionFiles.getJobSplitFile(jobSubmitDir).toString();
FileStatus fStatus = fs.getFileStatus(metaSplitFile);
if (maxMetaInfoSize > 0 && fStatus.getLen() > maxMetaInfoSize) {
throw new IOException("Split metadata size exceeded " +
maxMetaInfoSize +". Aborting job " + jobId);
}}}}fStatus.getLen()获取的,时splitMeta文件的大小,这个配置项实际限制的是这个文件的大小,与split的数量(也就是map数量)有关系(设置越大可以启动的map数肯定越大),但不是直接控制。
 
建议看网上评论的同时,看看代码吧。

要回复问题请先登录注册