hadoop系列笔记
hadoop(一)入门、hadoop架构、集群环境搭建.
hadoop(二)HDFS概述、shell操作、客户端操作(各种API操作)以及hdfs读写流程.
hadoop(三)hdfs的NameNode和DataNode工作机制.
hadoop(四)MapReduce入门及序列化实操.
hadoop(五)MapReduce框架原理及工作机制.
hadoop(六)hadoop数据压缩、yarn架构及工作原理、hadoop企业优化.
hadoop fs 具体命令 OR hdfs dfs 具体命令
dfs是fs的实现类
用法是hadoop fs 加下面后缀执行
1.HDFS–>HDFS
2.本地–>HDFS
3.HDFS–>本地
4.其他
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>jdk.tools</groupId>
<artifactId>jdk.tools</artifactId>
<version>1.8</version>
<scope>system</scope>
<systemPath>${JAVA_HOME}/lib/tools.jar</systemPath>
</dependency>
</dependencies>
导完之后,需要在项目的src/main/resources目录下,新建一个文件,命名为“log4j.properties”,在文件中填入
log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spring.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
package com.liuyongjun.hdfs;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.junit.Test;
import java.io.IOException;
import java.net.URI;
/**
* @author liuyongjun
* @date 2020-06-30-16:19
*/
public class HdfsClient {
@Test
public void get() throws IOException, InterruptedException {
// 1 获取文件系统(hdfs抽象封装对象)
Configuration configuration = new Configuration();
// 配置在集群上运行
// configuration.set("fs.defaultFS", "hdfs://hadoop102:9000");
// FileSystem fs = FileSystem.get(configuration);
/*三个参数:URI:统一资源标识符,指定一下hdfs资源,hdfs://hadoop102:9000,首先hdfs是指schema(模式),是指用hdfs模式进行访问
hadoop102:9000是访问位置
configuration:之前搭hadoop集群,在配置文件的configration标签中配置的
user:登录用户
得到的fs就是文件系统(hdfs抽象封装对象)
*/
FileSystem fs = FileSystem.get(URI.create("hdfs://hadoop102:9000"), configuration, "liuyongjun");
// 2 下载到本地(用这个对象操作文件系统)
//Path是hadoop提供的对路径进行封装的抽象类
fs.copyToLocalFile(new Path("/test"),new Path("d:\\"));
// 3 关闭资源
//hdfs不支持并发写入,所以关闭资源
fs.close();
}
}
@Test
public void rename() throws IOException, InterruptedException {
//获取文件系统
FileSystem fs = FileSystem.get(URI.create("hdfs://hadoop102:9000"), new Configuration(), "liuyongjun");
//操作
fs.rename(new Path("/test"),new Path("/test2"));
//关闭文件系统
fs.close();
}
package com.liuyongjun.hdfs;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import org.apache.hadoop.io.IOUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import javax.swing.*;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URI;
/**
* @author liuyongjun
* @date 2020-06-30-16:19
*/
public class HdfsClient {
private FileSystem fs;
@Test
public void get() throws IOException, InterruptedException {
// 1 获取文件系统
Configuration configuration = new Configuration();
/*三个参数:URI:统一资源标识符,指定一下hdfs资源,hdfs://hadoop102:9000,首先hdfs是指schema(模式),是指用hdfs模式进行访问
hadoop102:9000是访问位置
configuration:之前搭hadoop集群,在配置文件的configration标签中配置的
user:登录用户
得到的fs就是文件系统(hdfs抽象对象)
*/
FileSystem fs = FileSystem.get(URI.create("hdfs://hadoop102:9000"), configuration, "liuyongjun");
// 2 下载
//Path是hadoop提供的对路径进行封装的抽象类
fs.copyToLocalFile(new Path("/test"),new Path("d:\\"));
// 3 关闭资源
//hdfs不支持并发写入,所以关闭资源
fs.close();
}
@Before
public void before() throws IOException, InterruptedException {
//获取文件系统
fs = FileSystem.get(URI.create("hdfs://hadoop102:9000"), new Configuration(), "liuyongjun");
}
@Test
public void rename() throws IOException {
//操作HDFS文件名更改
fs.rename(new Path("/test"),new Path("/test2"));
}
@Test
public void testCopyFromLocalFile() throws IOException {
//HDFS文件上传
fs.copyFromLocalFile(new Path("d:/2.txt"),new Path("/"));
}
@Test
public void append() throws IOException {
//HDFS文件拼接操作
FSDataOutputStream append = fs.append(new Path("/test/1.txt"), 1024);
FileInputStream open = new FileInputStream("d:/testhdfs/2.txt");
//流拷贝
IOUtils.copyBytes(open,append,1024,true);
//上面输入是本地,输出是hdfs,所以为文件上传
//如果输入为hdfs,输出为本地,则为文件下载
//hdfs获取输入流用open,获取输出流用append
}
@Test
public void delete() throws IOException, InterruptedException {
//删除操作
boolean delete = fs.delete(new Path("/test2"), true);
if(delete){
System.out.println("删除成功");
}else{
System.out.println("删除失败");
}
}
@Test
public void ls() throws IOException {
//HDFS文件查看
FileStatus[] fileStatuses = fs.listStatus(new Path("/"));
for (FileStatus fileStatus : fileStatuses) {
//HDFS文件和文件夹判断
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 {
//查看目录下所有文件
RemoteIterator<LocatedFileStatus> files = fs.listFiles(new Path("/"), true);
while(files.hasNext()){
LocatedFileStatus file = files.next();
System.out.println("==============================");
System.out.println(file.getPath());
System.out.println("块信息");
BlockLocation[] blockLocations = file.getBlockLocations();
for (BlockLocation blockLocation : blockLocations) {
String[] hosts = blockLocation.getHosts();
System.out.print("块在");
for (String host : hosts) {
System.out.print(host+" ");
}
}
}
}
@After
public void after() throws IOException {
//关闭文件系统
fs.close();
}
}
hdfs-site.xml
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<!--指定HDFS副本的数量-->
<property>
<name>dfs.replication</name>
<value>2</value>
</property>
</configuration>
上传程序
@Test
public void testCopyFromLocalFile() throws Exception {
// 1 获取文件系统
Configuration configuration = new Configuration();
//设置配置文件
configuration.set("dfs.replication", "1");
FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9000"), configuration, "liuyongjun");
// 2 上传文件
fs.copyFromLocalFile(new Path("d:/1.txt"), new Path("/1.txt"));
// 3 关闭资源
fs.close();
System.out.println("over");
}
上面我们设置副本数,服务器默认是3个,ClassPath下的用户自定义配置2个,客户端代码中设置的是1个,我们看看它响应哪个,则哪个优先级高
如图,副本数为:
所以参数优先级排序:(1)客户端代码中设置的值 >(2)ClassPath下的用户自定义配置文件 >(3)然后是服务器的默认配置
NameNode:领导级别。管理数据块映射;处理客户端的读写请求;配置副本策略;管理HDFS的名称空间;
DataNode:员工级别。负责存储客户端发来的数据块block;执行数据块的读写操作。
写详细步骤:
1、首先向namenode通信,请求上传文件,namenode检查目标文件是否已存在,父目录是否存在 ,还得看看是否有上传的权限,说白了,就是判断是否可以上传
2、namenode返回是否可以上传 ,如果可以,client会先对文件进行切分(逻辑切分)
3、客户端请求第一个 Block上传到哪几个DataNode服务器上。
4、NameNode返回3个DataNode节点,分别为dn1、dn2、dn3。
5、客户端通过FSDataOutputStream模块请求dn1上传数据,dn1收到请求会继续调用dn2,然后dn2调用dn3,将这个通信管道建立完成。
6、dn1、dn2、dn3逐级应答客户端。
7、客户端开始往dn1上传第一个Block(先从磁盘读取数据放到一个本地内存缓存),以Packet为单位,dn1收到一个Packet就会传给dn2,dn2传给dn3;dn1每传一个packet会放入一个应答队列等待应答。
8、当一个Block传输完成之后,客户端再次请求NameNode上传第二个Block的服务器。(重复执行3-7步)。
9、传输完毕之后,客户端关闭流资源,并且会告诉hdfs数据传输完毕,然后hdfs收到传输完毕就恢复元数据
具体概念介绍
Distributed FileSystem:进行抽象封装,FileSystem会利用JDK的反射机制创建一个DistributedFileSystem实例(对象),然后调用它的initialize()方法
逻辑切分:客户端并没有将文件真正切分,只是画了个标志线加以区分
写操作,上传文件,所以本地是输入流,hdfs是输出流
第三步有哪几个DataNode服务器上:这里指副本数,设置了几个副本,就返回几个DataNode(记住数据是存储在DataNode)我设置了三个副本,所以,返回三个;
同时,返回的DataNode也有一定规矩,首先第一个DataNode是距离客户端最近的,后两个是根据第一个选出,产生了两个问题,如何判断最近,以及如何根据第一个选,这个请看: 拓扑距离和机架感知.
第七步,packet为单位,每个64KB
传输Packet:dn1收到之后,一边往本地落盘,一边传给dn2,之后的dn2同理,当dn3落盘结束之后,它将成功信息发给dn2,之后dn2需要等自己成功并且收到dn3成功信息之后,将成功信息发给dn1,同理,dn1在接收到dn2成功信息并且自己落盘成功之后发给客户端,此时一个packet就成功了;注意packet不是逐个发的,是一个队列同时发的,成功了,在队列里删除掉,这样全部packet发完,第一块就传完了,接着传第二块,第二次选择的DataNode可能和第一次一样,也可能不一样
传输过程中几种失败可能:
1)客户端通过Distributed FileSystem向NameNode请求下载文件,NameNode通过查询元数据,找到文件块所在的DataNode地址。
2)挑选一台DataNode(就近原则,然后随机)服务器,请求读取数据。
3)DataNode开始传输数据给客户端(从磁盘里面读取数据输入流,以Packet为单位来做校验)。
4)客户端以Packet为单位接收,先在本地缓存,然后写入目标文件。
5)下载完第一块,在重复上面2.3步下载