原创

Java操作HDFS、HDFS相关命令、Hadoop安全模式

温馨提示:
本文最后更新于 2017年07月18日,已超过 2,467 天没有更新。若文章内的图片失效(无法正常加载),请留言反馈或直接联系我

最近写的一个项目想集成Hadoop的HDFS文件系统,于是,我又去温习了一遍Hadoop。

环境

首先在windows环境下安装hadoop并配置环境变量。
windows下配置java jdk。
下载winutils:https://github.com/steveloughran/winutils
按照自己hadoop版本选择hadoop.dll winutils.exe放到hadoop bin目录下(Windows安装的Hadoop的bin目录)。

官方文档

http://hadoop.apache.org/docs/stable

举个栗子

package com.lzhpo.aurora.hadoop;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.fs.Path;
import org.junit.Before;
import org.junit.Test;

import java.io.*;
import java.net.URI;

/**
 * @Author:lzhpo
 * @Date:2019/6/20
 * @Description:
 *
 * HDFS的Java访问接口 
 *   1)org.apache.hadoop.fs.FileSystem
 *     是一个通用的文件系统API,提供了不同文件系统的统一访问方式。
 *   2)org.apache.hadoop.fs.Path
 *     是Hadoop文件系统中统一的文件或目录描述,类似于java.io.File对本地文件系统的文件或目录描述。
 *   3)org.apache.hadoop.conf.Configuration
 *     读取、解析配置文件(如core-site.xml/hdfs-default.xml/hdfs-site.xml等),或添加配置的工具类
 *   4)org.apache.hadoop.fs.FSDataOutputStream
 *     对Hadoop中数据输出流的统一封装
 *   5)org.apache.hadoop.fs.FSDataInputStream
 *     对Hadoop中数据输入流的统一封装
 *
 * FileSystem的API:https://hadoop.apache.org/docs/current/api/org/apache/hadoop/fs/FileSystem.html
 */
public class TestHDFS {

    private static String hdfsUrl = "hdfs://192.168.200.111:9000";

    private static Configuration conf;

    private static FileSystem fs;

    /**
     * 初始化连接HDFS
     * @throws Exception
     */
    @Before
    public void initConnection() throws Exception{
        conf = new Configuration();
        fs = FileSystem.get(URI.create(hdfsUrl), conf, "root"); //root为hadoop用户名称,我使用的是root用户
    }


    /**
     * 列出指定目录下的文件(不包含取出目录下的所有文件)
     * @throws Exception
     */
    @Test
    public void testListFIles() throws Exception {
        Path dst = new Path("/");
        FileStatus[] files = fs.listStatus(dst);
        System.out.println("================================================");
        for (FileStatus file : files) {
            System.out.println(file.getPath().toString());
        }
        System.out.println("================================================");
    }

    /**
     * 获取指定目录下的所有对象信息
     *
     * 格式:FileStatus{path=hdfs://192.168.200.111:9000/CodeTest; isDirectory=true; modification_time=1546875772083; access_time=0; owner=dr.who; group=supergroup; permission=rwxr-xr-x; isSymlink=false}
     * @throws Exception
     */
    @Test
    public void testListAll() throws Exception{
        FileStatus[] listStatus = fs.listStatus(new Path("/"));
        System.out.println("================================================");
        for (FileStatus fileStatus : listStatus){
            System.out.println(fileStatus);
        }
        System.out.println("================================================");
    }

    /**
     * 读取指定文件
     * 注意:
     *      它会判断你的这个是否是文件
     *      如果是文件夹:org.apache.hadoop.ipc.RemoteException: Path is not a file: /
     * @throws Exception
     */
    @Test
    public void testReadFile() throws Exception{
        /**
         * 乱码
         */
//        FSDataInputStream open = fs.open(new Path("/Aurora/test1.txt"));
//        IOUtils.copyBytes(open, System.out, conf ,true);
        /**
         * 不乱码
         */
//        FSDataInputStream fileInputStream = fs.open(new Path("/Aurora/test1.txt"));
        String filePath = "/test1/d.txt";
        FSDataInputStream fileInputStream = fs.open(new Path(filePath));
        InputStreamReader  inputStreamReader = new InputStreamReader(fileInputStream, "gbk"); //设置gbk格式,防止读取到中文乱码
        char[] chars = new char[1024];
        int len = inputStreamReader.read(chars);
        System.out.println("================================================");
        System.out.println(new String(chars,0,len)); //0,:开始读取位置,从0开始。 len:读取长度。
        System.out.println("================================================");
        fileInputStream.close();
        inputStreamReader.close();
    }


    /**
     * 创建一个文件夹
     * @throws Exception
     */
    @Test
    public void testHDFSMkdir() throws Exception {
        //一般url只认识http协议
        //URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());//保证url也认识hdfs协议,这样就可以解析HDFS_PATH了
        Path path = new Path("/test1");
        fs.mkdirs(path);
    }

    /**
     * 创建一个文件
     * @throws Exception
     */
    @Test
    public void testCreateFile() throws Exception {
        Path path = new Path("/test1/d.txt");
        FSDataOutputStream out = fs.create(path);
        out.write("会打篮球的程序猿!".getBytes("gbk"));
        out.close();
    }

    /**
     * 重命名
     * @throws Exception
     */
    @Test
    public void testRenameFile() throws Exception {
        Path path = new Path("/test1/b.txt");
        Path newPath = new Path("/test1/bb.txt");
        System.out.println(fs.rename(path, newPath)); //返回true为改名成功,false为失败。
    }

    /**
     * 上传文件
     * @throws Exception
     */
    @Test
    public void testUploadLocalFile() throws Exception {
        Path src = new Path("E:/picture/lzhpo.png");
        Path dst = new Path("/test1");
        fs.copyFromLocalFile(src, dst);
    }


    /**
     * 查找文件所在的数据块
     * @throws Exception
     */
    @Test
    public void testGetBlockInfo() throws Exception { // list block info of file
        Configuration conf = new Configuration();
        FileSystem fs = FileSystem.get(URI.create(hdfsUrl), conf);
        Path dst = new Path("/test1/lzhpo.png");
        FileStatus fileStatus = fs.getFileStatus(dst);
        BlockLocation[] blkloc = fs.getFileBlockLocations(fileStatus, 0, fileStatus.getLen()); // 查找文件所在数据块
        System.out.println("================================================");
        for (BlockLocation loc : blkloc) {
            for (int i = 0; i < loc.getHosts().length; i++)
                System.out.println(loc.getHosts()[i]);
        }
        System.out.println("================================================");
    }


    /**
     * 删除文件、文件夹
     * @throws Exception
     */
    @Test
    public void testRemoveFile () throws Exception {
        FileSystem fs = FileSystem.get(URI.create(hdfsUrl), new Configuration());
        fs.delete(new Path("/test2"), true);//是否递归删除
    }
}

HDFS相关操作命令

官方文档命令(2.9.2):http://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoop-hdfs/HDFSCommands.html

http://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoop-common/FileSystemShell.html

老版本(0.18):https://hadoop.apache.org/docs/r1.0.4/cn/hdfs_shell.html

FS Shell常用操作命令

调用文件系统(FS)Shell命令应使用 bin/hadoop fs 的形式。 所有的的FS shell命令使用URI路径作为参数。URI格式是scheme://authority/path。对HDFS文件系统,scheme是hdfs,对本地文件系统,scheme是file。其中scheme和authority参数都是可选的,如果未加指定,就会使用配置中指定的默认scheme。一个HDFS文件或目录比如/parent/child可以表示成hdfs://namenode:namenodeport/parent/child,或者更简单的/parent/child(假设你配置文件中的默认值是namenode:namenodeport)。大多数FS Shell命令的行为和对应的Unix Shell命令类似,不同之处会在下面介绍各命令使用详情时指出。出错信息会输出到stderr,其他信息输出到stdout

cat

查看HDFS的文件。

用法:hadoop fs -cat [-ignoreCrc] URI [URI ...]
参数:-ignore选项禁用校验和验证。
举个栗子:hadoop fs -cat /test1/c.txt

checksum

返回文件的校验和信息。

用法:hadoop fs -checksum URI
举个栗子:
[root@bigdata ~]# hadoop fs -checksum /test1/c.txt
/test1/c.txt    MD5-of-0MD5-of-512CRC32C    000002000000000000000000c76902108ba59943f44c5ae78847a17f

chmod

更改文件的权限。使用-R,通过目录结构递归更改。用户必须是文件的所有者,否则必须是超级用户。

用法:hadoop fs -chmod [-R] <MODE [,MODE] ... | OCTALMODE> URI [URI ...]

chown

更改文件的所有者。用户必须是超级用户。

用法:hadoop fs -chown [-R] [OWNER] [:[GROUP]] URI [URI]

cp

复制。

用法:hadoop fs -cp [-f] [-p | -p[topax]] URI [URI ...] <dest>
举个栗子:
[root@bigdata ~]# hadoop fs -cp /file/hdfs-site.xml /

get

将文件复制到本地文件系统。注意和cp区分。

用法:hadoop fs -get [-ignorecrc] [-crc] [-p] [-f] <src> <localdst>
举个栗子:
hadoop fs -get hdfs://nn.example.com/user/hadoop/file localfile

ls

列出文件。

举个栗子:
hadoop fs -ls /

lsr

递归列出文件。

举个栗子:
hadoop fs -lsr /

mkdir

创建文件夹。

举个栗子:
hadoop fs -mkdir -p /test2

还有很多,例如mv、rm....这些都是和Linux差不多的,就不一一列举了。

mv

移动文件。

举个栗子:
hadoop fs -mv /test1/a.txt /test2

rm

删除文件。

举个栗子:
# 递归删除文件夹
hadoop fs -rm -r /test1
# 删除文件
hadoop fs -rm /test1.txt

df

显示可用空间。

举个栗子:
[root@bigdata ~]# hadoop fs -df /
Filesystem                          Size      Used    Available  Use%
hdfs://192.168.200.111:9000  37558423552  21427215  27929939968    0%

选项:

  • 如果目标已存在,则-f选项将覆盖目标。
  • -p选项将保留文件属性[topx](时间戳,所有权,权限,ACL,XAttr)。如果指定了-p且没有arg,则保留时间戳,所有权和权限。如果指定了-pa,则还保留权限,因为ACL是一组超级权限。确定是否保留原始命名空间扩展属性与-p标志无关。

Hadoop管理员操作命令

命令

1、查看正在运行的 Job。

hadoop job -list

​ 2、关闭正在运行的 Job。

hadoop job -kill job_1432108212572_0001

​ 3、检查 HDFS 块状态,查看是否损坏。

hadoop fsck /

​ 4、检查 HDFS 块状态,并删除损坏的块。

hadoop fsck / -delete

​ 5、检查 HDFS 状态,包括 DataNode 信息。

hadoop dfsadmin -report

​ 6、Hadoop 进入安全模式。

hadoop dfsadmin -safemode enter

​ 7、Hadoop 离开安全模式。

hadoop dfsadmin -safemode leave

​ 8、平衡集群中的文件

sbin/start-balancer.sh

踩个我前几年的坑?

问题描述
Cannot create directory /Aurora. Name node is in safe mode. The reported blocks 117 needs additional 3 blocks to reach the threshold 0.9990 of total blocks 121. The number of live datanodes 1 has reached the minimum number 0. Safe mode will be turned off automatically once the thresholds have been reached. NamenodeHostName:bigdata
原因分析

开启了安全模式状态下是不能创建文件夹的。

由于系统断电,内存不足等原因导致dataNode丢失超过设置的丢失百分比,系统自动进入安全模式。

解决办法
1.执行命令退出安全模式:hdfs dfsadmin -safemode leave

2.执行健康检查
hdfs fsck / -files

3.删除损坏掉的block。
hdfs fsck / -delete

Hadoop安全模式

安全模式是HDFS所处的一种特殊状态,在这种状态下,文件系统只接受读数据请求,而不接受删除、修改等变更请求。在NameNode主节点启动时,HDFS首先进入安全模式,DataNode在启动的时候会向namenode汇报可用的block等状态,当整个系统达到安全标准时,HDFS自动离开安全模式。如果HDFS出于安全模式下,则文件block不能进行任何的副本复制操作,因此达到最小的副本数量要求是基于datanode启动时的状态来判定的,启动时不会再做任何复制(从而达到最小副本数量要求)。

本文目录