HDFS源碼解析(三)

本人博客針對的是hadoop2版本,比1版本略爲複雜(採用了很多當下流行的設計模式,加入了新的序列化框架,ha配置,聯邦特性,yarn框架,以及採用maven的工程劃分結構等)。網上的源碼分析大多針對的是1版本,由於是針對源碼寫出自己的理解,難免有錯誤或不當的地方,歡迎指正

前面兩篇主要講了namenode,現在來說說datanode。好了,直接打開idea,進入DataNode

首先我來翻譯一下注釋(有些是自己添加的):

/**********************************************************
 * DataNode is a class (and program) that stores a set of
 * blocks for a DFS deployment.  A single deployment can
 * have one or many DataNodes.  Each DataNode communicates
 * regularly with a single NameNode.  It also communicates
 * with client code and other DataNodes from time to time.
 *datanode是DFS調度存儲一系列數據塊的一個類或者說是程序。DFS調度可以有1個或多個數據節點。
 * 每個數據節點定期和唯一的namenode進行通信。有時它也和客戶端或其他的數據節點通信。
 *
 * DataNodes store a series of named blocks.  The DataNode
 * allows client code to read these blocks, or to write new
 * block data.  The DataNode may also, in response to instructions
 * from its NameNode, delete blocks or copy blocks to/from other
 * DataNodes.
 *數據節點存儲一系列命名數據塊。它允許客戶端讀寫或者創建新的數據塊。而且,
 * 它還會執行來自namenode的刪除數據塊,拷貝或複製其他節點上的數據塊的指令,
 * 當然了,這些指令是通過心跳的的響應時傳達的
 *
 * The DataNode maintains just one critical table:
 *   block-> stream of bytes (of BLOCK_SIZE or less)
 *數據節點保存了極其重要的一張表:數據塊到字節流的映射
 *
 * This info is stored on a local disk.  The DataNode
 * reports the table's contents to the NameNode upon startup
 * and every so often afterwards.
 *這個信息保存在本地磁盤上,數據節點在啓動,以後定期把這些內容上報給namenode
 * 這就是前面文章中說的第三種元數據是由數據節點上報動態建立的
 *
 * DataNodes spend their lives in an endless loop of asking
 * the NameNode for something to do.  A NameNode cannot connect
 * to a DataNode directly; a NameNode simply returns values from
 * functions invoked by a DataNode.
 *datanode是一個死循環並一直詢問namenode有什麼事吩咐。namenode不可以直接連接datanode,
 *它只能通過datanode的請求函數中返回值
 *
 * DataNodes maintain an open server socket so that client code 
 * or other DataNodes can read/write data.  The host/port for
 * this server is reported to the NameNode, which then sends that
 * information to clients or other DataNodes that might be interested.
 *數據節點保持一個打開的套接字供客戶端和其他數據節點讀寫數據。當前的主機名,
 * 端口要上報給namenode,然後namenode再發給其他感興趣的客戶端或數據節點
 *
 **********************************************************/

接着,同namenode分析思路,直接進入main方法

public static void main(String args[]) {
    if (DFSUtil.parseHelpArgument(args, DataNode.USAGE, System.out, true)) { // 在namenode中見過吧,解析命令行參數,其實在hadoop1中是沒有這個if判斷的
      System.exit(0);
    }

    secureMain(args, null);
  }
public static void secureMain(String args[], SecureResources resources) {
    int errorCode = 0;
    try {
      StringUtils.startupShutdownMessage(DataNode.class, args, LOG); // 打印啓動關閉信息
      DataNode datanode = createDataNode(args, null, resources); 
// 看到沒,跟namenode一個編碼思路,
// 創建datanode時會調用instantiateDataNode方法,進行初始化配置信息,權限設置。
// 在hadoop1裏面有行代碼是
// String[] dataDirs = conf.getStrings(DATA_DIR_KEY);而在hadoop2裏面是
// Collection<StorageLocation> dataLocations = getStorageLocations(conf);
// hadoop2對其做了下封裝,顯得更規範。java你懂得,
// 不抽出點接口、進行點包裝顯示不出自己的逼格。其實就是獲取數據存儲目錄。
	if (datanode != null) {
        datanode.join();
 // 還記得namenode中是啓動兩大rpcserver嗎,下面詳細解析join方法
      } else {
        errorCode = 1;
      }
    } catch (Throwable e) {
      LOG.fatal("Exception in secureMain", e);
      terminate(1, e);
    } finally {
      // We need to terminate the process here because either shutdown was called
      // or some disk related conditions like volumes tolerated or volumes required
      // condition was not met. Also, In secure mode, control will go to Jsvc
      // and Datanode process hangs if it does not exit.
      LOG.warn("Exiting Datanode");
      terminate(errorCode);
    }
  }

在createDataNode中,你還會看到runDatanodeDaemon方法

  public void runDatanodeDaemon() throws IOException {
    blockPoolManager.startAll();

    // start dataXceiveServer
    // DataXceiverServer類是DataNode的輔助類,
    // 它最主要是用來實現客戶端或其他數據節點與當前節點通信,
    // 並負責接收/發送數據塊。這個類的創建是爲了監聽來自客戶端或其他數據節點的請求。
    // 它的實現通信的方法不是用hadoop IPC,而是用jdk本身就有的ServerSocket。
    // DataXceiverServer是一個簡單的tcp socket server, 監聽特定的端口,
    // 持有一個單獨的線程,不斷調用accept,如果有請求過來,
    // 就創建一個DataXceiver線程並啓動,進行處理
    dataXceiverServer.start();
    if (localDataXceiverServer != null) {
      localDataXceiverServer.start();
    }
    ipcServer.start();
    startPlugins(conf);
  }

在datanode.join中有吊用下面的join方法

 void join() {
    while (shouldRun) {
      try {
        // BlockPoolManager類提供管理BlockPool的相關API,在hadoop2中允許存在多個namespace
        // 其中,BPOfferService爲每個Namespace下每個BlockPool一個實例,
        // 提供BlockPool對它所對應的Namespace的操作的相關API,
        // BPOfferService爲指定Namespace中每個namenode一個實例,
        // 自已持有線程,定時向它所對應的namenode發heartbeat, blockreport,
        // 並執行namenode通過heartbeat/blockreport response傳回來的command
        blockPoolManager.joinAll();
        if (blockPoolManager.getAllNamenodeThreads() != null
            && blockPoolManager.getAllNamenodeThreads().length == 0) {
          shouldRun = false;
        }
        // Terminate if shutdown is complete or 2 seconds after all BPs
        // are shutdown.
        synchronized(this) {
          wait(2000);
        }
      } catch (InterruptedException ex) {
        LOG.warn("Received exception in Datanode#join: " + ex);
      }
    }
  }

在datanode類中還有DataBlockScanner線程,類型爲volatile 。

(Java語言中的 volatile 變量可以被看作是一種 “程度較輕的 synchronized”,目前還挺有爭議的。)

DataBlockScanner的主要功能是掃描並校驗磁盤上的data block, 把發現的壞塊報告給namenode. 

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