配置伪分布模式下的hadoop以及采用fuse-dfs来访问HDFS
实验目标
配置环境的主要目的是得到HDFS的客户端fuse-dfs的IO性能。本来的服务器上没有任何环境,因此安装均是从无到有的。系统是Ubuntu server 14.04 amd64。整个过程参考了很多网上的博客,但是由于JAVA版本、hadoop版本、HDFS版本以及fuse-dfs版本的原因,网上各种解决方案在本机的运行上有点问题,需要进行一些变通才能保证各步骤的成功运行,所以写个随笔记录一下,方便自己以后参考。
整体步骤
完成测试的步骤包括如下步骤:
(1)安装JAVA环境:hadoop是基于java的,所以必须得安装java环境才能运行hadoop。
(2)下载hadoop源码:我下载的hadoop-2.8.5-src。这部分的源码其实我需要的只是fuse-dfs这一部分的代码。下载hadoop的二进制文件:由于其余的代码我并没有编译,所以我直接下载了同样版本的可执行二进制文件。
(3)编译fuse-dfs的代码。
(4)配置hadoop伪分布环境,单namenode与单datanode。
(5)挂载fuse-dfs,进行测试。
接下来进行步骤详解:
(1)(2)安装JAVA环境和hadoop的源码下载这部分就不详细描述了,网上大把教程,直接从第三部分开始。
(3)编译fuse-dfs的代码。
首先我们找到fuse-dfs的代码,他放在hadoop源码根目录下面的 hadoop-hdfs-project/hadoop-hdfs-native-client/src/main/native/fuse-dfs/下面。为了方便,我选择将这个文件夹拷出来单独编译。
首先我们将CMakeLists打开,将该文件最后的部分注释掉。(我已经注释掉了,原来的是没有前面的#号的)。
#add_executable(test_fuse_dfs # test/test_fuse_dfs.c # test/fuse_workload.c # util/posix_util.c #) #target_link_libraries(test_fuse_dfs # ${FUSE_LIBRARIES} # native_mini_dfs # ${JAVA_JVM_LIBRARY} # pthread #)
然后执行cmake,系统会生成自动化的makefile文件,然后执行make会产生很多报错,首先是缺乏头文件hdfs.h和config.h。hdfs.h可以在hadoop-2.8.5-src/hadoop-hdfs-project/hadoop-hdfs-native-client/src/main/native/libhdfs/include/hdfs中找到,而config.h则在hadoop-2.8.5-src/hadoop-hdfs-project/hadoop-hdfs-native-client/src 执行cmake即可生成。将config.h拷贝到fuse-dfs目录下,将hdfs.h拷贝到fuse-dfs/hdfs目录下。完成这两个操作之后,编译应该不会报错了,但是链接是会报错的:
一个是
Please add -D_FILE_OFFSET_BITS=64 to your compile flags!
针对这个错误,需要在fuse-dfs/CMakeFiles/fuse_dfs.dir/中的flags.make中增加一行。
C_FLAGS += -D_FILE_OFFSET_BITS=64
这个问题就可以解决了。然后是缺乏库的问题,需要将hadoop源码中的libhdfs.so拷入到/usr/lib中即可,编译连接就可以通过了。
(4)配置伪分布环境
这一部分的配置在hadoop-2.8.5的可执行文件目录完成。首先我们需要将hadoop-2.8.5/etc/hadoop/hadoop-env.sh文件中指定JAVA_HOME的一行修改为如下
export JAVA_HOME=/mnt/data/code/jdk1.8.0_191(根据自己的java_home目录自行替换)
然后进入etc/hadoop目录修改配置文件,首先修改core-site.xml,修改为如下即可,其中tmp目录根据自己的实际情况进行修改,如果不填这部分默认tmp目录为/tmp:
<configuration> <property> <name>fs.defaultFS</name> <value>hdfs://localhost:9000</value> </property> <property> <name>io.file.buffer.size</name> <value>131072</value> </property> <property> <name>hadoop.tmp.dir</name> <value>file:/mnt/data/code/hdfs/hadoop/tmp</value> <description>A basefor other temporary directories.</description> </property> <property> <name>hadoop.proxyuser.spark.hosts</name> <value>*</value> </property> <property> <name>hadoop.proxyuser.spark.groups</name> <value>*</value> </property> </configuration>
接下来修改hdfs-site.xml,分别指定namenode和datanode的位置以及副本数量。
<configuration> <property> <name>dfs.replication</name> <value>1</value> </property> <property> <name>dfs.namenode.name.dir</name> <value>file:/mnt/data/code/hdfs/hadoop/name</value> </property> <property> <name>dfs.datanode.data.dir</name> <value>file:/mnt/data/code/hdfs/hadoop/data</value> </property> <property> <name>dfs.webhdfs.enabled</name> <value>true</value> </property> </configuration>
这些都完成之后就可以运行HDFS了,,切换到hadoop的二进制文件目录hadoop-2.8.5,首先对namenode进行格式化
./bin/hdfs namenode -format
然后可以启动和停止hdfs,通过如下命令。
./sbin/start-dfs.sh ./sbin/stop-dfs.sh
执行启动命令后,可以通过jps命令查看是否在运行。准确结果如下:
root@opstor:/mnt/data/code/hadoop-2.8.5/sbin# jps 1986 Jps 31862 DataNode 31642 NameNode 32143 SecondaryNameNode
也可以通过网页端查看,http://localhost:50070查看。
(5)挂载fuse-dfs
这一步涉及到fuse代码中的C语言代码调用hdfs中用java实现的IO操作,所以需要将运行环境配置好才行,为此fuse-dfs也提供了fuse_dfs_wrapper.sh来保证这一点,但是由于hadoop的一些库的位置变化,这个文件需要进行调整才能保证fuse-dfs的成功挂载。
修改后的fuse_dfs_wrapper.sh文件如下,其中HADOOP_PREFIX根据自己的hadoop二进制可执行文件目录自行修改。
export HADOOP_PREFIX="/mnt/data/code/hadoop-2.8.5/share/hadoop" if [ "$HADOOP_PREFIX" = "" ]; then echo "HADOOP_PREFIX is empty. Set it to the root directory of Hadoop source code" exit 1 fi #export FUSEDFS_PATH="$HADOOP_PREFIX/hadoop-hdfs-project/hadoop-hdfs-native-client/target/main/native/fuse-dfs" #export LIBHDFS_PATH="$HADOOP_PREFIX/hadoop-hdfs-project/hadoop-hdfs-native-client/target/usr/local/lib" export FUSEDFS_PATH="/mnt/data/code/fuse-dfs" export LIBHDFS_PATH="/usr/lib" if [ "$OS_ARCH" = "" ]; then export OS_ARCH=amd64 fi if [ "$JAVA_HOME" = "" ]; then export JAVA_HOME=/usr/local/java fi if [ "$LD_LIBRARY_PATH" = "" ]; then export LD_LIBRARY_PATH=$JAVA_HOME/jre/lib/$OS_ARCH/server:/usr/local/lib fi while IFS= read -r -d '' file do export CLASSPATH=$CLASSPATH:$file done < <(find "$HADOOP_PREFIX/hdfs" -name "*.jar" -print0) while IFS= read -r -d '' file do export CLASSPATH=$CLASSPATH:$file done < <(find "$HADOOP_PREFIX/hdfs//lib" -name "*.jar" -print0) while IFS= read -r -d '' file do export CLASSPATH=$CLASSPATH:$file done < <(find "$HADOOP_PREFIX/tools" -name "*.jar" -print0) while IFS= read -r -d '' file do export CLASSPATH=$CLASSPATH:$file done < <(find "$HADOOP_PREFIX/tools/lib" -name "*.jar" -print0) while IFS= read -r -d '' file do export CLASSPATH=$CLASSPATH:$file done < <(find "$HADOOP_PREFIX/common" -name "*.jar" -print0) while IFS= read -r -d '' file do export CLASSPATH=$CLASSPATH:$file done < <(find "$HADOOP_PREFIX/common/lib" -name "*.jar" -print0) export CLASSPATH=$HADOOP_CONF_DIR:$CLASSPATH export PATH=$FUSEDFS_PATH:$PATH export LD_LIBRARY_PATH=$LIBHDFS_PATH:$JAVA_HOME/jre/lib/$OS_ARCH/server fuse_dfs "$@"
其实这个脚本的主要目的就是在挂载fuse-dfs之前保证java的库都能准确定位。修改完成之后即可采用进行fuse-dfs的挂载。后续测试即可顺利进行。
./fuse_dfs_wrapper.sh dfs://localhost:9000/ mnt/dfs