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中获取文件数据。

相关推荐
SelectDB16 小时前
秒级弹性、最高降本 70%:SelectDB Serverless 如何重塑云数仓资源效率
大数据·后端·云原生
WhoAmI16 小时前
MapReduce框架原理解析一:InputFormat
大数据·hadoop
WhoAmI16 小时前
MapReduce框架原理解析三:OutputFormat
大数据·hadoop
WhoAmI16 小时前
MapReduce框架原理解析二:Shuffle
大数据·hadoop
大大大大晴天2 天前
Hudi技术内幕:Key Generation原理与实践
大数据
得物技术5 天前
从埋点需求到规则资产:Hermes Agent 重构得物数仓工作流
大数据·llm·ai编程
久美子5 天前
AI驱动数仓建设的Harness工程实践——本体建模、知识分层与上下文工程
大数据
大树886 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
大志哥1236 天前
ES和Logstash日志链路系统上线后遭遇切片爆炸(解决)
大数据·elasticsearch
果丁智能6 天前
物联网智能锁赋能集中式住宿:身份核验与远程权限管控的全链路技术实践
大数据·人工智能·物联网·智能家居