一.HDFS基本知识
1.让文件平均分块block 每块有多个副本 每块和每个副本存在不同的Datanode上。
一个文件分成多块 默认每块128M 那么一个130M的文件 就会分成一块128M 一块2M
一个文件,除了最后一个block之外,其他block大小都一样
副本因子(replication ):一个文件副本数量,默认三份
二.优缺点
优点
1.使得多个计器之间能够负载均衡
2.有一个服务器挂了也不影响整个文件
3.多个datanode并行处理,提升速度
缺点
1.数据访问有延迟
2.不适合小文件的存储(浪费block)
三.hdfs架构
Master(NameNode) 带N个Slaves(DataNode)
datanode管理数据存储
NameNode:负责客户端请求的响应,负责元数据管理
当一个read读文件请求过来时,他要请求namenode,看目标文件被分成了几分,存到了哪几个节点上
DataNode:负责存储数据块block,定期向Namenode汇报信息,健康状况,与NameNode维持心跳
比如一个DataNode存储空间不够用了,那么再有文件写入时,NameNode作为管理者,就不往这个DataNode上分发了
四.经典部署模式
一个hdfs只部署一个NameNode,每个机器部署一个DataNode
目前我用三台机器搭建的HADOOP分布式:hadoop102,hadoop103,hadoop104
hadoop102:NameNode,DataNode,NodeManager(NodeManager是yarn的)
hadoop103:DataNode,ResourceManager(yarn),NodeManager
hadoop104:DataNode,NodeManager
部署成功之后可以看到活着的节点有三个
五.hdfs安装
开始想在windows上搞虚拟机,但是过程比较费劲也比较卡,后来放弃了,直接租的三台阿里云服务器
目前只说大致过程,等我心情好了再写个完整版
我用的是上传压缩包去安装,看网上也有yum安装,yum能在线下载并安装rpm包,能更新系统
1.修改/etc/hosts
三台机器主机名对应ip
2.免密配置
生成的在.ssh目录下生成公钥文件和私钥文件 带.pub的是公钥
你想让谁免密登陆当前机器,就把公钥拷贝给谁
免密测试
3.配置jdk
4.配置hadoop环境变量
5.修改配置文件
5.1核心配置文件core-site.xml
5.2hdfs配置文件hdfs-site.xml
5.3yarn配置文件yarn-site.xml
5.4mapreduce配置文件mapred-site.xml
5.5配置workers(老版本中也叫slaves,听说因为反对奴隶制,改成了workers)
六.安装过程中踩的坑
1.命令不生效
原因:hadoop文件大小为0KB
我也不到我误碰了什么
解决办法:
再解压一个,把里边的hadoop文件复制过来
2.无法访问yarn控制台
yarn-site.xml配置文件
3.格式化报错
格式化这个步骤要放在第一次启动之前
.xml文件的文件头,前边不能留空格,不然hadoop格式化时候会报错
七.hdfs命令
查看根目录文件
hdfs dfs -ls /
将文件上传到根目录
hdfs dfs -put test.txt /
查看文件内容
hdfs dfs -cat /test.txt
创建目录
hdfs dfs -mkdir /testDir
从hdfs上获取文件到本地
hdfs dfs -get /testDir
删除文件
hdfs dfs -rm /test.txt
八.读写文件流程
hdfs写文件流程
1.客户端分块block
2.namenode作为领导,分任务
3.datanode存储数据
4.过程中,datanode和namenode保持心跳,汇报信息
hdfs读文件流程
1.客户端发起读文件操作
2.namenode提供文件的block信息以及存储block的datanode信息
举例 test.txt的block1在datanode1,datanode2
block2在datanode2,datanode3
九.javaApi操作hdfs
主要应用hadoop包下的FileSystem类,有很多操作文件的方法,方法名与hdfs命令类似
1.资源下载路径
2.maven下载仓库配置
<repositories>
<repository>
<id>cloudera</id>
<url>https://repository.cloudera.com/artifactory/cloudera-repos/</url>
</repository>
</repositories>
<!--添加hadoop依赖-->
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>${hadoop.version}</version>
</dependency>
3.简单操作hdfs的方法
(现在一般都用springboot了 下边代码不是springboot,就很入门的测试)
package com.imooc.hadoop.hdfs;
import com.google.code.useragent.UserAgentParser;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.util.Progressable;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URI;
/**
* Hadoop HDFS Java API 操作
*/
public class HDFSApp {
/**
* 创建文件
*/
@Test
public void create() throws Exception {
FSDataOutputStream output = fileSystem.create(new Path("/hdfsapi/test/a.txt"));
output.write("hello hadoop".getBytes());
output.flush();
output.close();
}
/**
* 查看HDFS文件的内容
*/
@Test
public void cat() throws Exception {
FSDataInputStream in = fileSystem.open(new Path("/hdfsapi/test/a.txt"));
IOUtils.copyBytes(in, System.out, 1024);
in.close();
}
/**
* 重命名
*/
@Test
public void rename() throws Exception {
Path oldPath = new Path("/hdfsapi/test/a.txt");
Path newPath = new Path("/hdfsapi/test/b.txt");
fileSystem.rename(oldPath, newPath);
}
/**
* 上传文件到HDFS
*
* @throws Exception
*/
@Test
public void copyFromLocalFile() throws Exception {
Path localPath = new Path("/Users/rocky/data/hello.txt");
Path hdfsPath = new Path("/hdfsapi/test");
fileSystem.copyFromLocalFile(localPath, hdfsPath);
}
/**
* 上传文件到HDFS
*/
@Test
public void copyFromLocalFileWithProgress() throws Exception {
InputStream in = new BufferedInputStream(
new FileInputStream(
new File("/Users/rocky/source/spark-1.6.1/spark-1.6.1-bin-2.6.0-cdh5.5.0.tgz")));
FSDataOutputStream output = fileSystem.create(new Path("/hdfsapi/test/spark-1.6.1.tgz"),
new Progressable() {
public void progress() {
System.out.print("."); //带进度提醒信息
}
});
IOUtils.copyBytes(in, output, 4096);
}
/**
* 下载HDFS文件
*/
@Test
public void copyToLocalFile() throws Exception {
Path localPath = new Path("/Users/rocky/tmp/h.txt");
Path hdfsPath = new Path("/hdfsapi/test/hello.txt");
fileSystem.copyToLocalFile(hdfsPath, localPath);
}
/**
* 查看某个目录下的所有文件
*/
@Test
public void listFiles() throws Exception {
FileStatus[] fileStatuses = fileSystem.listStatus(new Path("/"));
for(FileStatus fileStatus : fileStatuses) {
String isDir = fileStatus.isDirectory() ? "文件夹" : "文件";
short replication = fileStatus.getReplication();//查看副本数量
long len = fileStatus.getLen();//文件大小
String path = fileStatus.getPath().toString();//全路径
System.out.println(isDir + "\t" + replication + "\t" + len + "\t" + path);
}
}
/**
* 删除
*/
@Test
public void delete() throws Exception{
fileSystem.delete(new Path("/"), true);
}
@After
public void tearDown() throws Exception {
configuration = null;
fileSystem = null;
System.out.println("HDFSApp.tearDown");
}
public static final String HDFS_PATH = "hdfs://127.0.0.1:9820";
FileSystem fileSystem = null;
Configuration configuration = null;
/**
* 注意这里是@Before
* @throws Exception
*/
@Before
public void setUp() throws Exception {
System.out.println("HDFSApp.setUp");
configuration = new Configuration();
fileSystem = FileSystem.get(new URI(HDFS_PATH), configuration, "hadoop");
}
/**
* 创建HDFS目录
*/
@Test
public void mkdir() throws Exception {
fileSystem.mkdirs(new Path("/hdfsapi/test"));
}
}