Hadoop HDFS源码学习笔记(六)--fetchBlockByteRange

深入解析客户端如何从数据节点获取数据块的过程,包括连接建立、读取数据的细节及Block Reader对象的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

client端需要从datanode端读取数据,当顺序的读取block的时候,会调用到fetchBlockByteRange函数,该函数中,有一个死循环,在循环内部首先使用函数getBlockAt()获得最新的block的信息,然后选择要链接的datanode的信息得到DNAddrPair类型的对象,从该结构中得到DatanodeInfo以及datanode的InetSocketAddress,然后调用函数getBlockReader函数获得一个BlockReader类型的对象。

 getBlockReader函数分析:

 1、首先根据dnAddr判断是否在client端有跟该datanode的cache的连接,如果存在cache的连接,则会调用DFSClient的getLocalBlockReader函数来执行后续的操作,先不分析这类情况。

2、for循环,主要目的是允许retry连接,次数为3

循环中:

(1)根据dnAddr去一个SocketCache类型的变量中去取得cache的Socket

如果不能从socketCache中得到cache的Socket,则会使用DFSClient的socketFactory的createSocket函数创建一个新的socket,然后执行connect连接操作

(2)调用BlockReaderFactory的newBlockReader方法new一个BlockReader类型的对象,单步跟踪进去,发现又进行了一次封装,facoty类函数封装了RemoteBlockReader2的newBlockReader方法,在该方法内部,使用NetUtils的getOutputSream方法返回了一个(OutputStream)SocketOutputStream对象,利用该对象创建了一个BufferedOutputStream,然后利用该对象创建了一个DataOutputStream对象out,然后利用out创建了一个Sender对象,调用sender的readBlock方法。

Sender的readBlock方法,得到了一个OpReadBlockProto对象,并创建了该对象的header的PB的Message,然后调用自身的send函数,发送了一个ReanBlock类型的命令,在send函数中调用了DataOutputStream的Flush函数。

回到RemoteBlockReader2的newBlockReader方法:创建了一个SocketInputStream对象,然后利用该对象创建了一个DataInputStream类型的对象,之后创建了一系列的response,checksum的proto的message信息,创建的datachecksum对象,并对firstChunkOffset进行了验证检测。

然后调用RemoteBlockReader2的构造函数,创建了一个RemoteBlockReader2的对象,然后返回

(3)调用RemoteBlockReader2的readAll方法,该方法封装了BlockReaderUtil的readAll方法, readAll方法,则又循环读入,封装的是RemoteBlockReader2的read方法,在read方法内部,首先判断,一个java.nio.ByteBufer类型的curPacketBuf是否为null,或者(jana.nio.ByteBuffer类型的curDataSlice的remaining为0,且bytesNeededToFinish大于0)则会调用RemoteBlockReader2的readNextPacket()方法。在readNextPacket函数中调用了函数readPacketHeader方法,该方法最终会使用到ReadableByteChannel类型的RemoteBlockReader2的in成员变量来读取packet的header,并将读取过来的ByteBuffer类型的headerBuf中的packetheader字段放入到PacketHeader类型的成员变量curHeader中。

调用resetPacketBuffer函数,根据计算出来的checksumsLen和packetheader中的dataLen重设curPacketBuf以及curDataSlice的字段内容。调用readChannelFully函数从socket连接中读取数据到curPacketBuf中。然后根据用户请求的offset和得到的packetHeader中存储的该packet在block中的offset计算得到应该读取的position,然后利用该newPos对curDataSlice进行position设置。注意在radChannelFuly函数之后会根据curHeader存放的当前packet中的data的length来更新bytesNeededToFini。sh成员变量,直到该变量小于0才判定已经读完用户请求长度的数据,然后接受最后一个空包,然后发送给datanode一个readResult。

跳出到RemoteBlockReader2的read函数中,会发现首先需要判断当前的packet中的dataLen和用户请求的len的长度大小,得到小的一个值nRead,然后从curdataSlice数组中获得nRead长度的数据。然后就跳回到BlockReaderUtil的readAll函数中,该函数会根据当前的nRead值以及之前的累积读到的数据长度和用户请求的len来判定是否继续执行read操作。

至此就使用BlockReader读取了用户请求的数据,然后会关闭当前的BlockReader,并返回,到目前就完成的fecthBlockByteRange的函数操作,从之前的分析可以了解到,该函数执行的操作是根据block的元数据信息从一个datanode上读取block中的数据

现将在该追踪过程中画的序列图和相关类图附上,以便理清思路,源码就不贴了,因为这次用的是23的代码,本机上没有,是在台式机上追踪的,两台电脑没互通呵呵。





"C:\Program Files\Java\jdk-17\bin\java.exe" -Didea.launcher.port=54222 "-Didea.launcher.bin.path=D:\hadoop\IntelliJ IDEA Community Edition 2018.3.6\bin" -Dfile.encoding=UTF-8 -classpath "D:\hadoop\Hadoop\target\classes;D:\hadoop\hadoop-3.1.4\share\hadoop\client\hadoop-client-api-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\client\hadoop-client-runtime-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\client\hadoop-client-minicluster-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\common\hadoop-kms-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\common\hadoop-nfs-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\common\hadoop-common-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\common\hadoop-common-3.1.4-tests.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\hdfs\hadoop-hdfs-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\hdfs\hadoop-hdfs-nfs-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\hdfs\hadoop-hdfs-rbf-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\hdfs\hadoop-hdfs-3.1.4-tests.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\hdfs\hadoop-hdfs-client-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\hdfs\hadoop-hdfs-httpfs-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\hdfs\hadoop-hdfs-rbf-3.1.4-tests.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\hdfs\hadoop-hdfs-client-3.1.4-tests.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\hdfs\hadoop-hdfs-native-client-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\hdfs\hadoop-hdfs-native-client-3.1.4-tests.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\mapreduce\hadoop-mapreduce-examples-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\mapreduce\hadoop-mapreduce-client-hs-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\mapreduce\hadoop-mapreduce-client-app-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\mapreduce\hadoop-mapreduce-client-core-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\mapreduce\hadoop-mapreduce-client-common-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\mapreduce\hadoop-mapreduce-client-shuffle-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\mapreduce\hadoop-mapreduce-c
最新发布
05-07
<think>好的,我现在需要帮助用户解决Hadoop 3.1.4的启动命令配置问题,特别是关于JDK 17和IDEA Community Edition 2018.3.6的classpath路径分析。首先,我得回顾一下用户提供的引用内容和之前的问题。 用户提到了几个关键点:Hadoop运行配置问题、启动命令的构成,以及classpath路径分析。引用中提到了ClassNotFoundException,JAVA_HOME未设置的问题,还有修改hadoop-env.sh和yarn.application.classpath的配置。此外,用户还提到了完全分布式环境的搭建步骤,比如移动和解压安装包,配置workers文件和环境变量。 首先,ClassNotFoundException通常和类路径有关,可能是驱动类没找到,或者打包的jar文件没有正确包含所需的类。用户使用JDK 17,需要注意Hadoop版本是否兼容,因为Hadoop 3.1.4可能对JDK 17的支持有限,官方文档可能推荐的是JDK 8或11。这时候可能需要确认兼容性,或者调整JDK版本。 接下来是启动命令的配置。Hadoop启动通常通过start-dfs.sh和start-yarn.sh,这些脚本会读取Hadoop的配置文件,比如hadoop-env.sh,里面需要正确设置JAVA_HOME。用户提到使用JDK 17,所以必须确保hadoop-env.sh中的JAVA_HOME指向正确的JDK路径,例如export JAVA_HOME=/usr/lib/jvm/jdk-17。如果路径错误,会导致JAVA_HOME找不到,从而引发各种错误。 关于classpath,用户需要运行hadoop classpath命令获取路径,并将结果添加到yarn.application.classpath的配置中。这确保YARN能够找到所有的依赖库。同时,如果用户使用IDEA进行开发,需要确保项目中的classpath配置正确,包括Hadoop的库和JDK 17的版本。IDEA 2018.3.6可能较旧,可能需要检查是否支持JDK 17,或者是否需要升级插件。 另外,用户的环境变量配置在/etc/profile.d/my_env.sh中,需要确认Hadoop和JDK的路径是否正确设置,并且通过source命令使其生效。同时,workers文件中的节点名称是否正确,比如master、slave1、slave2是否与实际的主机名对应,SSH免密登录是否配置,这些都是启动分布式环境的关键步骤。 可能用户遇到的错误包括:ClassNotFoundException(类路径问题)、JAVA_HOME未设置(环境变量或配置文件错误)、或者节点通信问题(workers配置或SSH问题)。需要一步步检查这些方面,确认每个配置项的正确性。 最后,用户可能需要了解如何在IDEA中配置Hadoop项目,添加正确的依赖库,并设置运行参数,确保打包后的jar包含所有需要的类,并且Hadoop的classpath正确指向这些依赖。同时,考虑到JDK 17的新特性,比如模块化系统,可能需要调整Hadoop的启动脚本或依赖项,避免不兼容的问题。</think>### Hadoop 3.1.4 启动命令配置详解(JDK-17 + IDEA 2018.3.6) #### 一、核心配置项分析 1. **JAVA_HOME配置** 修改 `$HADOOP_HOME/etc/hadoop/hadoop-env.sh` 文件,明确指定JDK-17路径: ```bash export JAVA_HOME=/usr/lib/jvm/jdk-17 ``` 若未配置,会触发 `Error: JAVA_HOME is not set` 错误[^2]。 2. **Classpath动态获取** 运行 `hadoop classpath` 获取当前Hadoop类路径,输出结果需添加到 `yarn-site.xml` 的 `yarn.application.classpath` 配置项中: ```xml <property> <name>yarn.application.classpath</name> <value>/opt/module/hadoop-3.1.4/etc/hadoop:/opt/module/hadoop-3.1.4/share/hadoop/common/lib/*:...</value> </property> ``` 该路径包含Hadoop核心库和第三方依赖[^3]。 3. **IDEA项目配置要点** - 确保 `pom.xml` 中Hadoop依赖版本与集群版本一致(3.1.4) - 设置编译兼容性为JDK-17: ```xml <properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> </properties> ``` #### 二、典型启动命令结构 完整作业提交命令示例: ```bash hadoop jar your-job.jar com.example.MainClass \ -D mapreduce.job.queuename=default \ /input/path /output/path ``` - `hadoop jar`:Hadoop执行入口 - `-D` 参数:动态配置MapReduce参数 - 末尾参数:程序自定义输入输出路径 #### 三、JDK-17兼容性问题 需注意: 1. Hadoop 3.1.4 官方支持最高JDK11,使用JDK-17需重新编译Hadoop源码: ```bash mvn clean package -Pdist,native -DskipTests -Dmaven.javadoc.skip=true -Djava.version=17 ``` 2. 若出现 `UnsupportedClassVersionError`,需检查IDEA的编译输出目标版本设置 #### 四、调试技巧 1. **环境验证命令**: ```bash # 检查JAVA_HOME echo $JAVA_HOME # 验证Hadoop类路径 hadoop classpath ``` 2. **日志定位**: - NameNode日志:`$HADOOP_HOME/logs/hadoop-*-namenode-*.log` - YARN日志:通过 `yarn logs -applicationId <app_id>` 获取
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值