体系架构
- NameNode
- HDFS主节点、管理员
- 接收客户端(命令行、Java程序)的请求:创建目录、上传、下载、删除数据
- 管理和维护HDFS的日志和元信息
- 日志文件(edits文件)
- 二进制文件,记录客户端所有操作,同时体现HDFS的最新状态
- $HADOOP_HOME/tmp/dfs/name/current
- 日志查看器(edits viewer):把edits转成文本(XML)格式
- hdfs oev -i edits_inprogress_0000000000000000107 -o ~/a.xml
- 元信息(fsimage文件)
- 记录数据块的位置信息、数据块的冗余信息,不体现HDFS的最新状态
- $HADOOP_HOME/tmp/dfs/name/current
- image viewer,把fsimage文件转为文本或者xml
- 日志文件(edits文件)
- DataNode
- 数据节点
- 按数据块保存数据库(1.x:64M,2.x:128M)
- /root/training/hadoop-2.7.3/tmp/dfs/data/current/BP-419062579-192.168.157.111-1535553141546/current/finalized/subdir0/subdir0
- 数据块冗余度设置原则:一般跟数据节点的个数一样,但是最大不要超过3
- Hadoop 3.x以后,HDFS纠删码技术,大大的节约存储的空间(节约一半 )
- SecondaryNameNode
- 第二名称节点
- 进行日志信息的合并
- 由于edits文件记录了最新的状态信息,并且随着操作越来越多,edits就会越大
- 把edits中的最新信息写到fsimage中
- edits文件就可以清空
- 通常和NameNode部署在一台机器上,提高下载速度
- 什么时候合并?HDFS发出检查点时(checkpoint)
- HDFS每隔60分钟产生一个检查点(fs.check.period)
- edits文件达到64M(fs.check.size)
数据传输
- 数据上传
- 请求上传数据 Distributed FileSystem.java
- 创建 DFSClient.java
- 建立RPC通信
- 拿到NameNode代理对象NameNodeProxies(HA)
- 请求创建文件元信息
- 创建文件元信息
- 将元信息返回给 Distributed FileSystem
- 创建输出流 FSDataOutputStream
- 上传数据到DataNode
- 根据元信息,水平复制
- 数据下载
- 请求
- 创建
- 建立RPC通信
- 请求得到元信息
- 查找元信息(先查缓存,再查fsimage)
- 返回元信息
- 创建输入流
- 下载数据块
- 把下载的数据块合成一个文件
高级特性
- 安全模式
- 只读,正常运行时off
- HDFS的自我保护机制,检查数据块副本率
- 如果冗余度小于设定的副本率(DataNode坏掉),就水平复制
- 在hdfs-default.xml中设定副本率
- 快照
- 全部文件系统或某目录在某时刻的镜像,默认关闭
- 启用目录的快照功能
- 创建快照 -createSnapshot 目录 快照名称
- 用于以下场景
- 防止用户误操作/备份/测试/灾难恢复
- 一般不建议使用,因为本来就有冗余,再生成新的冗余,太浪费空间
- 配额
- HDFS为每个目录分配的大小空间
- 名称配额
- 设置该目录中最多存放的文件(目录)个数
- 空间配额
- 设置该目录中最大能够存放的文件大小
- 回收站
- 默认禁用
- 放入/trash
- 回收站中文件可快速恢复
- 可设置一个时间,超过后文件自动删除
- 用户权限管理
- 功能较弱
- 建议使用 Hadoop Kerberos
启动过程
- 网页->Startup Progress
- Loading fsimage
- Loading edits
- Saving checkpoint
- Safe mode
底层原理
- RPC(remote procedure call)
- 远程过程调用(协议)
- 在客户端调用服务器端的程序
- 一个框架,调用者和被调用者运行在其中完成通信
- 调用远程代码,需要实现调用者和被调用者间的连接与通信
- 基于Client/Server进程间相互通信的一种同步通信形式
- Client是请求服务的调用者,Server是执行Client的请求而被调用的程序
- Hadoop用Java实现RPC
- 客户端
- 服务器端
- 远程过程调用(协议)
MyRPCClient.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 package rpc.client; 2 3 import java.io.IOException; 4 import java.net.InetSocketAddress; 5 6 import org.apache.hadoop.conf.Configuration; 7 import org.apache.hadoop.ipc.RPC; 8 9 import rpc.server.MyInterface; 10 11 public class MyRPCClient { 12 13 public static void main(String[] args) throws IOException { 14 // 使用Hadoop RPC框架调用Server端程序 15 // 得到Server部署对象的代理对象 16 MyInterface proxy = RPC.getProxy(MyInterface.class, 17 MyInterface.versionID, 18 new InetSocketAddress("localhost",7788), 19 new Configuration()); 20 // 使用代理对象调用Server程序 21 String result = proxy.sayHello("Tom"); 22 System.out.println(result); 23 } 24 }
MyInterface.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 package rpc.server; 2 3 import org.apache.hadoop.ipc.VersionedProtocol; 4 5 public interface MyInterface extends VersionedProtocol{ 6 // 定义版本号 7 // 使用版本号进行签名 8 public static long versionID = 1; 9 10 // 定义业务方法 11 public String sayHello(String name); 12 }
MyInterfaceImpl.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 package rpc.server; 2 3 import java.io.IOException; 4 5 import org.apache.hadoop.ipc.ProtocolSignature; 6 7 public class MyInterfaceImpl implements MyInterface{ 8 9 @Override 10 public ProtocolSignature getProtocolSignature( 11 String arg0, long arg1, int arg2) 12 throws IOException { 13 // 通过版本号定义签名信息 14 return new ProtocolSignature(MyInterface.versionID,null); 15 } 16 17 @Override 18 public long getProtocolVersion(String arg0, long arg1) 19 throws IOException { 20 // 返回版本号 21 return MyInterface.versionID; 22 } 23 24 @Override 25 public String sayHello(String name) { 26 System.out.println("**********调用Server端**********"); 27 return "Hello " + name; 28 } 29 }
MyRPCServer.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 package rpc.server; 2 3 import java.io.IOException; 4 5 import org.apache.hadoop.HadoopIllegalArgumentException; 6 import org.apache.hadoop.conf.Configuration; 7 import org.apache.hadoop.ipc.RPC; 8 import org.apache.hadoop.ipc.RPC.Server; 9 10 public class MyRPCServer { 11 public static void main(String[] args) throws HadoopIllegalArgumentException, IOException { 12 // 利用Hadoop的RPC框架实现RPC Server 13 14 // 使用RPC Builder构建 15 RPC.Builder builder = new RPC.Builder(new Configuration()); 16 17 // 定义Server的参数 18 builder.setBindAddress("localhost"); 19 builder.setPort(7788); 20 21 // 部署程序 22 builder.setProtocol(MyInterface.class); 23 builder.setInstance(new MyInterfaceImpl()); 24 25 // 创建RPC Server 26 Server server = builder.build(); 27 28 server.start(); 29 } 30 }
- Java动态代理对象
- 如果一个类的名字有$,表示这是一个代理对象
- 是一种包装设计模式
- 可以增强类的功能
- 应用:数据库连接池
- newProxyInstance 参数
- ClassLoader 类加载器
- Class<?>[ ] 真正对象实现的接口
- InvocationHandler 实现接口来处理客户端调用
MyBusiness.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 package proxy; 2 3 public interface MyBusiness { 4 public void method1(); 5 public void method2(); 6 }
MyBusinessImpl.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 package proxy; 2 3 public class MyBusinessImpl implements MyBusiness { 4 5 @Override 6 public void method1() { 7 System.out.println("*********method1*********"); 8 } 9 10 @Override 11 public void method2() { 12 System.out.println("*********method2*********"); 13 } 14 }
TestMain.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 package proxy; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 import java.lang.reflect.Proxy; 6 7 public class TestMain { 8 9 public static void main(String[] args) { 10 // 创建对象 11 MyBusiness obj = new MyBusinessImpl(); 12 // 创建代理对象 13 MyBusiness proxy = (MyBusiness) Proxy.newProxyInstance(TestMain.class.getClassLoader(), 14 obj.getClass().getInterfaces(), 15 new InvocationHandler(){ 16 @Override 17 public Object invoke(Object proxy,Method method,Object[] args)throws Throwable { 18 if(method.getName().equals("method1")) { 19 //重写 20 System.out.println("*************代理对象中的method1*************"); 21 return null; 22 }else { 23 // 其他方法 24 return method.invoke(obj, args); 25 } 26 } 27 }); 28 // 通过代理对象调用真正对象 29 proxy.method1(); 30 proxy.method2(); 31 } 32 }
命令
- hdfs dfs
- -ls /:查看所有目录下的文件
- -ls /data:查看/data下的所有文件
- -mkdir /data:在hdfs上创建目录/data
- -cp:拷贝文件
- -rm:删除文件
- -get:复制文件到本地