Centos虚拟机部署CDH以及HDFS的操作

1、

第一步是要部署java环境和安装ssh,首先在根目录建两个文件夹software和app分别存放安装包和解压后的文件:
这里写图片描述

把安装好的jdk-8u161-linux-x64.tar和hadoop-2.6.0-cdh5.14.0.tar上传到software文件夹。然后把jdk解压到app目录下:
tar -zxvf jdk-8u161-linux-x64.tar.gz -C ~/app/
接着进入jdk的目录输入pwd得到jdk目录所在路径,并手动把这个路径复制到粘贴板(即/root/app/jdk1.8.0_161):
这里写图片描述
下一步是要配置jdk的环境变量,由于Linux下有多种方式配置环境变量,这里只是选择其中的一种方式:
这里写图片描述
该配置文件的原始设置如下:
这里写图片描述
加入jdk的环境变量设置后如下所示:
这里写图片描述
使用source命令使刚刚的配置文件立即生效:
这里写图片描述
然后就能测试一下jdk是否配置成功:
这里写图片描述
弄完JDK之后,接下来就是要安装ssh:

sudo yum install ssh

然后设置ssh免密登录:

ssh-keygen -t rsa

输入完之后一直按回车即可:
这里写图片描述
用ls -a可以看到隐藏的.ssh文件夹,然后复制一下id_rsa.pub文件,如下所示:
这里写图片描述
可以看一下拷贝后的文件的内容:
这里写图片描述
这时ssh已经配置成功,可以测试一下,输入
ssh hadoop1(这个是我的用户名),第一次还需要输入yes,然后输入exit退出一下,再输入一次ssh hadoop1,这时就已经能直接登录进去而不需要输入密码了:
这里写图片描述

2、

第二步就是安装hadoop的CDH版本(http://archive.cloudera.com/cdh5/cdh/5/),这里我安装的是hadoop-2.6.0-cdh5.14.0.tar.gz,注意要看一下CDH的版本和JDK的版本以及Linux系统的版本有什么对应的要求(https://www.cloudera.com/documentation/enterprise/release-notes/topics/rn_consolidated_pcm.html#pcm_jdk
解压包放在了software文件夹,同样是解压到app文件夹下:

tar -zxvf hadoop-2.6.0-cdh5.14.0.tar.gz -C ~/app/

解压完成后,要配置app/hadoop-2.6.0-cdh5.14.0/etc/hadoop/hadoop-env.sh:
这里写图片描述
修改该配置文件的JAVA_HOME即可,其它地方不用动:
这里写图片描述
然后配置另外两个配置文件:
这里写图片描述
其中core-site.xml里的fs.defaultFS配置了HDFS默认的文件系统的地址,其中9000端口是Hadoop1.x用的,在2.x中一般是8020,如下(hadoop000是计算机名):
这里写图片描述
特别注意:由于HDFS文件存储在临时文件夹中,而每次虚拟机重启后都会清除掉,所以要在core-site.xml中加一个设置项,value指定的文件夹可以自己新建,将会用来存储HDFS的文件:
这里写图片描述

hdfs-site.xml中的副本节点数调整为1(原本默认为3),因为这里是用单机的伪分布式:
这里写图片描述
我创建的用于存储临时文件的文件夹和两个配置文件具体如下所示:
①文件夹:
这里写图片描述
②core-site.xml(/root/app/hadoop-2.6.0-cdh5.14.0/etc/hadoop/core-site.xml):
这里写图片描述
③hdfs-site.xml(/root/app/hadoop-2.6.0-cdh5.14.0/etc/hadoop/hdfs-site.xml):
这里写图片描述

最后,同一路径下还有一个配置文件slaves用于设置datanode(现在是单机伪分布式,暂时用不到)

3、启动hdfs

配置好上述步骤后,可以开始启动执行。(参考:http://archive.cloudera.com/cdh5/cdh/5/hadoop/里面有一个single node setup:http://archive.cloudera.com/cdh5/cdh/5/hadoop/hadoop-project-dist/hadoop-common/SingleCluster.html

①格式化文件系统(仅第一次执行即可,不要重复执行,因为数据会清空):

bin/hdfs namenode -format

如下所示:
这里写图片描述
②开启 NameNode 进程和 DataNode 进程:

sbin/start-dfs.sh

如下所示:
这里写图片描述
输入完成后可以输入jps命令查看有哪些java进程从而检查节点是否启动成功:
这里写图片描述
同时有对应生成的日志:
这里写图片描述
这里写图片描述
除了用jps命令检查是否启动成功之外,还可以在本地浏览器上输入http://Hadoop1:50070(事先要修改hostname:http://blog.csdn.net/u014034934/article/details/72874927)或者http://192.168.197.129:50070查看:
这里写图片描述
若要停止则输入如下命令:
这里写图片描述

4、HDFS常用命令(hdfs shell)

参考:http://archive.cloudera.com/cdh5/cdh/5/hadoop/hadoop-project-dist/hadoop-hdfs/HDFSCommands.html
这里写图片描述
注意:为了更方便地使用Hadoop的bin目录下的命令,建议把它配置到环境变量中,然后就能直接在命令行输入bin目录里的命令,例如输入hdfs,就会显示所有hdfs命令的选择:
这里写图片描述
选择第一个dfs,即输入hdfs dfs会有进一步的提示:
这里写图片描述
为了使用这些指令,创建一个data文件夹用于存放被测试的文件:
这里写图片描述
在data文件夹新建一个hello.txt,里面输入一些内容然后保存退出。
查看当前路径是否有hdfs的文件:
这里写图片描述
一开始没有,这时把当前路径的hello.txt上传到hdfs(实际也是选择了当前路径)里,重新查看就会发现hdfs中有了刚刚的文件(hdfs dfs -put hello.txt / 从本地上传到hdfs中,也可以使用copyFromLocal)(hdfs dfs -ls / 查看hdfs的文件):
这里写图片描述
查看HDFS里文件的内容(hdfs dfs -text /hello.txt):
这里写图片描述
在HDFS中新建文件夹:

hdfs dfs -mkdir /test

在HDFS中递归新建文件夹:

hdfs dfs -mkdir -p /test/a/b

查看递归的文件和文件夹目录:

hdfs dfs -ls -R /

这里写图片描述

使用-copyFromLocal命令(即上传,上面另一种方式是用-put):

hdfs dfs -copyFromLocal hello.txt /test/a/b/h.txt

使用-cat查看内容(上面另一种方式是用-text查看内容):

hdfs dfs -cat /test/a/b/h.txt

从HDFS中拿取文件到本地(即下载):

hdfs dfs -get /test/a/b/h.txt

从HDFS删除文件:

hdfs dfs -rm /hello.txt

从HDFS删除文件夹,要用递归的方式:

hdfs dfs -rm -R /test

现在要测试一下HDFS的分块(Block)功能,先把一个大文件(400多M)上传到HDFS中:
这里写图片描述
然后浏览器输入http://192.168.197.129:50070,点击导航栏最右边的浏览文件系统:
这里写图片描述
显示的是HDFS中所有的文件和文件夹:
这里写图片描述
点击刚刚上传的那个400多M的文件,会发现文件被分成了多个Block,因为该文件超过了128M:
这里写图片描述

5、Java API操作HDFS文件

包含内容:
这里写图片描述
(1)首先在IDEA中新建一个Maven Project(勾选Create from …,并选择quick start)
这里写图片描述
项目初始结构如下(pom.xml中的JUnit版本可以改成4.10):
这里写图片描述
(2)在pom.xml中添加Hadoop的依赖
由于与CDH以及Hadoop的版本都有关系,先在centos系统中输入echo $HADOOP_HOME得到版本为hadoop-2.6.0-cdh5.14.0,然后为了在pom.xml中能统一管理这些版本,在properties中添加一个节点记录版本:

<hadoop.version>2.6.0-cdh5.14.0</hadoop.version>

然后添加如下依赖:

<dependency>
      <groupId>org.apache.hadoop</groupId>
      <artifactId>hadoop-client</artifactId>
      <version>${hadoop.version}</version>
</dependency>

第一次导入包会报错:Dependency ‘org.apache.hadoop:hadoop-client:2.6.0-cdh5.14.0’ not found,说明找不到这些包(因为默认的仓库是没有cdh的仓库的),我们要在pom.xml中定义一个新的仓库(id可以随便写,但url要正确):

<repositories>
    <repository>
      <id>cloudera</id>
      <url>https://repository.cloudera.com/artifactory/cloudera-repos</url>
    </repository>
</repositories>

重新导入包(第一次下载需要耗费较长的时间),这时就能解决上面的问题了。
(3)hadoop-client的包下载完后,进入下列选项选中Maven Projects视图
这里写图片描述
就能看到依赖的包等信息:
这里写图片描述
(4)下面开始编写单元测试来使用HDFS的Java API(可以删掉test/java下的原有的AppTest,新建测试类)

这里先列出几个编写测试过程中遇到的问题:

①使用FileSystem的copyFromLocalFile方法时,报错:rg.apache.hadoop.ipc.RemoteException(org.apache.hadoop.hdfs.server.namenode.SafeModeException): Cannot create file/hdfsapi/test/img.png. Name node is in safe mode.The reported blocks 7 has reached the threshold 0.9990 of total blocks 7. The number of live datanodes 1 has reached the minimum number 0. In safe mode extension. Safe mode will be turned off automatically in 13 seconds.
涉及到的知识点是:Hadoop安全模式的理解(参考:http://blog.csdn.net/michael_zhu_2004/article/details/8268728),即若要让hadoop强制退出安全模式(不建议):

$ hdfs dfsadmin -safemode leave

上述操作不建议,最好是等待(一般默认的延迟时间是30s,由dfs.safemode.extension指定)

②使用FileSystem的copyToLocalFile方法时,报错:java.lang.NullPointerException
解决方法(参考:http://blog.csdn.net/u014307117/article/details/44787639):调用方法改为

fileSystem.copyToLocalFile(false,hdfsPath, localPath,true);

对应的API是:

public void copyToLocalFile(boolean delSrc, Path src, Path dst, boolean useRawLocalFileSystem) throws IOException {
        Configuration conf = this.getConf();
        FileSystem local = null;
        if (useRawLocalFileSystem) {
            local = getLocal(conf).getRawFileSystem();
        } else {
            local = getLocal(conf);
        }

        FileUtil.copy(this, src, (FileSystem)local, dst, delSrc, conf);
    }

short replication = fileStatus.getReplication();

问题:我们已经在hdfs-site.xml中设置了副本系数为1,为什么上述代码得到的文件副本系数为3
原因:
如果是通过hdfs shell的方式put上去的,那么采用默认的副本系数为1;
而如果是java api上传上去的,在本地我们并没有手工设置副本系数,所以默认采用的是hadoop自己的副本系数。

下面是hdfs完整的Java API测试代码:

package com.jaxhin.hadoop.hdfs;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.util.Progressable;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URI;

/**
 * Hadoop HDFS Java API操作
 */
public class HDFSApp {

    private static final String HDFS_PATH = "hdfs://192.168.197.129:8020";

    FileSystem fileSystem = null;
    Configuration configuration = null;

    /**
     * 创建HDFS目录
     * @throws Exception
     */
    @Test
    public void mkdir() throws Exception{
        fileSystem.mkdirs(new Path("/hdfsapi/test"));
    }

    /**
     * 创建文件
     * @throws Exception
     */
    @Test
    public void create() throws Exception{
        FSDataOutputStream output = fileSystem.create(new Path("/hdfsapi/test/a.txt"));
        output.write("Hello Hadoop".getBytes());
        output.flush();
        output.close();
    }

    /**
     * 查看HDFS中文件的内容
     * @throws Exception
     */
    @Test
    public void cat() throws Exception{
        FSDataInputStream in = fileSystem.open(new Path("/hdfsapi/test/a.txt"));
        IOUtils.copyBytes(in, System.out, 1024);
        in.close();
    }

    /**
     * 重命名
     * @throws Exception
     */
    @Test
    public void rename() throws Exception{
        Path oldPath = new Path("/hdfsapi/test/a.txt");
        Path newPath = new Path("/hdfsapi/test/b.txt");
        fileSystem.rename(oldPath, newPath);
    }

    /**
     * (从本地系统,现在是win10)上传文件到HDFS
     * @throws Exception
     */
    @Test
    public void copyFromLocalFile() throws Exception{
        Path localPath = new Path("D:/code/img.png");
        Path hdfsPath = new Path("/hdfsapi/test");
        fileSystem.copyFromLocalFile(localPath, hdfsPath);
    }

    /**
     * (从本地系统,现在是win10)上传文件到HDFS,并带有进度条(适用于大文件上传)
     * @throws Exception
     */
    @Test
    public void copyFromLocalFileWithProgress() throws Exception{
        InputStream in = new BufferedInputStream(new FileInputStream(new File("D:/code/img.png")));
        FSDataOutputStream out = fileSystem.create(new Path("/hdfsapi/test/t.png"), new Progressable() {
            public void progress() {
                System.out.print(".");
            }
        });
        IOUtils.copyBytes(in, out, 32);
    }

    /**
     * 下载HDFS文件
     * @throws Exception
     */
    @Test
    public void copyToLocalFile() throws Exception{
        Path localPath = new Path("D:/code/hdfs-test.png");
        Path hdfsPath = new Path("/hdfsapi/test/img.png");
        fileSystem.copyToLocalFile(false, hdfsPath, localPath, true);
    }

    /**
     * 查看某个目录下的所有文件
     * @throws Exception
     */
    @Test
    public void listFiles() throws Exception{
        FileStatus[] fileStatuses = fileSystem.listStatus(new Path("/hdfsapi/test"));
        for (FileStatus fileStatus : fileStatuses){
            String isDir = fileStatus.isDirectory() ? "文件夹" : "文件";
            short replication = fileStatus.getReplication();
            long len = fileStatus.getLen();
            String path = fileStatus.getPath().toString();

            System.out.println(isDir+"\t"+replication+"\t"+len+"\t"+path);
        }
    }

    /**
     * 删除HDFS文件
     * @throws Exception
     */
    @Test
    public void delete() throws Exception{
        //fileSystem.delete(new Path("/hdfsapi/test/"));//方法过时
        fileSystem.delete(new Path("/hdfsapi/test/"), true);//后面的参数表示是否递归删除
    }

    @Before
    public void setUp() throws Exception{
        System.out.println("HDFSApp.setUp ...");

        configuration = new Configuration();
        fileSystem = FileSystem.get(new URI(HDFS_PATH), configuration, "root");

    }

    @After
    public void tearDown() throws Exception{
        configuration = null;
        fileSystem = null;

        System.out.println("HDFSApp.tearDown ...");
    }

}

6、HDFS文件读写流程详解

参考(有很多类似的漫画可以搜索):通过漫画轻松掌握HDFS工作原理:http://blog.chinaunix.net/uid-27105712-id-3274395.html

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值