HDFS 07 - HDFS 效能調優之 合併小檔案

瘦風發表於2021-06-20

1 - 為什麼要合併小檔案

HDFS 擅長儲存大檔案

我們知道,HDFS 中,每個檔案都有各自的後設資料資訊,如果 HDFS 中有大量的小檔案,就會導致後設資料爆炸,叢集管理的後設資料的記憶體壓力會非常大。

所以在專案中,把小檔案合併成大檔案,是一種很有用也很常見的優化方法。

2 - 合併本地的小檔案,上傳到 HDFS

將本地的多個小檔案,上傳到 HDFS,可以通過 HDFS 客戶端的 appendToFile 命令對小檔案進行合併。

在本地準備2個小檔案:

# user1.txt 內容如下:
1,tom,male,16
2,jerry,male,10

# user2.txt 內容如下:
101,jack,male,19
102,rose,female,18

合併方式:

hdfs dfs -appendToFile user1.txt user2.txt /test/upload/merged_user.txt

合併後的檔案內容:

HDFS 07 - HDFS 效能調優之 合併小檔案

3 - 合併 HDFS 的小檔案,下載到本地

可以通過 HDFS 客戶端的 getmerge 命令,將很多小檔案合併成一個大檔案,然後下載到本地。

# 先上傳小檔案到 HDFS:
hdfs dfs -put user1.txt user2.txt /test/upload
# 下載,同時合併:
hdfs dfs -getmerge /test/upload/user*.txt ./merged_user.txt

下載、合併後的檔案內容:

HDFS 07 - HDFS 效能調優之 合併小檔案

4 - 通過 Java API 實現檔案合併和上傳

程式碼如下(具體測試專案,可到 我的 GitHub 檢視):

@Test
public void testMergeFile() throws Exception {
    // 獲取分散式檔案系統
    FileSystem fileSystem = FileSystem.get(new URI("hdfs://hadoop:9000"), new Configuration(), "healchow");
    FSDataOutputStream outputStream = fileSystem.create(new Path("/test/upload/merged_by_java.txt"));
    // 獲取本地檔案系統
    LocalFileSystem local = FileSystem.getLocal(new Configuration());
    // 通過本地檔案系統獲取檔案列表,這裡必須指定路徑
    FileStatus[] fileStatuses = local.listStatus(new Path("file:/Users/healchow/bigdata/test"));
    for (FileStatus fileStatus : fileStatuses) {
        // 建立輸入流,操作完即關閉
        if (fileStatus.getPath().getName().contains("user")) {
            FSDataInputStream inputStream = local.open(fileStatus.getPath());
            IOUtils.copy(inputStream, outputStream);
            IOUtils.closeQuietly(inputStream);
        }
    }

    // 關閉輸出流和檔案系統
    IOUtils.closeQuietly(outputStream);
    local.close();
    fileSystem.close();
}

合併的結果,和通過命令合併的完全一致:

HDFS 07 - HDFS 效能調優之 合併小檔案

版權宣告

作者:瘦風(https://healchow.com)

出處:部落格園-瘦風的南牆(https://www.cnblogs.com/shoufeng)

感謝閱讀,公眾號 「瘦風的南牆」 ,手機端閱讀更佳,還有其他福利和心得輸出,歡迎掃碼關注?

本文版權歸博主所有,歡迎轉載,但 [必須在頁面明顯位置標明原文連結],否則博主保留追究相關人士法律責任的權利。

相關文章