一、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端管理页面
如果页面无法访问
- 查看namenode进程是否启动 jps
[root@linux1 logs]# netstat -nltp | grep 9870
tcp 0 0 0.0.0.0:9870 0.0.0.0:* LISTEN 1889/java
- 检查远程linux防火墙是否关闭
systemctl status/stop/ disable firewalld
- 在windows上ping linux的主机名 linux1
若ping不到 ,查看本地的域名映射是否正确
9、日志
日志的默认路径是hadoop的安装目录
如果启动有问题查看你的日志
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>}
[-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();
}