HDFS实战

本文详细介绍了Hadoop HDFS的安装步骤,包括上传安装包、配置环境变量、分发到集群、初始化NameNode、启动服务、页面访问等。此外,还讲解了HDFS的Shell操作和Java程序操作,涵盖了文件系统的命令、上传下载文件、读写操作等核心功能。
摘要由CSDN通过智能技术生成

一、HDFS安装步骤

1、上传安装包到linux1

将安装包上传到/opt/apps/下

2、解压

tar -zxvf hadoop-3.1.1.tar.gz 

3、解压后的目录

[atguigu@hadoop102 hadoop-3.1.3]$ ll
总用量 52
drwxr-xr-x. 2 atguigu atguigu  4096 5月  22 2017 bin
drwxr-xr-x. 3 atguigu atguigu  4096 5月  22 2017 etc
drwxr-xr-x. 2 atguigu atguigu  4096 5月  22 2017 include
drwxr-xr-x. 3 atguigu atguigu  4096 5月  22 2017 lib
drwxr-xr-x. 2 atguigu atguigu  4096 5月  22 2017 libexec
-rw-r--r--. 1 atguigu atguigu 15429 5月  22 2017 LICENSE.txt
-rw-r--r--. 1 atguigu atguigu   101 5月  22 2017 NOTICE.txt
-rw-r--r--. 1 atguigu atguigu  1366 5月  22 2017 README.txt
drwxr-xr-x. 2 atguigu atguigu  4096 5月  22 2017 sbin
drwxr-xr-x. 4 atguigu atguigu  4096 5月  22 2017 share

重要目录

  • (1)bin目录:存放对Hadoop相关服务(hdfs,yarn,mapred)进行操作的脚本(普通的命令、客户端的指令)
  • (2)etc目录:Hadoop的配置文件目录,存放Hadoop的配置文件
  • (3)lib目录:存放Hadoop的本地库(对数据进行压缩解压缩功能)
  • (4)sbin目录:存放启动或停止Hadoop相关服务的脚本(超级命令)
  • (5)share目录:存放Hadoop的依赖jar包、文档、和官方案例

4、配置

配置文件均在hadoop安装目录下的etc/hadoop里

(1)在 hadoop-env.sh 中配置java环境变量

配置JAVA_HOME

vi hadoop-env.sh
export  JAVA_HOME=/opt/apps/jdk1.8.0_191

hadoop执行启动脚本时候会加载这个hadoop-env.sh,如果这里面配置了$JAVA_HOME会覆盖/etc/profile里面的$JAVA_HOME。启动脚本会先启动NameNode,然后再通过ssh启动slaves(也就是DataNode、NodeManager这些)。这时候需要去远程连接其他服务器,ssh过去的时候如果$JAVA_HOME配在/etc/profile,每次都得source一下。所以,Hadoop把$JAVA_HOME放在hadoop-env.sh里面,这样的话ssh远程执行的时候也不用source /etc/profile了。

(2)修改hdfs-site.xml

 <!-- 集群的namenode的位置  datanode能通过这个地址注册-->
	<property>
	     <name>dfs.namenode.rpc-address</name>
		 <value>linux1:8020</value>
	</property>
	 <!-- namenode存储元数据(数据存储的位置信息)的位置 -->
	<property>
	     <name>dfs.namenode.name.dir</name>
		 <value>/opt/hdpdata/name</value>
	</property>
	 <!-- datanode存储数据块的位置 -->
	<property>
	     <name>dfs.datanode.data.dir</name>
		 <value>/opt/hdpdata/data</value>
	</property>
	 <!-- secondary namenode机器的位置-->
	<property>
		<name>dfs.namenode.secondary.http-address</name>
		<value>linux2:50090</value>
	</property>

5、分发到集群的其他节点

scp -r hadoop-3.1.1 linux2:$PWD
scp -r hadoop-3.1.1 linux3:$PWD

开发一个远程复制的脚本

#!/bin/bash
for hostname in  doit02 doit03 
do 
scp -r  hadoop-3.1.1 $hostname:$PWD
done

(1)rsync远程同步工具

rsync主要用于备份和镜像。具有速度快、避免复制相同内容和支持符号链接的优点。

rsync和scp区别:用rsync做文件的复制要比scp的速度快,rsync只对差异文件做更新。scp是把所有文件都复制过去。

安装
在集群中每台服务器都执行如下命令:

yum install rsync -y

基本语法:
rsync -av 源文件路径/名称 目标主机:目标文件路径/名称
注意:这里必须写文件名称,因为它会对这两个文件名称内的文件进行对比复制,不会自己生成外部文件夹 。需要在两台服务器上都下载 rsync工具

选项:

  • -a:归档拷贝
  • -v:显示复制过程

初次分发用scp,之后修改了配置文件等可以用 rsync

rsync -av config.xml linux2:$PWD/config.xml

6、在linux1上初始化namenode

bin/hadoop namenode -format   

初始化以后会在配置的目录下生成文件夹

注意:只有在集群第一次启动时,才需要格式化NameNode。
格式化NameNode,会产生新的集群id,导致NameNode和DataNode的集群id不一致,集群找不到已往数据。如果集群在运行过程中报错,需要重新格式化NameNode的话,一定要先停止namenode和datanode进程,并且要删除所有机器的data和logs目录,然后再进行格式化。

7、单节点启动

sbin/hadoop-daemon.sh start namenode     # linux1
sbin/hadoop-daemon.sh start datanode     # linux1
sbin/hadoop-daemon.sh start datanode     # linux2
sbin/hadoop-daemon.sh start datanode     # linux3

可以使用jps命令查看java进程,linux1上的java进程如下:

[root@linux1 hadoop-3.1.1]#jps
5831 DataNode
6825 Jps
5659 NameNode

8、页面访问

访问 http://linux1:9870/ 可以进入到NameNode的web端管理页面

如果页面无法访问

  1. 查看namenode进程是否启动 jps
[root@linux1 logs]# netstat -nltp | grep 9870
tcp        0      0 0.0.0.0:9870            0.0.0.0:*               LISTEN      1889/java  
  1. 检查远程linux防火墙是否关闭
systemctl  status/stop/  disable firewalld 
  1. 在windows上ping linux的主机名 linux1
    若ping不到 ,查看本地的域名映射是否正确

9、日志

日志的默认路径是hadoop的安装目录
logs所在目录
如果启动有问题查看你的日志
日志文件

10、一键启停

(1)配置从节点的主机名到workers文件中

linux1
linux2
linux3

运行start-dfs.sh、stop-dfs.sh时会读取这个文件对各个从节点开启关闭
注意:该文件中添加的内容结尾不允许有空格,文件中不允许有空行。

(2)修改一键启停的命令脚本

sbin/start-dfs.sh 一键启动

sbin/stop-dfs.sh 一键停止

需要在这两个文件的第二行加上如下代码:

HDFS_DATANODE_USER=root 
HADOOP_SECURE_DN_USER=hdfs 
HDFS_NAMENODE_USER=root 
HDFS_SECONDARYNAMENODE_USER=root

添加原因:
在hadoop-env.sh文件中可以找到如下的描述

To prevent accidents, shell commands be (superficially) locked to only allow certain users to execute certain subcommands.

为了防止发生意外,仅(部分)锁定shell命令以仅允许某些用户执行某些子命令。

It uses the format of (command)_(subcommand)_USER.For example, to limit who can execute the namenode command,export HDFS_NAMENODE_USER=hdfs

使用“命令_子命令_用户”,例如,通过使用export HDFS_NAMENODE_USER=hdfs来限制哪个用户可以执行namenode命令。

11、添加系统环境变量

vi /etc/profile

export  JAVA_HOME=/opt/apps/jdk1.8.0_191
export  HADOOP_HOME=/opt/apps/hadoop-3.1.1
export  PATH=$PATH:$JAVA_HOME/bin:$HADOOP_HOME/bin:$HADOOP_HOME/sbin

source /etc/profile

注意:要将hadoop的bin与sbin都配置到环境变量中

二、HDFS的Shell操作(开发重点)

1、基本命令

使用命令hdfs dfs 会出现以下内容

[-appendToFile … ]追加一个文件到已经存在的文件末尾
[-cat [-ignoreCrc] …]显示文件内容
[-checksum …]
[-chgrp [-R] GROUP PATH…]Linux文件系统中的用法一样,修改文件所属权限
[-chmod [-R] <MODE[,MODE]… | OCTALMODE> PATH…]同上
[-chown [-R] [OWNER][:[GROUP]] PATH…]同上
[-copyFromLocal [-f] [-p] [-l] [-d] [-t ] … ]从本地文件系统中拷贝文件到HDFS路径去(上传)
[-copyToLocal [-f] [-p] [-ignoreCrc] [-crc] … ]从HDFS拷贝到本地(下载)
[-count [-q] [-h] [-v] [-t []] [-u] [-x] [-e] …]
[-cp [-f] [-p | -p[topax]] [-d] … ] 从HDFS的一个路径拷贝到HDFS的另一个路径
[-createSnapshot []]
[-deleteSnapshot ]
[-df [-h] [ …]]
[-du [-s] [-h] [-v] [-x] …] 统计文件夹的大小信息
[-expunge]
[-find … …]
[-get [-f] [-p] [-ignoreCrc] [-crc] … ] (下载)等同于copyToLocal,生产环境更习惯用get
[-getfacl [-R] ]
[-getfattr [-R] {-n name | -d} [-e en] ]
[-getmerge [-nl] [-skip-empty-file] ]
[-head ]
[-help [cmd …]]
[-ls [-C] [-d] [-h] [-q] [-R] [-t] [-S] [-r] [-u] [-e] [ …]] 显示目录信息
[-mkdir [-p] …] 创建文件夹
[-moveFromLocal … ] 从本地剪切粘贴到HDFS
[-moveToLocal ]
[-mv … ] 在HDFS目录中移动文件
[-put [-f] [-p] [-l] [-d] … ] 上传,等同于copyFromLocal,生产环境更习惯用put
[-renameSnapshot ]
[-rm [-f] [-r|-R] [-skipTrash] [-safely] …] 删除文件或文件夹
[-rmdir [–ignore-fail-on-non-empty]

…]
[-setfacl [-R] [{-b|-k} {-m|-x <acl_spec>} ]|[–set <acl_spec> ]]
[-setfattr {-n name [-v value] | -x name} ]
[-setrep [-R] [-w] …] 设置HDFS中文件的副本数量
[-stat [format] …]
[-tail [-f] ] 显示一个文件的末尾1kb的数据
[-test -[defsz] ]
[-text [-ignoreCrc] …]
[-touchz …]
[-truncate [-w] …]
[-usage [cmd …]]

-rm -r:递归删除目录及目录里面内容(与linux稍微不一样 ,没有 f)

-setrep:设置HDFS中文件的副本数量
hadoop fs -setrep 10 /jinguo/shuguo.txt
这里设置的副本数只是记录在NameNode的元数据中,是否真的会有这么多副本,还得看DataNode的数量。因为目前只有3台设备,最多也就3个副本,只有节点数的增加到10台时,副本数才能达到10

上传时设置参数

//上传a.txt,并指定块大小为1M
hdfs dfs -D dfs.blocksize=1048576 -put a.txt /a

-D 设置一些参数

2、默认操作本地文件系统

如果配置了系统环境变量 可以直接执行bin目录下的命令
hdfs dfs  运行文件系统的命令终端
hdfs dfs -ls /   查看目录/下的内容   ### 默认执行的是本地文件系统

此时执行hdfs dfs -ls / 会发现显示的目录信息是linux服务器的根目录

3、操作分布式文件系统

[root@linux1 bin]# hdfs dfs -mkdir hdfs://linux:8020/aaa
[root@linux1 bin]# hdfs dfs -ls hdfs://linux:8020/

hdfs dfs -text 命令可以查看压缩文件内容

4、修改默认操作的文件系统

每次都在命令后面加上 hdfs://linux:8020/ 有点太麻烦,所以我们需要修改配置,让它默认操作的就是hdfs文件系统

vi hadoop-3.1.1/etc/hadoop/core-site.xml

  <property>
     <name>fs.defaultFS</name>
     <value>hdfs://linix1:8020</value>
  </property>

以后操作的文件系统就是HDFS分布式文件系统

三、HDFS的JAVA程序操作

需要本地有hadoop的环境变量

1、添加依赖

 <dependencies>
    <dependency>
      <groupId>org.apache.hadoop</groupId>
      <artifactId>hadoop-common</artifactId>
      <version>3.0.3</version>
    </dependency>

    <dependency>
      <groupId>org.apache.hadoop</groupId>
      <artifactId>hadoop-hdfs</artifactId>
      <version>3.0.3</version>
    </dependency>

    <dependency>
      <groupId>org.apache.hadoop</groupId>
      <artifactId>hadoop-client</artifactId>
      <version>3.0.3</version>
    </dependency>
  </dependencies>

2、获取指定目录下的文件并打印

  public static void main(String[] args) throws Exception {
    //配置文件对象
    Configuration conf = new Configuration();

    //配置hdfs的默认访问地址
    // conf.set("dfs.defaultFS" , "hdfs://doit01:8020");

    // 设置数据存储的物理切块大小
    // conf.set("dfs.blocksize" ,"64M");

    //2 获取客户端连接对象
    /**
     * 参数一 确定HDFS的地址
     *  URI 统一资源标识符
     *   "jdbc:mysql://localhost:3306/db_doit26"
     *   "http://localhost:8080/exsample/mv.png"
     *   "hdfs://doit01:8020/"
     *   "file://E:word.txt"
     *     URL 统一资源定位
     *     URN 统一资源名称
     * 参数二 配置对象
     * 参数三 用户名
     */
    FileSystem fs = FileSystem.get(new URI("hdfs://linux1:8020"), conf, "root");
    // 3 操作API 实现对HDFS 的操作
    // 指定目录下的所有的内容 文件和文件夹
    FileStatus[] fileStatuses = fs.listStatus(new Path("/"));
    for (FileStatus fileStatus : fileStatuses) {
      System.out.println(fileStatus.getPath().getName());
    }
    //4 释放资源
    fs.close();
  }

2、获取文件元数据信息

 public static void main(String[] args) throws Exception {
    Configuration conf = new Configuration();
    FileSystem fs = FileSystem.get(new URI("hdfs://linux1:8020"), conf, "root");
    Path path = new Path("/");
    /**
     * 列出目录下的所有的文件
     *  参数一  路径
     *  参数二  是否递归遍历
     */
    RemoteIterator<LocatedFileStatus> iterator = fs.listFiles(path, true);
    // 遍历所有的文件
    while (iterator.hasNext()) {
      // 获取出当前的文件
      LocatedFileStatus next = iterator.next();
      //BlockLocation[] 数组中存储的是当前文件的所有的物理切块数据信息(一个文件分不同块存储)
      BlockLocation[] blockLocations = next.getBlockLocations();
      //当前文件名
      String name = next.getPath().getName();
      //当前文件路径
      Path path1 = next.getPath();
      //文件的副本个数
      short replication = next.getReplication();
      //数据的物理切块的大小
      long blockSize = next.getBlockSize();
      //遍历该文件的每个块
      for (BlockLocation blockLocation : blockLocations) {
        String[] cachedHosts = blockLocation.getCachedHosts();
        //
        String[] names = blockLocation.getNames();
        //数据块和他副本所在的主机节点(因为一个 block 块可能有多个副本,默认值是 3)
        String[] hosts = blockLocation.getHosts();
        //数据块的长度(实际占用的大小)
        long length = blockLocation.getLength();
        //每个物理切块的起始偏移量(假如一个文件被分为三块,则第一个块的起始偏移量为0,第二个块的起始偏移量为第一个块存储的字节数)
        long offset = blockLocation.getOffset();

        System.out.println(
            name + blockSize+"===" + path1 + "===" + Arrays.asList(cachedHosts) + "===" + Arrays.asList(names)
                + "===" + Arrays.asList(hosts) + "==="
                + length+"==="+offset);

      }
    }
    fs.close();
  }

此处有问题:数据块的长度是什么长度 names是什么

3、文件上传

  public static void main(String[] args) throws Exception{
    Configuration conf =new Configuration() ;
    FileSystem fs = FileSystem.get(new URI("hdfs://linux1:8020"), conf, "root");

    /**
     * 参数一:是否删除源文件
     * 参数二:是否覆盖目标文件
     * 参数三:本地 源文件路径
     * 参数四:HDFS 目标文件路径
     */
    //上传文件
    fs.copyFromLocalFile(true,true,new Path("D://a.txt"),new Path("/a"));
    fs.close();
  }

4、文件下载

 public static void main(String[] args) throws Exception {
    // 1 获取文件系统
    Configuration conf = new Configuration();
    FileSystem fs = FileSystem.get(new URI("hdfs://linux1:8020"), conf, "root");
    // 2 执行下载操作
    //参数一 boolean delSrc 指是否将原文件删除
    //参数二 Path src 指要下载的文件路径(HDFS文件)
    //参数三 Path dst 指将文件下载到的路径
    //参数四 boolean useRawLocalFileSystem 是否使用RawLocalFileSystem作为本地文件系统  默认是false  
    //RawLocalFileSystem不会校验和,所以改为true它不会在本地创建任何crc文件
    fs.copyToLocalFile(false, new Path("/a"), new Path("D://"));
    fs.close();
  }

需要注意的是,在往hdfs上上传数据时不需要hadoop环境变量,但是从hdfs下载文件到本地,需要本地有hadoop的环境变量

5、文件读取

  public static void main(String[] args) throws Exception {
    Configuration conf = new Configuration();
    FileSystem fs = FileSystem.get(new URI("hdfs://linux1:8020"), conf, "root");

    FSDataInputStream fin = fs.open(new Path("/a.txt"));
    //流定位,可以对任意字节位置进行重新定位,可以实现读完后再读一遍
    fin.seek(1);
    //跳过多少字节
    fin.skip(1) ;

    System.out.println(fin.read());

    BufferedReader br =new BufferedReader(new InputStreamReader(fin));
    String line=null;
    if((line=br.readLine())!=null){
      System.out.println(line);
    }
    br.close();
    fin.close();
    fs.close();
  }

注意代码中seek与skip的不同

6、文件写入

  /**
   * 在HDFS中的数据一般用于一次存储多次读取的使用场景
   *   一般不会对数据进行写操作
   *     1) 只能一个用户写
   *     2) 覆盖写      X
   *     3) 追加写
   */
  public static void main(String[] args) throws Exception {
    Configuration conf = new Configuration();
    FileSystem fs = FileSystem.get(new URI("hdfs://linux1:8020"), conf, "root");

    //读数据
    FSDataInputStream open = fs.open(new Path("/a/while.sh"));
    BufferedReader br =new BufferedReader(new InputStreamReader(open));

    //写数据
    //create方法默认覆盖写,可以设置第二个参数为false改为追加写
    FSDataOutputStream fos = fs.create(new Path("/a/c.txt"));
    //追加写
    //FSDataOutputStream fos2 = fs.append(new Path("/a/c.txt"));
    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(fos));

    String line=null;

    while((line=br.readLine())!=null){
      bw.write(line);
      bw.newLine();
    }
    bw.close();
    br.close();
    fos.close();
    fs.close();
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值