HDFS源碼解析(二)

上一篇講到了namenode的格式化,格式化方法中有

FSImage fsImage = new FSImage(conf, nameDirsToFormat, editDirsToFormat);
    try {
      FSNamesystem fsn = new FSNamesystem(conf, fsImage);

今天主要講講FSImage ,FSNamesystem 分別在(1),(2)中

(1)先來看FSImageFSImage處理checkpointing(檢查點),並記錄到文件命名空間編輯日誌中。

fsimage在磁盤上對應上一篇文章提到的/home/hadoop/dfs/name路徑。目錄下有currentimagein_use.lock;在current目錄下有edits日誌,fsimage內存鏡像,fstime鏡像時間,VERSION版本信息。

FSImage常用操作有loadFSImage(加載文件系統鏡像),saveFSImage(保存文件系統鏡像)

在loadFSImage中,最終會調用FSImageFormat類中的load(File curFile)方法,代碼如下:

public void load(File curFile) throws IOException {
      checkNotLoaded(); // 保證是第一次加載時執行下面的語句
      assert curFile != null : "curFile is null"; // 斷言

      StartupProgress prog = NameNode.getStartupProgress(); // 獲取啓動進度
      Step step = new Step(StepType.INODES);
      prog.beginStep(Phase.LOADING_FSIMAGE, step);
      long startTime = now(); // 開始

      //
      // Load in bits
      //
      MessageDigest digester = MD5Hash.getDigester();
      DigestInputStream fin = new DigestInputStream(
           new FileInputStream(curFile), digester); // 獲取輸入流

      DataInputStream in = new DataInputStream(fin); // 包裝輸入流
      try {
        // read image version: first appeared in version -1
        int imgVersion = in.readInt(); // 讀取鏡像版本號
        if (getLayoutVersion() != imgVersion) { // 判斷版本是否一致,不一致拋異常
          throw new InconsistentFSStateException(curFile, 
              "imgVersion " + imgVersion +
              " expected to be " + getLayoutVersion());
        }
        boolean supportSnapshot = NameNodeLayoutVersion.supports( // 判斷是否支持快照
            LayoutVersion.Feature.SNAPSHOT, imgVersion);
        if (NameNodeLayoutVersion.supports(
            LayoutVersion.Feature.ADD_LAYOUT_FLAGS, imgVersion)) {
          LayoutFlags.read(in);
        }

        // read namespaceID: first appeared in version -2
        in.readInt(); // 讀取命名空間編號

        long numFiles = in.readLong(); // 文件數量
<span style="white-space:pre">	</span>......
在saveFSImage中,最終調用FSImageFormatProtobuf中save(File file, FSImageCompression compression)方法,代碼如下

void save(File file, FSImageCompression compression) throws IOException {
      FileOutputStream fout = new FileOutputStream(file); // 創建輸出流
      fileChannel = fout.getChannel(); // 獲取網絡套接字的通道,用過java nio的朋友應該清楚
      try {
        saveInternal(fout, compression, file.getAbsolutePath().toString()); // 在該方法中,underlyingOutputStream.write(FSImageUtil.MAGIC_HEADER)進行持久化操作
      } finally {
        fout.close();
      }
    }
(2)對於hadoop集羣,master節點存儲3種類型元數據:文件和數據塊的命名空間,文件和數據塊的對應關係,每個數據塊副本的存放地點。所有的元數據都保存在內存中,前兩種類型也會以記錄變更日誌的方式記錄在系統日誌文件中。

文件系統的存儲和管理都交給了FSNameSystem類,我們就看看他的註釋:

/***************************************************
 * FSNamesystem does the actual bookkeeping work for the // 此類爲datanode做實際的簿記工作
 * DataNode.
 *
 * It tracks several important tables.
 *
 * 1)  valid fsname --> blocklist  (kept on disk, logged) // 文件系統命名空間到數據塊列表的映射,保存在磁盤上並記錄日誌
 * 2)  Set of all valid blocks (inverted #1) // 合法數據塊集合,上面的逆關係
 * 3)  block --> machinelist (kept in memory, rebuilt dynamically from reports) // 數據塊到datanode的映射,保存在內存中,由datanode上報動態重建
 * 4)  machine --> blocklist (inverted #2) // datanode上保存的數據塊列表,上面的逆關係
 * 5)  LRU cache of updated-heartbeat machines 近期最少使用緩存隊列,保存datanode的心跳信息
 ***************************************************/


FSNamesystem 有一個FSDirectory成員變量,它保存文件名到數據塊列表的映射,類中有添加文命名空間,添加文件,添加數據塊,創建目錄等操作。

下面是數據塊相關的方法

  @Override // FSNamesystemMBean
  @Metric
  public long getPendingReplicationBlocks() { // 返回正在複製的數據塊
    return blockManager.getPendingReplicationBlocksCount();
  }

  @Override // FSNamesystemMBean
  @Metric
  public long getUnderReplicatedBlocks() { // 返回需要複製的數據塊
    return blockManager.getUnderReplicatedBlocksCount();
  }

  /** Returns number of blocks with corrupt replicas */
  @Metric({"CorruptBlocks", "Number of blocks with corrupt replicas"})
  public long getCorruptReplicaBlocks() { // 返回損壞的數據塊
    return blockManager.getCorruptReplicaBlocksCount();
  }

  @Override // FSNamesystemMBean
  @Metric
  public long getScheduledReplicationBlocks() { // 返回當前正在處理的數據塊複製數目
    return blockManager.getScheduledReplicationBlocksCount();
  }

  @Override
  @Metric
  public long getPendingDeletionBlocks() { // 返回正在刪除的數據塊數目
    return blockManager.getPendingDeletionBlocksCount();
  }

  @Metric
  public long getExcessBlocks() { // 返回超過配額的數據塊數目
    return blockManager.getExcessBlocksCount();
  }
  
  // HA-only metric
  @Metric
  public long getPostponedMisreplicatedBlocks() { // 返回延期或錯過複製的數據塊數目,僅在ha的情況下
    return blockManager.getPostponedMisreplicatedBlocksCount();
  }


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章