4、HDFS实战操作:Shell命令、Java API调用、文件上传下载与权限管理
好,咱们进入HDFS的实战环节。
说实话,很多初学者学Hadoop,理论知识背得滚瓜烂熟,一上手就懵了。为什么?因为没真正敲过命令,没写过一行API代码。今天我就带你把这些坑都踩一遍,你跟着我走一遍,以后自己搞大数据平台,心里就有底了。
4.1 HDFS Shell命令:你每天都会用的东西
先说说Shell命令。这是最基础的操作,也是我日常用得最多的。你想想看,平时查个文件、传个数据、删个目录,总不能每次都写Java代码吧?
HDFS的Shell命令,说白了就是一套模仿Linux文件系统的命令集。你如果熟悉Linux的ls、cp、mv、rm,那学这个基本没难度。只是前面要加个hdfs dfs -前缀。
4.1.1 常用命令速览
我列几个我每天必用的命令,你直接拿去用:
| 操作 | 命令示例 | 说明 |
|---|---|---|
| 查看目录 | hdfs dfs -ls /user |
列出HDFS根目录下/user的内容 |
| 创建目录 | hdfs dfs -mkdir -p /data/logs |
递归创建目录,和Linux的mkdir -p一样 |
| 上传文件 | hdfs dfs -put localfile.txt /data/ |
把本地文件上传到HDFS |
| 下载文件 | hdfs dfs -get /data/remotefile.txt ./ |
从HDFS下载到当前目录 |
| 查看文件内容 | hdfs dfs -cat /data/access.log |
直接打印文件内容,小文件用这个很方便 |
| 删除文件 | hdfs dfs -rm -r /data/old_dir |
递归删除,慎用! |
| 移动/重命名 | hdfs dfs -mv /data/a.txt /data/b.txt |
相当于Linux的mv |
hdfs dfs -ls -R 来递归查看整个目录树,排查数据分布时特别好用。另外,-du -h 可以看每个目录占了多少空间,做存储规划时离不开它。
4.1.2 文件上传下载的细节
上传下载看着简单,但坑不少。我一个个说。
上传文件:
-put:最常用,上传单个文件或目录。-copyFromLocal:和-put功能一样,但语义更明确——从本地复制到HDFS。-moveFromLocal:上传后删除本地文件。我一般不用,除非你确定本地不需要了。
下载文件:
-get:下载到本地。-copyToLocal:和-get一样,语义更明确。-getmerge:这个我特别喜欢。它能把HDFS上某个目录下的所有小文件合并成一个文件下载。比如你有一堆日志碎片,用这个命令一步到位。
避坑指南: 我曾经在生产环境上犯过一个低级错误——用 -put 上传了一个200GB的大文件,结果网络抖动导致上传失败,前功尽弃。后来我学乖了,上传大文件时一定用 -D dfs.client.block.write.replace-datanode-on-failure.policy=NEVER 这个参数,能避免很多网络问题导致的失败。
4.2 Java API调用:让程序替你干活
Shell命令适合人机交互,但真正的生产环境,谁天天手动敲命令?都是程序自动跑的。这时候就需要Java API了。
HDFS提供了完整的Java API,你可以在自己的Java项目里直接操作HDFS上的文件。说白了,就是把Shell命令变成代码里的方法调用。
4.2.1 环境准备
首先,你得在pom.xml里引入Hadoop客户端依赖:
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>3.3.4</version>
</dependency>
然后,写一个工具类,获取FileSystem对象。这是所有操作的入口:
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import java.net.URI;
public class HdfsUtil {
private static final String HDFS_URI = "hdfs://namenode:9000";
public static FileSystem getFileSystem() throws Exception {
Configuration conf = new Configuration();
// 设置副本数,我一般设3,生产环境也够用
conf.set("dfs.replication", "3");
return FileSystem.get(new URI(HDFS_URI), conf, "hadoop");
}
}
"hadoop" 是用户名。如果你用root或其他用户启动的HDFS,这里要对应上。不然你会遇到Permission denied,别问我怎么知道的……
4.2.2 核心操作代码
我直接给你几个最常用的代码片段,你复制就能用:
1. 创建目录
FileSystem fs = HdfsUtil.getFileSystem();
Path dir = new Path("/user/data");
if (!fs.exists(dir)) {
fs.mkdirs(dir);
System.out.println("目录创建成功");
}
fs.close();
2. 上传文件
FileSystem fs = HdfsUtil.getFileSystem();
Path localPath = new Path("C:/logs/app.log");
Path hdfsPath = new Path("/user/data/app.log");
fs.copyFromLocalFile(localPath, hdfsPath);
System.out.println("上传完成");
fs.close();
3. 下载文件
FileSystem fs = HdfsUtil.getFileSystem();
Path hdfsPath = new Path("/user/data/app.log");
Path localPath = new Path("./download/app.log");
fs.copyToLocalFile(hdfsPath, localPath);
System.out.println("下载完成");
fs.close();
4. 列出目录内容
FileSystem fs = HdfsUtil.getFileSystem();
Path dir = new Path("/user/data");
FileStatus[] statuses = fs.listStatus(dir);
for (FileStatus status : statuses) {
System.out.println(status.getPath().getName() +
" - 大小: " + status.getLen() + "字节");
}
fs.close();
fs.close()。我见过太多新手写代码不关连接,最后导致连接池爆满,整个集群都卡了。你可以用try-with-resources语法,自动关闭,省心。
4.3 权限管理:别让所有人都能删你的数据
说到权限管理,很多人觉得HDFS权限就是摆设。嗯,默认情况下确实有点松。但生产环境,你必须认真对待。
HDFS的权限模型和Linux很像,也是读(r)、写(w)、执行(x)三组权限,分别对应owner、group、others。
4.3.1 权限命令
Shell命令里操作权限很简单:
# 修改文件权限,和Linux的chmod一样
hdfs dfs -chmod 755 /user/data
# 修改文件所有者
hdfs dfs -chown hadoop:hadoop /user/data
# 修改文件所属组
hdfs dfs -chgrp supergroup /user/data
你可能会问:执行权限(x)对文件有什么用?
嗯,这里要注意。对于普通文件,执行权限没意义。但对于目录,执行权限决定了你能不能进入这个目录。说白了,如果你对一个目录没有x权限,就算你有r权限,你也ls不了里面的内容。
4.3.2 权限检查机制
HDFS的权限检查默认是开启的。但有个坑——它默认不检查客户端的身份。什么意思呢?
就是说,如果你在客户端执行hdfs dfs -ls,HDFS会相信你告诉它的用户名。如果你随便设个HADOOP_USER_NAME=hdfs,你就变成了超级用户。
export HADOOP_USER_NAME=root 把整个 /data 目录给删了。所以生产环境一定要开启Kerberos认证,不然权限管理就是个笑话。
4.3.3 ACL访问控制列表
如果你觉得传统的ugo权限不够灵活,HDFS还支持ACL。你可以给某个用户单独设置权限:
# 给user1添加读权限
hdfs dfs -setfacl -m user:user1:r /user/data
# 查看ACL
hdfs dfs -getfacl /user/data
# 移除ACL
hdfs dfs -setfacl -x user:user1 /user/data
这个功能我在多租户场景下用得很多。比如A团队和B团队共享一个目录,但A只能读,B能读写,用ACL就很好解决。
4.4 实战中的那些坑
最后,我总结几个我踩过的坑,你遇到了直接对照排查:
- 上传大文件超时: 检查
dfs.client.socket-timeout参数,默认60000ms,网络不好时建议调大到120000ms。 - 文件明明存在但读不到: 八成是权限问题。用
hdfs dfs -ls -d看看目录权限。 - Java API报错FileNotFoundException: 检查路径开头有没有
/。HDFS是绝对路径,少了斜杠就会找不到。 - 写入时提示空间不足: 用
hdfs dfsadmin -report看看各DataNode的磁盘使用情况,可能某个节点磁盘满了。
好了,HDFS实战操作就讲到这里。你把这些命令和代码都敲一遍,遇到问题再回来翻翻这部分内容。下一章我们讲MapReduce,那才是真正考验你大数据思维的时候。