HDFS源码解析---checksum数据校验

Hdfs 客户端读过程 源码解析 说到hdfs文件系统上的读文件流程,相信大家都不会陌生,都会知道读取文件的过程如下的示意图: 客户端读过程示意图: 其基本的读取流程如下: 客户端通过调用FileSystem对象的open()方法来打开hdfs上的文件,这个方法在底层会调用ClientProtocol.open()方法,该方法会返回一个HdfsDataInputStream对象用于读取数据块。HdfsDataInputStream是一个DFSInputStream的装饰类,真正进行数据块读取操作的是DFSInputSt... 阅读详情

客户端获取文件的checksum

整体流程如下:

1、获取文件的所有block

2、遍历每个block

3、获取block的所有副本以及所在的datanode,去datanode上获取这个block的checksum

4、获取每个block的checksum的byte-per-checksum,crc-per-block(block的crc)以及MD5

5、根据所有block的MD5计算文件的MD5

6、文件的MD5 + bytesPerCRC + crcPerBlock 计算MD5FileChecksum

public MD5MD5CRC32FileChecksum getFileChecksum(String src, long length)
      throws IOException {
    checkOpen();
    Preconditions.checkArgument(length >= 0);
    //get block locations for the file range
    LocatedBlocks blockLocations = callGetBlockLocations(namenode, src, 0,
        length, dfsClientConf.preferedPool);
    if (null == blockLocations) {
      throw new FileNotFoundException("File does not exist: " + src);
    }
    List<LocatedBlock> locatedblocks = blockLocations.getLocatedBlocks();
    final DataOutputBuffer md5out = new DataOutputBuffer();
    int bytesPerCRC = -1;
    DataChecksum.Type crcType = DataChecksum.Type.DEFAULT;
    long crcPerBlock = 0;
    boolean refetchBlocks = false;
    int lastRetriedIndex = -1;

    // get block checksum for each block
    long remaining = length;
    if (src.contains(HdfsConstants.SEPARATOR_DOT_SNAPSHOT_DIR_SEPARATOR)) {
      remaining = Math.min(length, blockLocations.getFileLength());
    }
    for(int i = 0; i < locatedblocks.size() && remaining > 0; i++) {
      if (refetchBlocks) {  // refetch to get fresh tokens
        blockLocations = callGetBlockLocations(namenode, src, 0, length, dfsClientConf.preferedPool);
        if (null == blockLocations) {
          throw new FileNotFoundException("File does not exist: " + src);
        }
        locatedblocks = blockLocations.getLocatedBlocks();
        refetchBlocks = false;
      }
      LocatedBlock lb = locatedblocks.get(i);
      final ExtendedBlock block = lb.getBlock();
      if (remaining < block.getNumBytes()) {
        block.setNumBytes(remaining);
      }
      remaining -= block.getNumBytes();
      final DatanodeInfo[] datanodes = lb.getLocations();
      
      //try each datanode location of the block
      final int timeout = 3000 * datanodes.length + dfsClientConf.socketTimeout;
      boolean done = false;
      for(int j = 0; !done && j < datanodes.length; j++) {
        DataOutputStream out = null;
        DataInputStream in = null;
        
        try {
          //connect to a datanode
          IOStreamPair pair = connectToDN(datanodes[j], timeout, lb);
          out = new DataOutputStream(new BufferedOutputStream(pair.out,
              HdfsConstants.SMALL_BUFFER_SIZE));
          in = new DataInputStream(pair.in);

          if (LOG.isDebugEnabled()) {
            LOG.debug("write to " + datanodes[j] + ": "
                + Op.BLOCK_CHECKSUM + ", block=" + block);
          }
          // get block MD5
          new Sender(out).blockChecksum(block, lb.getBlockToken());

          final BlockOpResponseProto reply =
            BlockOpResponseProto.parseFrom(PBHelper.vintPrefixed(in));

          if (reply.getStatus() != Status.SUCCESS) {
            if (reply.getStatus() == Status.ERROR_ACCESS_TOKEN) {
              throw new InvalidBlockTokenException();
            } else {
              throw new IOException("Bad response " + reply + " for block "
                  + block + " from datanode " + datanodes[j]);
            }
          }
          
          OpBlockChecksumResponseProto checksumData =
            reply.getChecksumResponse();

          //read byte-per-checksum
          final int bpc = checksumData.getBytesPerCrc();
          if (i == 0) { //first block
            bytesPerCRC = bpc;
          }
          else if (bpc != bytesPerCRC) {
            throw new IOException("Byte-per-checksum not matched: bpc=" + bpc
                + " but bytesPerCRC=" + bytesPerCRC);
          }
          
          //read crc-per-block
          final long cpb = checksumData.getCrcPerBlock();
          if (locatedblocks.size() > 1 && i == 0) {
            crcPerBlock = cpb;
          }

          //read md5
          final MD5Hash md5 = new MD5Hash(
              checksumData.getMd5().toByteArray());
          md5.write(md5out);
          
          // read crc-type
          final DataChecksum.Type ct;
          if (checksumData.hasCrcType()) {
            ct = PBHelper.convert(checksumData
                .getCrcType());
          } else {
            LOG.debug("Retrieving checksum from an earlier-version DataNode: " +
                      "inferring checksum by reading first byte");
            ct = inferChecksumTypeByReading(lb, datanodes[j]);
          }

          if (i == 0) { // first block
            crcType = ct;
          } else if (crcType != DataChecksum.Type.MIXED
              && crcType != ct) {
            // if crc types are mixed in a file
            crcType = DataChecksum.Type.MIXED;
          }

          done = true;

          if (LOG.isDebugEnabled()) {
            if (i == 0) {
              LOG.debug("set bytesPerCRC=" + bytesPerCRC
                  + ", crcPerBlock=" + crcPerBlock);
            }
            LOG.debug("got reply from " + datanodes[j] + ": md5=" + md5);
          }
        } catch (InvalidBlockTokenException ibte) {
          if (i > lastRetriedIndex) {
            if (LOG.isDebugEnabled()) {
              LOG.debug("Got access token error in response to OP_BLOCK_CHECKSUM "
                  + "for file " + src + " for block " + block
                  + " from datanode " + datanodes[j]
                  + ". Will retry the block once.");
            }
            lastRetriedIndex = i;
            done = true; // actually it's not done; but we'll retry
            i--; // repeat at i-th block
            refetchBlocks = true;
            break;
          }
        } catch (IOException ie) {
          LOG.warn("src=" + src + ", datanodes["+j+"]=" + datanodes[j], ie);
        } finally {
          IOUtils.closeStream(in);
          IOUtils.closeStream(out);
        }
      }

      if (!done) {
        throw new IOException("Fail to get block MD5 for " + block);
      }
    }

    //compute file MD5
    final MD5Hash fileMD5 = MD5Hash.digest(md5out.getData()); 
    switch (crcType) {
      case CRC32:
        return new MD5MD5CRC32GzipFileChecksum(bytesPerCRC,
            crcPerBlock, fileMD5);
      case CRC32C:
        return new MD5MD5CRC32CastagnoliFileChecksum(bytesPerCRC,
            crcPerBlock, fileMD5);
      default:
        // If there is no block allocated for the file,
        // return one with the magic entry that matches what previous
        // hdfs versions return.
        if (locatedblocks.size() == 0) {
          return new MD5MD5CRC32GzipFileChecksum(0, 0, fileMD5);
        }

        // we should never get here since the validity was checked
        // when getCrcType() was called above.
        return null;
    }
  }

DataXceiver 计算Block Checksum

读取Block对应的meta文件内容,并计算其MD5值

  • 如果是整个Block校验,直接使用全部meta文件内容计算其MD5值
  • 如果是部分Block校验
  @Override
  public void blockChecksum(final ExtendedBlock block,
      final Token<BlockTokenIdentifier> blockToken) throws IOException {
    updateCurrentThreadName("Getting checksum for block " + block);
    final DataOutputStream out = new DataOutputStream(
        getOutputStream());
    checkAccess(out, true, block, blockToken,
        Op.BLOCK_CHECKSUM, BlockTokenSecretManager.AccessMode.READ);
    // client side now can specify a range of the block for checksum
    long requestLength = block.getNumBytes();
    Preconditions.checkArgument(requestLength >= 0);
    long visibleLength = datanode.data.getReplicaVisibleLength(block);
    boolean partialBlk = requestLength < visibleLength;

    final LengthInputStream metadataIn = datanode.data
        .getMetaDataInputStream(block);
    
    final DataInputStream checksumIn = new DataInputStream(
        new BufferedInputStream(metadataIn, HdfsConstants.IO_FILE_BUFFER_SIZE));
    try {
      //read metadata file
      final BlockMetadataHeader header = BlockMetadataHeader
          .readHeader(checksumIn);
      final DataChecksum checksum = header.getChecksum();
      final int csize = checksum.getChecksumSize();
      final int bytesPerCRC = checksum.getBytesPerChecksum();
      final long crcPerBlock = csize <= 0 ? 0 : 
        (metadataIn.getLength() - BlockMetadataHeader.getHeaderSize()) / csize;

      final MD5Hash md5 = partialBlk && crcPerBlock > 0 ? 
          calcPartialBlockChecksum(block, requestLength, checksum, checksumIn)
            : MD5Hash.digest(checksumIn);
      if (LOG.isDebugEnabled()) {
        LOG.debug("block=" + block + ", bytesPerCRC=" + bytesPerCRC
            + ", crcPerBlock=" + crcPerBlock + ", md5=" + md5);
      }

      //write reply
      BlockOpResponseProto.newBuilder()
        .setStatus(SUCCESS)
        .setChecksumResponse(OpBlockChecksumResponseProto.newBuilder()             
          .setBytesPerCrc(bytesPerCRC)
          .setCrcPerBlock(crcPerBlock)
          .setMd5(ByteString.copyFrom(md5.getDigest()))
          .setCrcType(PBHelper.convert(checksum.getChecksumType())))
        .build()
        .writeDelimitedTo(out);
      out.flush();
    } catch (IOException ioe) {
      LOG.info("blockChecksum " + block + " received exception " + ioe);
      incrDatanodeNetworkErrors();
      throw ioe;
    } finally {
      IOUtils.closeStream(out);
      IOUtils.closeStream(checksumIn);
      IOUtils.closeStream(metadataIn);
    }

    //update metrics
    datanode.metrics.addBlockChecksumOp(elapsed());
  }

读文件校验checksum

  /**
   * Open a DataInputStream to a DataNode so that it can be read from.
   * We get block ID and the IDs of the destinations at startup, from the namenode.
   */
  private synchronized DNAddrPair blockSeekTo(long target) throws IOException {
    if (target >= getFileLength()) {
      throw new IOException("Attempted to read past end of file");
    }

    // Will be getting a new BlockReader.
    closeCurrentBlockReader();

    //
    // Connect to best DataNode for desired Block, with potential offset
    //
    DatanodeInfo chosenNode = null;
    int refetchToken = 1; // only need to get a new access token once
    int refetchEncryptionKey = 1; // only need to get a new encryption key once
    
    boolean connectFailedOnce = false;

    while (true) {
      //
      // Compute desired block
      //
      LocatedBlock targetBlock = getBlockAt(target, true);
      assert (target==pos) : "Wrong postion " + pos + " expect " + target;
      long offsetIntoBlock = target - targetBlock.getStartOffset();

      DNAddrPair retval = chooseDataNode(targetBlock);
      chosenNode = retval.info;
      InetSocketAddress targetAddr = retval.addr;
      StorageType storageType = retval.storageType;

      long startCreateBlockReader = Time.monotonicNow(), setupConnectionSpan = 0;
      try {
        if (targetBlock.getLocations().length == 1) {
          dfsClient.getConf().effectSocketTimeout.set(dfsClient.getConf().socketTimeoutForEC);
        } else {
          dfsClient.getConf().effectSocketTimeout.set(dfsClient.getConf().socketTimeout);
        }
        ExtendedBlock blk = targetBlock.getBlock();
        Token<BlockTokenIdentifier> accessToken = targetBlock.getBlockToken();
        CachingStrategy curCachingStrategy;
        boolean shortCircuitForbidden;
        synchronized(infoLock) {
          curCachingStrategy = cachingStrategy;
          shortCircuitForbidden = shortCircuitForbidden();
        }
        blockReader = new BlockReaderFactory(dfsClient.getConf()).
            setInetSocketAddress(targetAddr).
            setRemotePeerFactory(dfsClient).
            setDatanodeInfo(chosenNode).
            setStorageType(storageType).
            setFileName(src).
            setBlock(blk).
            setBlockToken(accessToken).
            setStartOffset(offsetIntoBlock).
            setVerifyChecksum(verifyChecksum).
            setClientName(dfsClient.clientName).
            setLength(blk.getNumBytes() - offsetIntoBlock).
            setCachingStrategy(curCachingStrategy).
            setAllowShortCircuitLocalReads(!shortCircuitForbidden).
            setClientCacheContext(dfsClient.getClientContext()).
            setUserGroupInformation(dfsClient.ugi).
            setConfiguration(dfsClient.getConfiguration()).
            setTracer(dfsClient.getTracer()).
            setZoneLease(multiplexZoneLease).
            setZoneOppositeIdc(zoneOppositeIdc).
            setFailoverRemoteRead(retval.failoverRemoteRead).
            build();
        DFSClientFaultInjector.get().readFromDatanodeDelay();
        setupConnectionSpan = Time.monotonicNow() - startCreateBlockReader;
        addBlockReaderInfoAndReset(chosenNode, setupConnectionSpan);
        if(connectFailedOnce) {
          DFSClient.LOG.info("Successfully connected to " + targetAddr +
                             " for " + blk + ", scope:" + chosenNode.getScope());
        }
        return retval;
      } catch (IOException ex) {
        if (ex instanceof InvalidEncryptionKeyException && refetchEncryptionKey > 0) {
          DFSClient.LOG.info("Will fetch a new encryption key and retry, " 
              + "encryption key was invalid when connecting to " + targetAddr
              + " : " + ex);
          // The encryption key used is invalid.
          refetchEncryptionKey--;
          dfsClient.clearDataEncryptionKey();
        } else if (refetchToken > 0 && tokenRefetchNeeded(ex, targetAddr)) {
          refetchToken--;
          fetchBlockAt(target);
        } else {
          connectFailedOnce = true;
          DFSClient.LOG.warn("Failed to connect to " + targetAddr + " for block"
            + ", add to deadNodes and continue. " + ex, ex);
          // Put chosen node into dead list, continue
          ioExceptionHandler(targetBlock, chosenNode, null, ex);
        }
      } finally {
        if (setupConnectionSpan == 0)
          setupConnectionSpan = Time.monotonicNow() - startCreateBlockReader;
        dfsClient.stats.incrementReadSetupConnectionSpan(setupConnectionSpan);
      }
    }
  }

调用链如下:

1、readWithStrategy

        a、blockSeekTo(这一步会完成blockSender对象的创建)

blockReader = new BlockReaderFactory(dfsClient.getConf()).
    setInetSocketAddress(targetAddr).
    setRemotePeerFactory(dfsClient).
    setDatanodeInfo(chosenNode).
    setStorageType(storageType).
    setFileName(src).
    setBlock(blk).
    setBlockToken(accessToken).
    setStartOffset(offsetIntoBlock).
    setVerifyChecksum(verifyChecksum).
    setClientName(dfsClient.clientName).
    setLength(blk.getNumBytes() - offsetIntoBlock).
    setCachingStrategy(curCachingStrategy).
    setAllowShortCircuitLocalReads(!shortCircuitForbidden).
    setClientCacheContext(dfsClient.getClientContext()).
    setUserGroupInformation(dfsClient.ugi).
    setConfiguration(dfsClient.getConfiguration()).
    setTracer(dfsClient.getTracer()).
    setZoneLease(multiplexZoneLease).
    setZoneOppositeIdc(zoneOppositeIdc).
    setFailoverRemoteRead(retval.failoverRemoteRead).
build();

调用链如下:

build() ---> getRemoteBlockReaderFromDomain() ---> getRemoteBlockReader ---> RemoteBlockReader2.newBlockReader

        b、readBuffer(委托BlockReader对象读取数据)

在创建BlockReader对象后,client会调用BlockReader 对象的doRead()方法读取数据块。

Block、Chunk、Packet

1、block由一个个的chunk组成

2、每个chunk = checksum(4 Byte) + data(512 Byte),数据与检验值的比值为128:1,所以对于一个128M的block会有一个1M的校验文件与之对应。

3、多个chunk组成一个packet,packet = header + 所有校验块的校验和 + chunk

readWithStrategy --> readBuffer ---> reader.doRead --> blockReader.read(buf, off, len);--->

RemoteBlockReader2.read ---> readNextPacket

private void readNextPacket() throws IOException {
    //Read packet headers.
    packetReceiver.receiveNextPacket(in);

    PacketHeader curHeader = packetReceiver.getHeader();
    // 获取每个packet的data信息
    curDataSlice = packetReceiver.getDataSlice();
    assert curDataSlice.capacity() == curHeader.getDataLen();
    
    if (LOG.isTraceEnabled()) {
      LOG.trace("DFSClient readNextPacket got header " + curHeader);
    }

    // Sanity check the lengths
    if (!curHeader.sanityCheck(lastSeqNo)) {
         throw new IOException("BlockReader: error in packet header " +
                               curHeader);
    }
    
    if (curHeader.getDataLen() > 0) {
      int chunks = 1 + (curHeader.getDataLen() - 1) / bytesPerChecksum;
      int checksumsLen = chunks * checksumSize;

      assert packetReceiver.getChecksumSlice().capacity() == checksumsLen :
        "checksum slice capacity=" + packetReceiver.getChecksumSlice().capacity() + 
          " checksumsLen=" + checksumsLen;
      
      lastSeqNo = curHeader.getSeqno();
      if (verifyChecksum && curDataSlice.remaining() > 0) {
        // N.B.: the checksum error offset reported here is actually
        // relative to the start of the block, not the start of the file.
        // This is slightly misleading, but preserves the behavior from
        // the older BlockReader.
        checksum.verifyChunkedSums(curDataSlice,
            packetReceiver.getChecksumSlice(),
            filename, curHeader.getOffsetInBlock());
      }
      bytesNeededToFinish -= curHeader.getDataLen();
    }    
    
    // First packet will include some data prior to the first byte
    // the user requested. Skip it.
    if (curHeader.getOffsetInBlock() < startOffset) {
      int newPos = (int) (startOffset - curHeader.getOffsetInBlock());
      curDataSlice.position(newPos);
    }

    // If we've now satisfied the whole client read, read one last packet
    // header, which should be empty
    if (bytesNeededToFinish <= 0) {
      readTrailingEmptyPacket();
      DFSClientFaultInjector.get().sleepForDatanodeReadTimeout();
      if (verifyChecksum) {
        sendReadResult(Status.CHECKSUM_OK);
      } else {
        sendReadResult(Status.SUCCESS);
      }
    }
  }

HDFS源码分析DataXceiver之读数据块 在《HDFS源码分析DataXceiver之整体流程》一文中我们知道,无论来自客户端还是其他数据节点的请求达到DataNode时,DataNode上的后台线程DataXceiverServer均为每个请求创建一个单独的后台工作线程来处理,这个工作线程就是DataXceiver。并且,在线程DataXceiver处理请求的主方法run()方法内,会先读取操作符op,然后根据操作符op分别调用相应的方法进行请求的处理。而决定什么样的操作符op该调用何种方法的逻辑,则是在DataXceiver线程父类Receiv 阅读详情

相关推荐

Hhadoop-2.7.0中HDFS写文件源码分析(二):客户端实现之DFSPacket

一、简介      HDFS在数据传输过程中,针对数据块Block,不是整个block进行传输的,而是将block切分成一个个的数据包进行传输。而DFSPacket就是HDFS数据传输过程中对数据包的抽象。二、实现      HDFS客户端在往DataNodes节点写数据时,会以数据包packet的形式写入,且每个数据包包含一个包头,n个连续的校验和数据块checksum chunks和n个连续的

辰辰爸的博客 3336

Hadoop数据完整性与CheckSum校验原理

一、HDFS数据完整性 用户肯定都希望系统在存储和处理数据时,数据不会有任何丢失或损坏。但是,受网络不稳定、硬件损坏等因素,IO操作过程中难免会出现数据丢失或脏数据,难免会出现数据丢失或脏数据,数据传输的量越大,出现错误的概率就越高。 检测数据是否损坏的常见措施是,在数据第一次引入系统时计算校验和(checksum)并存储,在数据进行传输后再次计算校验和进行对比,如果计算所得的新校验和和原来的...

雾幻的博客 1万+

hadoop深入研究:(六)——HDFS数据完整性

转载请注明出处:hadoop深入研究:(六)——HDFS数据完整性数据完整性 IO操作过程中难免会出现数据丢失或脏数据,数据传输得量越大出错得几率越高。校验错误最常用得办法就是传输前计算一个校验和,传输后计算一个校验和,两个校验和如果不相同就说明数据存在错误,比较常用得错误校验码是CRC32.hdfs数据完整性 hdfs写入的时候计算出校验和,然后每次读的时候再计算校验和。要注意的一点是,hdfs

独自登高楼 望断天涯路 1万+

checksum和compression—— Hadoop权威指南7

1. Hadoop文件系统的数据完整性 1.1 关于checksum 学习计算机组成原理什么的,一般都会提到数据校验以保证数据的完整性 检测数据是否损坏的常见操作: 数据第一次写入系统时,对数据计算校验和(checksum),数据和checksum一起存入系统 之后读取数据时,重新计算数据的checksum,将计算出来的checksum与系统存储的checksum做比较 如果checksum不一致,则认为数据已损坏 计算checksum只能检查数据是否损坏,并不能修复数据 目前,常用的错误校验码是

lucyLee的博客 2102

MD5Checksum(MD5值校验工具)V4.1简体中文版.rar

软件介绍: MD5Checksum能够校验并计算文件的哈希值,显示文件大小,SHA1/SHA256/SHA384/SHA512校验值。支持文件校验,选择文件并校验。通过比较MD5值来判断两个文件的差异是否完全相同。可添加到资源管理器上下文菜单。语言切换说明:点击菜单Settings-->language-->Chinese simplified

企业数字化转型的 4A 架构指南:从概念解读到 TOGAF 阶段对应

4A企业架构是中国数字化转型实践中总结的简化框架,包含业务、应用、数据和技术四个架构层。它自上而下形成业务驱动应用的指导关系,自下而上构建技术支撑数据的实现路径,与国际标准TOGAF核心内容高度对应。该模型通过统一语言、战略对齐和系统梳理,有效连接业务需求与IT实施,已成为企业架构规划的实用工具。其分层结构清晰展示了从业务目标到技术落地的完整推导链,特别适合中国企业的数字化转型场景。

友莘居士的博客 2174

HDFS CheckSum

程序入口 Hadoop Branch : Hadoop-2.6.0 使用样例 : hadoop dfs -checksum /tmp/README.txt 结果 /tmp/README.txt MD5-of-0MD5-of-512CRC32C 00000200000000000000000017970719be16d1071635fa381b95f957 算法说明: “MD5-of-” ...

半日闲的博客 4190

PPO实战:如何用强化学习让小车爬上MountainCarContinuous-v0山顶(附完整代码)

本文提供了使用PPO算法解决MountainCarContinuous-v0环境的完整实战教程。针对该环境的连续动作空间和稀疏奖励挑战,文章详细解析了PPO智能体的网络架构、状态归一化、GAE优势估计等核心实现,并附带了可直接运行的PyTorch代码。同时分享了关键的调参技巧和实战避坑指南,帮助读者高效训练智能体完成小车爬坡任务。

linux的博客 967

hdfs中CheckSum

从DataNode获取的数据块可能已损坏。由于存储设备中的故障,网络故障或有缺陷的软件,可能会发生此损坏。HDFS客户端软件对HDFS文件的内容进行校验和检查。当客户端创建HDFS文件时,它会计算文件每个块的校验和,并将这些校验和存储在同一HDFS命名空间中的单独隐藏文件中。当客户端检索文件内容时,它会验证从每个DataNode接收的数据是否与存储在关联校验和文件中的校验和相匹配。如果不是,则客...

Dimples. 774

Mamba与iTransformer融合:时间序列预测中的曼巴注意力机制创新实践

本文探讨了Mamba与iTransformer融合在时间序列预测中的创新实践,重点介绍了曼巴注意力机制的设计与优势。通过双路径信息流设计,该方案在保持O(n)复杂度的同时,显著提升了预测精度和训练效率。实验证明,混合架构在电力负荷、气象数据等多变量长序列场景中表现优异,预测误差降低至0.083,内存占用仅4.2GB。

weixin_29292535的博客 219

STM32H743IIT6+USB3300高速HID通讯实战:从CUBEMX配置到调试避坑全记录

本文详细记录了基于STM32H743IIT6微控制器与USB3300 PHY芯片实现高速USB HID通信的完整实战过程。内容涵盖从硬件选型、STM32CubeMX工程配置(重点规避引脚映射等常见陷阱)、自定义报告描述符编写,到驱动层数据收发实现与高级调试技巧的全链路解析,旨在帮助开发者快速构建稳定、高效的嵌入式高速数据通道。

vscode5coder的博客 362

HDFS底层原理深度解析 | 读写流程、NameNode工作机制、DataNode心跳与数据完整性

HDFS 底层原理深度解析

记录学习点滴,分享实战干货,一起奔赴技术之路 496

Git系列(一)、Git基础教程【建议收藏】

Git一、Git简介1.1、什么是Git? 一、Git简介 1.1、什么是Git? Git是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或大或小的项目。 Git是Linus Torvalds为了帮助管理Linux内核开发而开发的一个开放源代码的版本控制软件。 Git与常用的版本控制工具CVS、Subversion等不同,它采用了分布式版本库的方式,不用服务器端软件支持。 .........

一宿君 4万+

Hadoop3.2.1 【 HDFS 】源码分析 : DataXceiver: 读取数据块 解析 [二]

一. 前言 Receiver.processOp()方法用于处理流式接口的请求, 它首先从数据流中读取序列化后的参数, 对参数反序列化, 然后根据操作码调用DataTransferProtocol中定义的方法, 这些方法都是在DataXceiver中具体实现的。 流式接口中最重要的一个部分就是客户端从数据节点上读取数据块, DataTransferProtocol.readBlock()给出了读取操作的接口定义, 操作码是81。 DataXceiver.readBlock()则实现了DataTransfer

张伯毅的专栏 7325

【电源专题】Type-C母座外壳直接接主板GND还是接RC呢?别再纠结了!

Type-C屏蔽壳接地这件事,没有唯一标准答案。符合规范、贴合产品、能过认证,就是最优解。希望这篇文章能帮你理清思路。

一点硬件 592

【蒸汽幻想台服新版商业端】2025最新整理单机一键即玩镜像端+WIN系半手工端+PC客户端+网页注册+网页管理后台+教程【站长亲测】

MMORPG端游【蒸汽幻想台服新版商业端】2025最新整理单机一键即玩镜像端+WIN系半手工端+PC客户端+网页注册+网页管理后台+教程。

百创科技 531

HDFS Java API源码探秘:一次文件上传,背后DataStreamer和NameNode都聊了啥?

本文深入解析HDFS Java API中文件上传的底层机制,揭示DataStreamer与NameNode的协作细节。通过源码分析,展示从客户端RPC调用到数据管道建立的全过程,包括元数据管理、数据可靠性保障及性能优化技巧,帮助开发者深入理解HDFS分布式文件系统的核心工作原理。

weixin_30376509的博客 680

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

八、HDFS中的DataNode

上篇博客介绍了HDFS中的NameNode和SecondaryNameNode,本篇主要介绍HDFS中的DataNode,关注专栏《from zero to hero(Hadoop篇)》查看相关系列的文章~ 一、DataNode的工作机制 (1)一个数据块在DataNode上以文件形式存储在磁盘上,包括两个文件:一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和,以及时间戳。(2)DataNode启动后向NameNode注册,通过后,周期性(1小时)的向NameNo...

象在舞的技术专栏 1454

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

hadoop源码 - HDFS的文件操作流 写操作(客户端)

在前面的博文中我主要从客户端的角度讲述了HDFS文件写操作的工作流程,但是关于客户端是如何把数据块传送到数据节点,同时数据节点又是如何来接受来自客户端的数据块呢?这就是本文将要讨论的。     在客户端负责数据写入处理的核心类是DFSOutputStream,它的内部主要有数据包发送器DataStream、数据包确认处理器ResponseProcessor和数据包封装器Packet,其整体设计架

Mrknowledge 1470

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

HDFS源码分析(5):datanode数据块的读与写DataXceiver

前提 Hadoop版本:hadoop-0.20.2 概述 现在已经知道datanode是通过DataXceiver来处理客户端和其它datanode的请求,在分析DataXceiver时已经对除数据块的读与写之外的操作进行了说明,本文主要分析比较复杂而且非常重要的两个操作:读与写。对于用户而言,HDFS用得最多的两个操作就是写和读文件,而且在大部分情况下,是一次写入,多次读取,满

linuxheik的专栏 842

HDFS磁盘故障处理与容错机制深度解析

在分布式存储系统中,磁盘故障是不可避免的常见问题,HDFS作为主流分布式文件系统,其容错机制设计尤为关键。从技术原理上看,HDFS通过多副本机制和纠删码(EC)技术实现数据冗余,其中EC编码基于数学算法允许部分数据块丢失后仍可恢复。工程实践中,有效的磁盘健康监控体系需要采集SMART指标、IO延迟等多层数据,结合慢磁盘识别算法实现早期预警。针对HDFS特有的故障场景,优化副本放置策略和恢复资源调度能显著提升系统可用性。这些技术在金融、电信等行业的大数据平台中有广泛应用,特别是在处理PB级数据存储时,良好的故

weixin_34007020的博客 315

libhdfs源码分析(4)

我们再来分析一下写数据流程 1. 由前可知DistributedFileSystem::create和DistributedFileSystem::append方法都会返回FSDataOutputStream对象,而其实返回的都是FSDataOutputStream的子类DFSClient::DFSOutputStream 2. 当我们调用write时,其实我们调用的是DFSOutpu

vinowan的专栏 699

HDFS源码分析2:Datanode通信分析

目录 Op线程 写在前面 第一个包: 后续的包 ReadBlock: WriteBlock: Datanode本质上也是TCPServer,一般的TCPServer接到客户端请求以后会分配一个线程处理,对于Datanode而言,这个线程可以叫做Op处理线程。每个OP线程会多次和客户端交互,中间涉及多种packet。 Op线程 写在前面 写在前面,关于proto writeDelimitedTo方法 在整个处理流程中,会非常频繁的使用的到proto.writeDelimitedTo来传递

行路中 397
上一篇: HDFS源码解析---读数据流程
下一篇: HDFS源码解析---HA
请叫我算术嘉
博客等级 码龄11年 393粉丝 385原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值