HDFS源码(二)

DataNode启动源码

创建HttpServer

初始化DataNode Rpc服务

获取NameNode Rpc代理

Datanode向NameNode注册

DataNode与NameNode周期心跳及block块汇报

数据上传源码

创建文件系统及初始化DFSClient

连接NN创建目录

启动DataStreamer线程

向dataQueue队列中写入packet

设置副本写入策略源码

java 复制代码
protected Node chooseTargetInOrder(int numOfReplicas, 
                               Node writer,
                               final Set<Node> excludedNodes,
                               final long blocksize,
                               final int maxNodesPerRack,
                               final List<DatanodeStorageInfo> results,
                               final boolean avoidStaleNodes,
                               final boolean newBlock,
                               EnumMap<StorageType, Integer> storageTypes)
                               throws NotEnoughReplicasException {
  // 计算结果列表的大小,默认初始 results 为0,result集合表示副本所在的节点
  final int numOfResults = results.size();
  // 如果结果列表为空
  if (numOfResults == 0) {
    // 选择本地节点作为第一个副本存储位置,并向result中加入节点
    DatanodeStorageInfo storageInfo = chooseLocalStorage(writer,
        excludedNodes, blocksize, maxNodesPerRack, results, avoidStaleNodes,
        storageTypes, true);

    //writer第一个副本要写出的DataNode节点
    writer = (storageInfo != null) ? storageInfo.getDatanodeDescriptor()
                                   : null;

    //减去一个副本后,如果为0则返回,writer,否则不返回,继续
    if (--numOfReplicas == 0) {
      return writer;
    }
  }
  //第一个副本所在DN节点
  final DatanodeDescriptor dn0 = results.get(0).getDatanodeDescriptor();

  if (numOfResults <= 1) {
    //选择远程机架存放第二个副本
    chooseRemoteRack(1, dn0, excludedNodes, blocksize, maxNodesPerRack,
        results, avoidStaleNodes, storageTypes);
    if (--numOfReplicas == 0) {
      //writer第一个副本要写出的DataNode节点
      return writer;
    }
  }

  if (numOfResults <= 2) {
    //第二个副本所在DN节点
    final DatanodeDescriptor dn1 = results.get(1).getDatanodeDescriptor();
    if (clusterMap.isOnSameRack(dn0, dn1)) {//如果dn0与dn1是同一机架,第三个副本选择不同机架
      chooseRemoteRack(1, dn0, excludedNodes, blocksize, maxNodesPerRack,
          results, avoidStaleNodes, storageTypes);
    } else if (newBlock){//如果是新块,选择与dn1 第二个副本所在节点相同的机架上放第三个副本
      chooseLocalRack(dn1, excludedNodes, blocksize, maxNodesPerRack,
          results, avoidStaleNodes, storageTypes);
    } else {//随机选择一台节点存储第3个副本
      chooseLocalRack(writer, excludedNodes, blocksize, maxNodesPerRack,
          results, avoidStaleNodes, storageTypes);
    }
    if (--numOfReplicas == 0) {
      //writer第一个副本要写出的DataNode节点
      return writer;
    }
  }
  //大于3个副本,随机选择节点存放副本
  chooseRandom(numOfReplicas, NodeBase.ROOT, excludedNodes, blocksize,
      maxNodesPerRack, results, avoidStaleNodes, storageTypes);
  //writer第一个副本要写出的DataNode节点
  return writer;
}

"chooseTargetInOrder"方法代码逻辑为block 副本找到存储节点的策略,然后返回block所在的第一个节点,首先第一个block存储在本机,第二个block存储在远程机架,第三个副本存储时先判断是否第一个副本和第二个副本是否在同一机架,如果在同一机架,那么第三个副本选择不同机架进行存储,否则选择与第二个副本相同机架的随机节点进行存储。最终该方法返回存储第一个副本的DataNode节点。

客户端与DataNode建立socket通信

向Datanode中写入数据

数据读取源码

数据 从HDFS中读取数据代码如下:

java 复制代码
public class ReadDataFromHDFS {
    public static void main(String[] args) throws IOException, InterruptedException {
        Configuration conf = new Configuration();

        //创建FileSystem对象
        FileSystem fs = FileSystem.get(URI.create("hdfs://node1:8020/"),conf,"root");

        //创建HDFS文件路径
        Path path = new Path("/test.txt");
        FSDataInputStream in = fs.open(path);


        //读取HDFS中数据
        BufferedReader br = new BufferedReader(new InputStreamReader(in));
        String newLine = "";
        while((newLine = br.readLine()) != null) {
            System.out.println(newLine);
        }

        //关闭流对象
        br.close();
        in.close();
    }
}

HDFS中数据读取源码相对简单,客户端从HDFS中获取文件数据时,首先会向NameNode获取文件相关的block信息,然后连接各个Datanode以流方式读取数据即可。

连接NameNode获取block信息

"namenode.getBlockLocations(src, start, length)"最终调用到NameNodeRpcServer.getBlockLocations(...)方法。

回到DFSClient.open()方法中,最终通过执行"return openInternal(locatedBlocks, src, verifyChecksum);"返回DFSInputStream对象。

客户端通过socket连接DataNode

DataNode返回block数据流

最终通过readBuffer(...)从DataNode中获取文件数据。

相关推荐
宸津-代码粉碎机4 分钟前
Java面试核心:JVM三大GC垃圾回收算法原理与生产场景落地分析
java·大数据·人工智能·python·spring
蓝速科技7 分钟前
蓝速 K10 三防平板在工业恶劣工况下的选型与应用指南
大数据·运维·数据库·人工智能·科技
衡石科技23 分钟前
多源数据分析的工程路径:连接、建模、同步与加速
大数据·人工智能·chatbi
外域速览9 小时前
智谱50亿美元押注AI自训练
大数据·人工智能
人工智能培训9 小时前
孪生不止在工厂:能源、医疗与农业
大数据·人工智能
QYRdata10 小时前
隐私合规技术迎来拐点:数据主体请求自动化年复合增长率14.0%(2026-2032)
大数据·服务发现
Elastic 中国社区官方博客12 小时前
列式存储并不等同于列式数据库。Columnar 模式为 Elasticsearch 带来了什么
大数据·运维·数据库·elasticsearch·搜索引擎
weixin1997010801612 小时前
[特殊字符]️《二手ERP对接电商平台的总体方案:统一数据模型 + 事件驱动 + 灰度上线6原则》(附Python源码)
大数据·python
大大大大晴天13 小时前
从元数据到数据地图:企业数据治理的第一块地基
大数据
科创致远13 小时前
科创致远 eSOP 电子作业指导书系统落地应用指南
大数据·人工智能·汽车·制造·精益工程