hadoop中有3个核心组件:
分布式文件系统:HDFS —— 实现将文件分布式存储在很多的服务器上
分布式运算编程框架:MAPREDUCE —— 实现在很多机器上分布式并行运算
分布式资源调度平台:YARN —— 帮用户调度大量的mapreduce程序,并合理分配运算资源
客户端有多种,例如命令行、页面、或者java程序,并且可以运行在任何一台机器上(HDFS集群中的一台机器或者一台独立的机器也可以)
hadoop fs -ls /hdfs
hadoop fs -put /本地文件 /hdfs目标路径
hadoop fs -copyFromLocal /本地文件 /hdfs路径
## 跟copyFromLocal的区别是:从本地移动到hdfs中
hadoop fs -moveFromLocal /本地文件 /hdfs路径
hadoop fs -get /hdfs路径文件 /本地路径
hadoop fs -copyToLocal /hdfs路径文件 /本地路径
hadoop fs -moveToLocal /hdfs路径文件 /本地路径
# -p 代表创建多层文件夹
hadoop fs -mkdir -p /aaa/xxx
hadoop fs -mv /hdfs路径1 /hdfs路径2
# -r 代表删除整个文件夹
hadoop fs -rm -r /aaa
hadoop fs -chown user:group /aaa
hadoop fs -chmod 700 /aaa
hadoop fs -appendToFile /本地文件 /hdfs中的文件
hadoop fs -cat /hdfs中的文件
hadoop fs -tail /hdfs中的文件
首先,初始化namenode的元数据目录
要在hdp-01上执行hadoop的一个命令来初始化namenode的元数据存储目录
hadoop namenode -format
然后,启动namenode进程和datanode(进入hadoop安装目录/sbin目录)
hadoop-daemon.sh start namenode
hadoop-daemon.sh start datanode
或者使用脚本批量启动
./start-dfs.sh
./stop-dfs.sh
hdfs dfsadmin -safemode leave
package HDFS;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import javax.imageio.stream.FileImageInputStream;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.LocatedFileStatus;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.RemoteIterator;
import org.junit.Before;
import org.junit.Test;
public class HdfsClientDemo {
public static void main(String[] args) throws Exception {
/**
* Configuration参数对象的机制:
* 构造时,会加载jar包中的默认配置 xx-drfalut.xml
* 再加载用户配置 xx-site.xml,覆盖掉默认参数
*
* 构造完成后,还可以conf.set("name","value"),会再次覆盖用户配置文件的参数值
*/
// new 时会从项目的classpath中加载core-defalut.xml hdfs-defalut.xml core-site.xml hdfs-site.xml等文件
Configuration conf = new Configuration();
// 指定客户端上传文件到hdfs时需要保存的副本数量
conf.set("dfs.replication", "2");
// 指定客户端上传文件到hdfs时切块的规格大小
conf.set("dfs.blocksize","64m");
FileSystem fs = FileSystem.get(new URI("hdfs://hadoop100:9000/"), conf, "root");
fs.copyFromLocalFile(new Path("D:\\big data\\java\\EclipseKepler\\eclipse-jee-kepler-SR2-Java8-win32-x86_64.zip"), new Path("/"));
fs.close();
}
FileSystem fs = null;
@Before
public void init() throws Exception{
Configuration conf = new Configuration();
conf.set("dfs.replication", "2");
conf.set("dfs.blocksize","64m");
fs = FileSystem.get(new URI("hdfs://hadoop100:9000/"), conf, "root");
}
/**
* 测试从服务器拷贝数据到本地磁盘
*/
@Test
public void testGet() throws Exception{
fs.copyToLocalFile(new Path("/eclipse-jee-kepler-SR2-Java8-win32-x86_64.zip"), new Path("e:/"));
fs.close();
}
/**
* 在hdfs内部移动文件/重命名
*/
@Test
public void testRename() throws Exception{
fs.rename(new Path("/xxx.txt"), new Path("/y/x.txt"));
fs.close();
}
/**
* 在hdfs创建文件夹
*/
@Test
public void testMkdirs() throws Exception{
fs.mkdirs(new Path("/xx/yy/zz"));
fs.close();
}
/**
* 在hdfs删除文件夹
*/
@Test
public void testDelete() throws Exception{
fs.delete(new Path("/xx"),true);
fs.close();
}
/**
* 查询hdfs指定目录下文件的信息
* (可以递归 所以返回一个迭代器 不然返回一个数组的话假如有很多文件,客户端所在的机器的内存也不够空间存放数据)
*/
@Test
public void testLs() throws Exception{
RemoteIterator<LocatedFileStatus> iter = fs.listFiles(new Path("/"), true);
while(iter.hasNext()){
LocatedFileStatus status = iter.next();
System.out.println("文件全路径:"+status.getPath());
System.out.println("文件块大小:"+status.getBlockSize());
System.out.println("文件长度:"+status.getLen());
System.out.println("副本数量:"+status.getReplication());
System.out.println("文件信息:"+Arrays.toString(status.getBlockLocations()));
System.out.println("-----------------------------------");
}
fs.close();
}
/**
* 查询hdfs指定目录下的文件和文件夹 (只能查看文件夹的下一级 不会递归)
*/
@Test
public void testLs2() throws Exception{
FileStatus[] listStatus = fs.listStatus(new Path("/"));
for(FileStatus status:listStatus){
System.out.println("文件全路径:"+status.getPath());
System.out.println("文件块大小:"+status.getBlockSize());
System.out.println("文件长度:"+status.getLen());
System.out.println("副本数量:"+status.getReplication());
System.out.println("-----------------------------------");
}
fs.close();
}
/**
* 读hdfs文件的内容
*
*/
@Test
public void testReadData() throws Exception{
FSDataInputStream in = fs.open(new Path("/test.txt"));
BufferedReader br = new BufferedReader(new InputStreamReader(in, "utf-8"));
String line = null;
while((line=br.readLine())!=null){
System.out.println(line);
}
in.close();
fs.close();
}
/**
* 读hdfs文件的指定偏移量范围的内容
*
*/
@Test
public void testRandomReadData() throws Exception{
FSDataInputStream in = fs.open(new Path("/xx.dat"));
// 将读取的起始位置进行指定
in.seek(12);
// 读16个字节
byte[] buf = new byte[16];
in.read(buf);
System.out.println(new String(buf));
in.close();
fs.close();
}
/**
* 往hdfs中的文件写内容
*/
@Test
public void testWriteData() throws Exception{
//输出流 将文件写到hdfs中 路径:/xx.jpg
FSDataOutputStream out = fs.create(new Path("/xx.hpg"), false);
// 读本地的数据 本地文件路径:D:/....
FileInputStream in = new FileInputStream("D:/.....");
byte[] buf = new byte[1024];
int read = 0;
while((read=in.read(buf))!=-1){
out.write(buf,0,read);
}
in.close();
out.close();
fs.close();
}
}
1、什么是元数据?
hdfs的目录结构及每一个文件的块信息(块的id,块的副本数量,块的存放位置)
2、元数据由谁负责管理?
namenode
3、管理机制示意图
在内存中,元数据的目录结构是树状的,会定期序列化(对象→二进制流)到磁盘中生成fsimage文件。但是假如内存中元数据非常大(几十G),客户端操作一次数据,即引起元数据变化,假如此时断电还没来得及更新到磁盘,怎么办?
这里当然不能采用 一旦元数据发生变化就序列化 的方法,因为元数据太大。namenode会把引起元数据变化的客户端操作记录在edits日志文件中,日志文件是有序切分的;假如断电了,则在下次启动时只需解析edits操作日志,在内存中更新元数据对象,然后再序列化到磁盘中就可以恢复最新的元数据,但是如果这样岂不是启动时间过长了?怎么办?
找一个秘书(Secondary namenode)定期来做这件事。 secondarynamenode会定期从namenode上下载fsimage镜像和新生成的edits日志,然后加载fsimage镜像到内存中,然后顺序解析edits文件,对内存中的元数据对象进行修改(整合)。整合完成后,将内存元数据序列化成一个新的fsimage,并将这个fsimage镜像文件上传给namenode。上述过程叫做:checkpoint操作
那secondary namenode每次做checkpoint操作时,都需要从namenode上下载上次的fsimage镜像文件吗?
第一次checkpoint需要下载,以后就不用下载了,因为自己的机器上就已经有了。
步骤解析:
3. 是一个block一个block地写进去;
4. 返回的data node主机是name node分配的,并且数量由副本数量决定;
5. 挑选离自己最近的一台data node,请求建立连接;怎样为最近?假如客户端离每个data node只有一台交换机(网关),则每个data node到客户端的距离是一致的,此时随机挑选;假如客户端到每台data node的距离不一致,即到某个data node之间经过多台交换机,则这个data node距离最远;
11. 客户端只将第一个block传输给它之前挑选的data node,剩下的副本由data node之间建立连接进行传输;在DN1上收到客户端发来的数据后,数据流向两个地方:1. 将数据写入本地;2. 将数据传向下一台data node;