Hadoop/HDFS常用命令&技巧

抽取自Linux开发常见命令和技巧 , 因为发现这只Hadoop大象/HDFS家族还是很有一些蛋疼的坑, 以及常用的地方的, 如果随便使用Linux命令替代, 很多时候得到的结果是有偏差/低效的.. 因为这毕竟是Hadoop自己实现的文件系统..

0x00.操作HDFS

总体来说命令格式是hadoop fs -xxx filePath1 filePath2 的形式为主, 区别主要是在本地文件HDFS文件的区别. 完整一点可以参考这篇. 注意HDFS非常不适合读写小文件(<10M), 建议应该是每个文件>256MB ,大量小文件的读写会大量占用RPC, 对整个HDFS集群都影响很大, 拷贝建议先归档为har

那我们这里把其中比较常用, 和容易混的说一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#有时候访问路径需要使用hadoop源文件地址.
hadoop fs -ls remotePath #访问非本机hadoop文件地址可能需要/path/to/hadoop绝对路径

#可以用于测试文件夹是否存储,要想看到输出结果可以执行完后`echo $?` ,成功0,否则1
hadoop fs -test -d filePath

#统计文件大小. 注意有些缩写命令提示已过时,就不推荐再合一起写了,但是du -sh不生效..
hadoop fs -dus -h filePath

#archive打包HDFS上的小文件,本质是起了一个MR作业 (注意: 打包只是合并, 没有任何压缩)
hadoop archive -archiveName filename.har -p hdfsInputPath hdfsOutputPath

#复制HDFS文件到本地机器. 相反的是put.类似的有copyToLocal?
hadoop fs -get hdfsPath localPath
hadoop fs -put localPath hdfsPath

0x01.写Map-Reduce作业

这里主要是千万要注意坑爹的不同Hadoop版本问题, 因为从0.x~3.x , 可能有很多的差异, jar包和使用的函数不要随便从网上复制粘贴模板 , 再就是建议本地先运行试试, 不要直接丢到服务器跑…

然后注意, 高版本客户端访问低版本的HDFS的时候, 很可能需要指定单独的classpath . 特别是如果修改过源码和相关API.. 不然直接访问肯定是报错的.

1. 访问低版本HDFS方式

一般把HDFS1.0 称为低版本HDFS, 和最新的HDFS3.0 相比, 它的访问接口可能发生了改变, 所以直接使用HDFS2.x 或3.x的包, 去调接口的时候就会报错, 或是提示找不到XXX映射, 在尽量不修改代码的原则下. 我们可以采用低版本的HDFS-client + classpath 拼接的方式去使用. 主要步骤如下:

  1. 部署一个HDFS1.x 的客户端, 不管修改过代码没, 要保证和你准备访问文件的HDFS是一个版本

  2. 修改/etc/bashrc , 引入hadoop的环境配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    vi /etc/bashrc
    #添加下面一行
    source /path/to/hadoop.bashrc #位置可以locate hadoop.bashrc先找找

    #改完应用
    source /etc/bashrc

    #然后测试是否能使用
    hadoop fs -ls /path/to/hdfs_test.txt
  3. 现在假设你的项目Maven中引入了比如hadoop-client-2.x.jar , 那么要做的就是用1.x的版本替换掉这个, 在启动的时候手动把classpath 拼接进去.

附:

这是hadoop.bashrc 内容, 仅供参考. 不同的路径自行修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
export HADOOP_PATH=/usr/bin/hadoop
export JAVA_HOME=$HADOOP_PATH/software/java/
export HADOOP_HOME=$HADOOP_PATH/software/hadoop/

export HADOOP_CLASSPATH=$HADOOP_CLASSPATH

export PATH=$JAVA_HOME/bin:$HADOOP_HOME/bin:$PATH:${HOME}/.local/bin
#嗯?
export PATH=$(echo $PATH | sed 's/:/\n/g' | sort | uniq | tr -s '\n' ':' | sed 's/:$//g')

export LANG="en_US.UTF-8"
export LC_ALL="en_US.UTF-8"
alias hls='hadoop fs -ls'
alias hdpfs='hadoop fs'
alias hdpls='hadoop fs -ls'
alias hcat='hadoop fs -cat'
alias hcopy='hadoop fs -copyToLocal'
alias hdfs='hadoop fs'
#what?
export PS1='[\u@\h \w]\$ '

#补充,如果使用时提示Unable to load native-hadoop library,可以考虑补充以下
export HADOOP_COMMON_LIB_NATIVE_DIR=$HADOOP_HOME/lib/native
export HADOOP_OPTS="-Djava.library.path=$HADOOP_HOME/lib:$HADOOP_COMMON_LIB_NATIVE_DIR"

然后如何手动加载1.x的hadoop包呢, 有两种常见方式:

  1. 通过hadoop classpath ,把输出的所有依赖包都附到你执行任务的classpath中

  2. 手动遍历, 然后拼接, 类似这样

    1
    2
    3
    4
    5
    #查询目录下所有jar包,然后去换行符,补':'号
    HADOOP_HOME="/path/to/hadoop0.x/" #或其他低版本绝对地址.
    CP="$CP:$(find -L $HADOOP_HOME -name "*.jar" | sort | tr '\n' ':')"
    CP="$CP:$HADOOP_HOME/conf/" # 不能带*,否则会识别不出,本质是为了加载conf里的映射文件spinnerViewFS.然后才能正确补充hdfs-path映射
    export JVM_OPTS="-cp $CP" #最后调用执行

然后为了避免冲突, 最好执行任务的时候去掉程序打包后lib/hadoop* 的jar包, 这样才能确定没有依赖错版本, 也避免提示native lib报错

0x0n.distcp和cp区别

HDFS内部. 文件的移动是最常见的事. 那么常见有几个选择. 不管是

首先要说明的是, ditscp本质是一个MR作业, 并且类似archive操作, 只有Map过程, 没有reduce

未完待续. hadoop这里也有不少小地方需要注意和一些高效的脚本去批量执行多个操作, 之后慢慢补上.