一、HDFS

  • HDFS:Hadoop Distribution File System
  • HDFS有三个部分:NameNode、DataNode、Secondary NameNode
  • 适合一次写入、多次读取、不支持文件修改的情况
  • 无法高效的对大量小文件进行存储
  • 不支持并发写入、文件随机修改,仅支持数据append
  • DataNode里面:文件不是整个存储的,是分成一个个block(块),默认一个block为128M

二、数据流

  • 分上传、下载两个部分,这是重点

  • 上传:

    1. 客户端(client)读取文件A(假设200M)

    2. client向NameNode申请

    3. NameNode审核后,同意申请client的请求

    4. client将200M的文件逻辑切分成128M和72M

    5. client输出流,请求NameNode上传第一个block
    6. NameNode返回DataNode的list,存储副本几个,list就有几个。这里有节点选择策略
    7. client依次向DataNode请求建立通道
    8. DataNode向client回复应答成功,注意这个通道是串联的
    9. client向DataNode传数据包,64KB一个
    10. 第一个block传完后,重复7~9,传第二个block。每次传block,返回的DataNode的list不一定相同。
    11. client向NameNode给信息,传输完毕
  • 下载:

    1. client向NameNode发起下载请求
    2. NameNode告诉client文件是否存在
    3. client向NameNode请求下载block
    4. NameNode向client返回DataNode的list
    5. client向DataNode请求建立通道
    6. DataNode向client回复应答成功
    7. DataNode向client传输block
    8. client向NameNode请求下载第二个block
  • 网络拓扑-节点距离计算

    • HDFS上传时,NameNode自动选择距离上传数据最近的DataNode

三、shell工具

1
2
3
4
5
hadoop fs -put xxxxxx
# 或者
hdfs dfs -put xxxxx
# 注意hadoop fs是一个脚本函数,fs执行org.apache.hadoop.fs.FsShell
# hdfs dfs也是dfs执行org.apache.hadoop.fs.FsShell
  • Hadoop fs 命令分类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
本地 ->> HDFS
put # 上传:hadoop fs -put xxx /存储目录
copyFromLocal # 和put是一样的
moveFromLocal # 剪切,put是复制
appendToFile # hadoop fs -appendToFile xxx /存储目录文件
HDFS ->> HDFS
cp
mv
chown
chgrp
chmod
mkdir
du # 查看文件夹
df # 查看硬盘情况
cat
rm
HFDS ->> 本地
get # hadoop fs -get /存储目录 ./
getmerge
copyToLocal # 和get一摸一样

四、客户端操作

  • maven:管理jar、项目的工具。我们往项目里导入依赖,可能会出现jar包冲突。

  • 要写API,大致如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
public class HDFSClient{

private Filesystem fs;
@Before
public void before() throws IOException, InterruptedException{
// 获取文件系统
fs = Filesystem.get(
URI.create("hdfs://hadoop104:9000"),
new Configuration(),
user:"ysp");
System.out.println("Before!!!!");
}

@Test
// 改成get()也行
public void put() throws IOException, InterruptedException{
// 获取HDFS的抽象封装对象
Filesystem filesystem = FileSystem.get(
URI.create("hdfs://hadoop104:9000"),
configuration,
user:'ysp');
// 用对象操作文件系统
filesystem.copyToLocalFile(new Path("/test"), new Path("d:/"));
// 关闭文件系统
filesystem.close();
}

@Test
public void rename(){
// 获取文件系统
FileSystem filesystem = Filesystem.get(
URI.create("hdfs://hadoop104:9000"),
new Configuration(),
user:"ysp");
// 操作
filesystem.rename(new Path("/test"), new Path("/test2"));
// 关闭文件系统
filesystem.close();
}

@Test
public void du(){
//append操作流,上传
FSDataOutputStream append = fs.append(new Path("/test/1.txt"), 1024);
FSDataOutputStream open = new FileInputStream(name:"d:/1.txt");
// org.apache.hadoop.io,做了流拷贝
IOUtils.copyBytes(open, append, buffSize:1024, close:1024);

}

@Test
public void delete(){
fs.delete(new Path("/1.txt"), recursive:true);
if (delete) {
System.out.println("删除成功");
} else {
System.out.println("删除失败");
}
}

@Test
public void ls(){ //ls就是liststatus
FileSystem[] fileSatuses = fs.delete(new Path("/1.txt"), recursive:true);
for (FileStatus fileStatus : fileStatuses) {
if ( fileStatus.isFile() ){
System.out.println("是文件的信息");
System.out.println(fileStatus.getPath());
System.out.println(fileStatus.getLen());
} else {
System.out.println( "这是一个文件夹" );
System.out.println(fileStatus.getPath());
}
}
}

@Test
public void listFiles() throws IOException{
// 迭代器,这个只能查文件,ls查看文件和文件夹
// 文件夹没有block
RemoteIterator<LocatedFileSatus> files = fs.listFiles(new Path("/"), recursive:true);
while (files.hasNext()) {
LocatedFileSatus file = files.next();
// 输出块信息
BlockLocation[] blockLocations = file.getBlockLocations();
for (BlockLocation blockLocation:blockLocations){
String[] hosts = blockLocation.getHosts();
for (String host : hosts) {
System.out.println( host + " ");
}
}
}
}

@After
public void after() throws IOException{
System.out.println("After!!!!");
fs.close();
}

}

五、NN和2NN的关系

  • NN的元数据:放在内存里,因为快,因此内存一定要长期工作。
Redis Hadoop(NN)
RDB 类RDB:Fsimage,相当于内存的一个存档,记录内存的状态
AOF 类AOF:edits.log,记录每一步操作
  • 持久化使用Redis:RDB加载高效但生成慢、AOF生成快但加载慢
  • NN的工作机制
    1. NN加载编辑日志和镜像文件到内存里,即edits_inprogress_001和fsimage
    2. client申请元数据的增删改请求
    3. NN记录操作日志、更新滚动日志
    4. 内存数据增删改
  • 2NN

    1. 向NN请求需要CheckPoint,触发条件:定时到,Edits中的数据满了,NN启动时
    2. 请求执行CheckPoints
    3. NN将edits_inprogress_001改名为edits_001,并新建一个edits_inprogress_002
    4. NN将fsimage和edits_001拷贝给2NN
    5. 2NN加载fsimage和edits_001
    6. 2NN生成新的fsimage.chkpoint
    7. 2NN拷贝fsimage.chkpoint到NN
    8. NN将fsimage.chkpoint重命名为fsimage
  • 2NN设定的时间为1小时

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# hdfs-default.xml
<property>
<name>dfs.namenode.checkpoint.period</name>
<value>3600</value>
</property>
# 操作次数达到1百万,2NN执行一次
<property>
<name>dfs.namenode.checkpoint.txns</name>
<value>1000000</value>
</property>
# 一分钟检查一次操作次数
<property>
<name>dfs.namenode.checkpoint.check.period</name>
<value>60</value>
</property>
  • fsimage和edits放在hadoop/data/tmp/dfs/hanem/current里面
1
2
3
# 查看fsimage和edits
hdfs oiv -p XML -i fsimagexxxxxxxx -o /opt/module/hadoop-3.1.3/fsimage.xml
hdfs oiv -p XML -i fsimagexxxxxxxx -o /opt/module/hadoop-3.1.3/fsimage.xml

六、DataNode

  • DataNode里存放着block
  • 每个block都存放这数据、数据长度、校验和、时间戳

  • DataNode启动后向NameNode注册

  • DataNode每周期上报所有块信息
  • DN每3秒一次心跳:心跳返回带有NN给DN的命令,大概失联十分钟就认为这个DN坏了
  • 数据完整性:crc校验和

  • 如何加新机器,扩展集群,重复集群的方法

  • 如何退役旧机器:白名单比黑名单严格
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 一定要在主机配置文件里面
# 配置白名单,只允许集群可以访问的DN
vim whitelist
hadoop104
hadoop106
vim hdfs-site.xml
<property>
<name>dfs.hosts</name>
<value>/opt/module/haddop-3.1.3/etc/hadoop/whitelist</value>
</property>
# 刷新下NN
hdfs dfsadmin -refreshNodes

# 配置黑名单
vim blacklist
hadoop105
vim hdfs-site.xml
<property>
<name>dfs.hosts.exclude</name>
<value>/opt/module/haddop-3.1.3/etc/hadoop/blacklist</value>
</property>
# 刷新下NN
hdfs dfsadmin -refreshNodes
  • DN的多目录配置,注意,配置了两个文件。用于扩展DN的容量。在Linux下,新增一块硬盘,会挂在在某个文件下,这个和windows不一样。
1
2
3
4
5
vim hdfs-site.xml
<property>
<name>dfs.datanode.data.dir</name>
<value>file:///${hadoop.tmp.dir}/dfs/data,file:///{hadoop.tmp.dir}/dfs/data2</value>
</property>