第五章:HDFS
一、操作HDFS
1、Web Console:端口50070
2、命令行:有两种类型
(1)普通操作命令: hdfs dfs ******
命令
-mkdir:在HDFS上创建目录
hdfs dfs -mkdir /aaa
hdfs dfs -mkdir -p /bbb/ccc
如果父目录不存在,使用-p参数先创建父目录
-ls 查看HDFS的某个目录
-ls -R 查看HDFS的某个目录,包含子目录
简写: -lsr
hdfs dfs -ls -R /bb
-put 上传数据
-copyFromLocal 上传数据
-moveFromLocal 上传数据,相当于ctrl+x(剪切)
-copyToLocal 下载数据
-get 下载数据
举例: hdfs dfs -get /input/data.txt .
-rm: 删除目录
-rmr: 删除目录,包括子目录
hdfs dfs -rmr /bbb
日志:
17/12/08 20:32:10 INFO fs.TrashPolicyDefault: Namenode trash configuration: Deletion interval = 0 minutes, Emptier interval = 0 minutes.
Deleted /bbb
-getmerge:把某个目录下的文件,合并后再下载
hdfs dfs -getmerge /student ~/allstudent.txt
-cp:拷贝 hdfs dfs -cp /input/data.txt /input/data2.txt
-mv:移动 hdfs dfs -mv /input/data.txt /aaa/a.txt
-count: 举例:hdfs dfs -count /students
-du: 类似-count,信息更详细
hdfs dfs -du /students
例子:
[root@bigdata11 ~]# hdfs dfs -count /students
1 2 29 /students
[root@bigdata11 ~]# hdfs dfs -ls /students
Found 2 items
-rw-r--r-- 1 root supergroup 19 2017-12-08 20:35 /students/student01.txt
-rw-r--r-- 1 root supergroup 10 2017-12-08 20:35 /students/student02.txt
[root@bigdata11 ~]# hdfs dfs -du /students
19 /students/student01.txt
10 /students/student02.txt
-text、-cat: 查看文本的内容
hdfs dfs -cat /input/data.txt
balancer:平衡操作
hdfs balancer
(2)管理命令:hdfs dfsadmin ******
-report: 打印HDFS的报告
举例:hdfs dfsadmin -report
-safemode:安全模式
hdfs dfsadmin -safemode
Usage: hdfs dfsadmin [-safemode enter | leave | get | wait]
enter 表示手动禁用安全模式
leave 表示手动退出安全模式
get 表示获取当前安全模式的状态
wait 等待安全模式执行完成
[root@bigdata11 ~]# hdfs dfsadmin -safemode get
Safe mode is OFF
[root@bigdata11 ~]# hdfs dfsadmin -safemode enter
Safe mode is ON
[root@bigdata11 ~]# hdfs dfs -mkdir /dddd
mkdir: Cannot create directory /dddd. Name node is in safe mode.
[root@bigdata11 ~]# hdfs dfsadmin -safemode leave
Safe mode is OFF
3、Java API
(1)创建一个目录:mkdir ----> 告诉:权限的问题
(2)上传数据、下载数据
(3)查询数据的元信息
依赖的jar包:
/root/training/hadoop-2.7.3/share/hadoop/common
/root/training/hadoop-2.7.3/share/hadoop/common/lib
/root/training/hadoop-2.7.3/share/hadoop/hdfs
/root/training/hadoop-2.7.3/share/hadoop/hdfs/lib
二、HDFS输出数据的原理(画图):比较重要(见另外一篇博客)
1、数据上传的原理(过程)
2、数据下载的原理(过程)
三、HDFS的高级特性
1、回收站 recyclebin
日志
-rmr: 删除目录,包括子目录
hdfs dfs -rmr /bbb
日志:
17/12/08 20:32:10 INFO fs.TrashPolicyDefault: Namenode trash configuration: Deletion interval = 0 minutes, Emptier interval = 0 minutes.
Deleted /bbb
(*)默认,HDFS的回收站是关闭
(*)启用回收站:参数---> core-site.xml
本质:删除数据的时候,实际是一个ctrl+x操作
<property>
<name>fs.trash.interval</name>
<value>1440</value>
</property>
由于修改了配置文件,所以需要重新启动hadoop。
日志:
hdfs dfs -rmr /folder1
rmr: DEPRECATED: Please use 'rm -r' instead.
17/12/11 21:05:57 INFO fs.TrashPolicyDefault: Namenode trash configuration: Deletion interval = 1440 minutes, Emptier interval = 0 minutes.
Moved: 'hdfs://bigdata11:9000/folder1' to trash at: hdfs://bigdata11:9000/user/root/.Trash/Current
(*)恢复:实际就是cp,拷贝
hdfs dfs -cp /user/root/.Trash/Current/input/data.txt /input
清空:hdfs dfs -expunge
(*)补充:Oracle数据库也有回收站
SQL> select * from tab;
TNAME TABTYPE CLUSTERID
------------------------------ ------- ----------
BIN$WBSNMvxJpWvgUAB/AQBygg==$0 TABLE
BONUS TABLE
DEPT TABLE
EMP TABLE
RESULT TABLE
SALGRADE TABLE
6 rows selected.
SQL> -- drop table mydemo1;
SQL> show recyclebin;
ORIGINAL NAME RECYCLEBIN NAME OBJECT TYPE DROP TIME
---------------- ------------------------------ ------------ -------------------
MYDEMO1 BIN$WBSNMvxJpWvgUAB/AQBygg==$0 TABLE 2017-09-01:06:56:15
SQL> select count(*) from mydemo1;
select count(*) from mydemo1
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> select count(*) from BIN$WBSNMvxJpWvgUAB/AQBygg==$0;
select count(*) from BIN$WBSNMvxJpWvgUAB/AQBygg==$0
*
ERROR at line 1:
ORA-00933: SQL command not properly ended
sql语句这样子写:
SQL> select count(*) from "BIN$WBSNMvxJpWvgUAB/AQBygg==$0";
COUNT(*)
----------
30
通过oracle的闪回技术恢复这张表。
SQL> flashback table mydemo1 to before drop;
Flashback complete.
SQL> show recyclebin;
SQL> select count(*) from mydemo1;
COUNT(*)
----------
30
2、快照snapshot:备份 ---> 一般来说:不建议使用快照
(*)默认:HDFS的快照是禁用的
(*)第一步:管理员开启某个目录的快照功能
[-allowSnapshot <snapshotDir>]
[-disallowSnapshot <snapshotDir>]
hdfs dfsadmin -allowSnapshot /mydir1
(*)第二步:使用HDFS的操作命令,创建快照
[-createSnapshot <snapshotDir> [<snapshotName>]]
[-deleteSnapshot <snapshotDir> <snapshotName>]
[-renameSnapshot <snapshotDir> <oldName> <newName>]
hdfs dfs -createSnapshot /mydir1 mydir1_backup_01
日志:Created snapshot /mydir1/.snapshot/mydir1_backup_01
本质:将数据拷贝一份到当前目录的一个隐藏目录下
(*)继续试验
hdfs dfs -put student02.txt /mydir1
hdfs dfs -createSnapshot /mydir1 mydir1_backup_02
对比快照: hdfs snapshotDiff /mydir1 mydir1_backup_01 mydir1_backup_02
Difference between snapshot mydir1_backup_01 and snapshot mydir1_backup_02 under directory /mydir1:
M .
+ ./student02.txt
3、配额quota:(1)名称配额: 规定某个目录下,存放文件(目录)的个数
实际的个数:N-1个
[-setQuota <quota> <dirname>...<dirname>]
[-clrQuota <dirname>...<dirname>]
hdfs dfs -mkdir /quota1
设置该目录的名称配额:3
hdfs dfsadmin -setQuota 3 /quota1
当我们放第三个文件的时候,会报错。
hdfs dfs -put data.txt /quota1
put: The NameSpace quota (directories and files) of directory /quota1 is exceeded: quota=3 file count=4
(2)空间配额: 规定某个目录下,文件的大小
[-setSpaceQuota <quota> [-storageType <storagetype>] <dirname>...<dirname>]
[-clrSpaceQuota [-storageType <storagetype>] <dirname>...<dirname>]
hdfs dfs -mkdir /quota2
设置该目录的空间配额是:10M
hdfs dfsadmin -setSpaceQuota 10M /quota2
正确的做法:hdfs dfsadmin -setSpaceQuota 130M /quota2
放一个小于10M的文件,会出错
Caused by: org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.hdfs.protocol.DSQuotaExceededException): The DiskSpace quota of /quota2 is exceeded: quota = 10485760 B = 10 MB but diskspace consumed = 134217728 B = 128 MB
注意:尽管数据不到128M,但是占用的数据块依然是128M
切记:当设置空间配额的时候,这个值不能小于128M
4、HDFS安全模式: safemode ---> HDFS只读
命令: hdfs dfsadmin -safemode get|wait|leave|enter
作用:检查数据块的副本率,如果副本率不满足要求,就会进行水平复制
5、HDFS的权限
chmod [R] mode file ...
6、HDFS的集群:开个头
集群的两大功能:负载均衡,高可用(失败迁移)
(1)NameNode联盟(Federation) ----> HDFS
(2)HA: HDFS、Yarn、HBase、Storm、Spark ---> 都需要ZooKeeper
四、HDFS底层的原理:Java程序
1、Java的动态代理
2、RPC:remote procedure call 远程过程调用
HDFS_WebConsole
HDFS_StartupProgress
HDFS的集群简介
package demo;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.junit.Test;
/*
* 使用HDFS的Java API创建一个目录
*
* 权限的问题:
* org.apache.hadoop.security.AccessControlException: Permission denied:
* user=lenovo, access=WRITE, inode="/folder1":root:supergroup:drwxr-xr-x
*
* 四种办法解决:
* 1、设置执行程序的用户是:root(HADOOP_USER_NAME)
* 2、使用Java的-D参数: HADOOP_USER_NAME
* 3、使用命令改变目录的权限:hdfs dfs -chmod 777 /folder2
* 4、参数:dfs.permissions ---> false(不进行权限检查,首先要把hadoop停下来,修改为false之后,需要重新启动hadoop)
*/
public class TestDemo1 {
@Test
public void test1() throws Exception{
//办法一:设置执行程序的用户是:root
System.setProperty("HADOOP_USER_NAME", "root");
//指定NameNode地址
Configuration conf = new Configuration();
//如果要使用主机名,需要配置Windows的host文件
//C:\Windows\System32\drivers\etc\hosts文件
conf.set("fs.defaultFS", "hdfs://bigdata11:9000");
/*
* 还有一种写法:IP地址
* conf.set("fs.defaultFS", "hdfs://192.168.157.11:9000");
*/
//创建一个HDFS的客户端
FileSystem client = FileSystem.get(conf);
//创建目录
client.mkdirs(new Path("/folder1"));
//关闭客户端
client.close();
}
@Test
public void test2() throws Exception{
//指定NameNode地址
Configuration conf = new Configuration();
//如果要使用主机名,需要配置Windows的host文件
//C:\Windows\System32\drivers\etc\hosts文件
conf.set("fs.defaultFS", "hdfs://bigdata11:9000");
/*
* 还有一种写法:IP地址
* conf.set("fs.defaultFS", "hdfs://192.168.157.11:9000");
*/
//创建一个HDFS的客户端
FileSystem client = FileSystem.get(conf);
//创建目录
client.mkdirs(new Path("/folder2"));
//关闭客户端
client.close();
}
@Test
public void test3() throws Exception{
//指定NameNode地址
Configuration conf = new Configuration();
//如果要使用主机名,需要配置Windows的host文件
//C:\Windows\System32\drivers\etc\hosts文件
conf.set("fs.defaultFS", "hdfs://bigdata11:9000");
/*
* 还有一种写法:IP地址
* conf.set("fs.defaultFS", "hdfs://192.168.157.11:9000");
*/
//创建一个HDFS的客户端
FileSystem client = FileSystem.get(conf);
//创建目录
client.mkdirs(new Path("/folder2/folder3"));
//关闭客户端
client.close();
}
@Test
public void test4() throws Exception{
//指定NameNode地址
Configuration conf = new Configuration();
//如果要使用主机名,需要配置Windows的host文件
//C:\Windows\System32\drivers\etc\hosts文件
conf.set("fs.defaultFS", "hdfs://bigdata11:9000");
/*
* 还有一种写法:IP地址
* conf.set("fs.defaultFS", "hdfs://192.168.157.11:9000");
*/
//创建一个HDFS的客户端
FileSystem client = FileSystem.get(conf);
//创建目录
client.mkdirs(new Path("/folder4"));
//关闭客户端
client.close();
}
}
java -D
//java -Dname=Tom -Dage=24 TestD
public class TestD{
public static void main(String[] args){
test1();
}
public static void test1(){
String name = System.getProperty("name");
String age = System.getProperty("age");
System.out.println(name+"\t"+age);
}
}
文件上传操作
package demo;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.junit.Test;
public class TestUpload {
@Test
public void testUpload1() throws Exception{
//指定NameNode地址
Configuration conf = new Configuration();
conf.set("fs.defaultFS", "hdfs://bigdata11:9000");
//创建一个HDFS的客户端
FileSystem client = FileSystem.get(conf);
//构造一个输出流,指向HDFS
OutputStream out = client.create(new Path("/folder1/a.tar.gz"));
//构造一个输入流,从本地文件读入数据
InputStream in = new FileInputStream("d:\\temp\\hadoop-2.7.3.tar.gz");
//下面是Java的基本IO
//缓冲区
byte[] buffer = new byte[1024];
//长度
int len = 0;
while((len=in.read(buffer)) > 0){
//表示读入了数据,再输出
out.write(buffer,0,len);
}
out.flush();
out.close();
in.close();
}
@Test
public void testUpload2() throws Exception{
//使用HDFS的工具类来简化程序
//指定NameNode地址
Configuration conf = new Configuration();
conf.set("fs.defaultFS", "hdfs://bigdata11:9000");
//创建一个HDFS的客户端
FileSystem client = FileSystem.get(conf);
//构造一个输出流,指向HDFS
OutputStream out = client.create(new Path("/folder1/b.tar.gz"));
//构造一个输入流,从本地文件读入数据
InputStream in = new FileInputStream("d:\\temp\\hadoop-2.7.3.tar.gz");
//使用HDFS的工具类来简化程序
IOUtils.copyBytes(in, out, 1024);
}
}
文件下载
package demo;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.junit.Test;
public class TestDownload {
@Test
public void testDownload() throws Exception{
//指定NameNode地址
Configuration conf = new Configuration();
conf.set("fs.defaultFS", "hdfs://bigdata11:9000");
//创建一个HDFS的客户端
FileSystem client = FileSystem.get(conf);
//从HDFS获取一个输入流
InputStream in = client.open(new Path("/folder1/a.tar.gz"));
//创建一个输出流,指向本地进行下载
OutputStream out = new FileOutputStream("d:\\temp\\aaa.tar.gz");
//下面是Java的基本IO
//缓冲区
byte[] buffer = new byte[1024];
//长度
int len = 0;
while((len=in.read(buffer)) > 0){
//表示读入了数据,再输出
out.write(buffer,0,len);
}
out.flush();
out.close();
in.close();
}
@Test
public void testDownload1() throws Exception{
//指定NameNode地址
Configuration conf = new Configuration();
conf.set("fs.defaultFS", "hdfs://bigdata11:9000");
//创建一个HDFS的客户端
FileSystem client = FileSystem.get(conf);
//从HDFS获取一个输入流
InputStream in = client.open(new Path("/folder1/a.tar.gz"));
//创建一个输出流,指向本地进行下载
OutputStream out = new FileOutputStream("d:\\temp\\bbb.tar.gz");
//使用HDFS的工具类来简化程序
IOUtils.copyBytes(in, out, 1024);
}
}
获取文件信息
package demo;
import java.util.Arrays;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.BlockLocation;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.junit.Test;
public class TestMetaData {
@Test
public void test1() throws Exception{
//获取HDFS的目录信息
//指定NameNode地址
Configuration conf = new Configuration();
conf.set("fs.defaultFS", "hdfs://bigdata11:9000");
//创建一个HDFS的客户端
FileSystem client = FileSystem.get(conf);
FileStatus[] fsList = client.listStatus(new Path("/folder1"));
for(FileStatus s: fsList){
System.out.println("文件还是目录?" + (s.isDirectory()?"目录":"文件"));
System.out.println(s.getPath().toString());
}
}
@Test
public void test2() throws Exception{
//获取文件的数据块信息
//指定NameNode地址
Configuration conf = new Configuration();
conf.set("fs.defaultFS", "hdfs://bigdata11:9000");
//创建一个HDFS的客户端
FileSystem client = FileSystem.get(conf);
//获取文件:/folder1/a.tar.gz数据块的信息
FileStatus fs = client.getFileStatus(new Path("/folder1/a.tar.gz"));
//通过文件的FileStatus获取相应的数据块信息
/*
* 0: 表示从头开始获取
* fs.getLen(): 表示文件的长度
* 返回值:数据块的数组
*/
BlockLocation[] blkLocations = client.getFileBlockLocations(fs, 0, fs.getLen());
for(BlockLocation b: blkLocations){
//数据块的主机信息: 数组,表示同一个数据块的多个副本(冗余)被 保存到了不同的主机上
System.out.println(Arrays.toString(b.getHosts()));
//获取的数据块的名称
System.out.println(Arrays.toString(b.getNames()));
}
client.close();
}
}