[BD] HDFS

体系架构

  • 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
  • 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

 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 }
View Code

MyInterface.java

 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 }
View Code

MyInterfaceImpl.java

 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 }
View Code

MyRPCServer.java

 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 }
View Code

 

    

  •  Java动态代理对象
    • 如果一个类的名字有$,表示这是一个代理对象
    • 是一种包装设计模式
    • 可以增强类的功能
    • 应用:数据库连接池
    • newProxyInstance 参数
      • ClassLoader 类加载器
      • Class<?>[ ] 真正对象实现的接口
      • InvocationHandler 实现接口来处理客户端调用

MyBusiness.java

1 package proxy;
2 
3 public interface MyBusiness {
4     public void method1();
5     public void method2();
6 }
View Code

MyBusinessImpl.java

 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 }
View Code

TestMain.java

 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 }
View Code

猜你喜欢

转载自www.cnblogs.com/cxc1357/p/12584402.html
BD
今日推荐