Fenriswolf 程式筆記

奮利斯狼的地盤,小綿羊勿入

用 Offline Image Viewer 分析 Hadoop Namespace

Hadoop 用 fsimage 來儲存整個 namespace,但 fsimage 是 binary 格式,很難讓系統管理者分析這個檔案。Offline Image Viewer 是 Hadoop 0.21 新增的功能,可以幫使用者把 fsimage 轉成不同的文字格式以方便做分析。如同字面所顯示,這個工具是離線操作的,也就是不需要啟動 Hadoop cluster。

使用 Offline Image Viewer (以下簡稱 OIV) 主要有兩個方向

  • 從系統管理的角度,在做 Hadoop 維護或升級等重要操作時一定要備份 fsimage 和 editlog 檔案。但問題是怎麼確定備份有成功? 以前可能會用 checksum 的機制來保証檔案的正確性。現在可以用 OIV 來達成這個目的。
    如果讀入一個壞掉的的 fsimage 檔案會有以下的錯誤訊息

    [root@hadoop-master current]# hdfs oiv -i fsimage_0000000000000000156 -o fsimage.txt 
    Input ended unexpectedly.
    12/12/09 11:47:55 ERROR offlineImageViewer.OfflineImageViewer: image loading failed at offset 1645
    Input file ended unexpectedly.  Exiting
    

    補充說明: fsimage checksum 的機制已經內建在 Hadoop 0.23 裡了,可以用以下指令檢查 fsimage

    md5sum -c fsimage_0000000000000000156.md5
    
  • 管理一個大的 Hadoop cluster 不容易,在初期規劃不可能考慮所有的面向,需要後續觀查 Hadoop 的使用狀況才能做調整。後面會列幾個案例。

 
1. 匯出 fsimage 檔案
使用方式如下

hdfs oiv [OPTIONS] -i INPUTFILE -o OUTPUTFILE -p PROCESSOR

要注意的是,不是所有資訊都會及時寫入 fsimage,有些可能還在 editlog 裡,因此會有一些時間差。至於差多久就要看 Checkpoint Node(舊版稱 Secondary NameNode) 裡 dfs.namenode.checkpoint.period 的設定,預設是一小時。如果希望讀到所有的資訊就要先進入 safemode,再執行 saveNamespace 的指令

hdfs dfsadmin -safemode enter
hdfs dfsadmin -saveNamespace

OIV 提供六種不同的輸出格式(processor)

  • Ls:
    預設的格式,如果不加 -p 參數就會以這種格式輸出
    指令

    hdfs oiv -i fsimage_0000000000000000156 -o fsimage.txt

    範例

    drwxr-xr-x  -     hdfs supergroup          0 2012-12-05 08:59 /
    drwxrwxrwt  -     hdfs       hdfs          0 2012-12-05 08:57 /tmp
    drwxr-xr-x  -     hdfs supergroup          0 2012-12-05 08:59 /user
    -rw-r--r--  3 fenriswolf fenriswolf      16539 2012-11-06 12:58 /user/fenriswolf/hadoop-annotations-2.0.0-cdh4.1.2.jar
    -rw-r--r--  3 fenriswolf fenriswolf      45332 2012-11-06 12:58 /user/fenriswolf/hadoop-auth-2.0.0-cdh4.1.2.jar
    -rw-r--r--  3 fenriswolf fenriswolf    1160874 2012-11-06 12:58 /user/fenriswolf/hadoop-common-2.0.0-cdh4.1.2-tests.jar
    -rw-r--r--  3 fenriswolf fenriswolf    2234642 2012-11-06 12:58 /user/fenriswolf/hadoop-common-2.0.0-cdh4.1.2.jar
    

    這種格式跟直接執行 hdfs dfs -ls -R 的效果一樣,差別只在根目錄也會被包含進去。另外檔案排序的方式不是以名稱,而是以存入的時間

  •  

  • Delimited:
    指令

    hdfs oiv -i fsimage_0000000000000000156 -o fsimage.tsv -p Delimited
    

    範例

    /       0       2012-12-05 08:59        1970-01-01 08:00        0       -1      0       2147483647      -1      rwxr-xr-x       hdfs    supergroup
    /tmp    0       2012-12-05 08:57        1970-01-01 08:00        0       -1      0       -1      -1      rwxrwxrwt       hdfs    hdfs
    /user   0       2012-12-05 08:59        1970-01-01 08:00        0       -1      0       -1      -1      rwxr-xr-x       hdfs    supergroup
    /user/fenriswolf/hadoop-annotations-2.0.0-cdh4.1.2.jar  3       2012-11-06 12:58        2012-11-06 12:58        134217728       1       16539   -1      -1      rw-r--r--       fenriswolf      fenriswolf
    /user/fenriswolf/hadoop-auth-2.0.0-cdh4.1.2.jar 3       2012-11-06 12:58        2012-11-06 12:58        134217728       1       45332   -1      -1      rw-r--r--       fenriswolf      fenriswolf
    /user/fenriswolf/hadoop-common-2.0.0-cdh4.1.2-tests.jar 3       2012-11-06 12:58        2012-11-06 12:58        134217728       1       1160874 -1      -1      rw-r--r--       fenriswolf      fenriswolf
    /user/fenriswolf/hadoop-common-2.0.0-cdh4.1.2.jar       3       2012-11-06 12:58        2012-11-06 12:58        134217728       1       2234642 -1      -1      rw-r--r--       fenriswolf      fenriswolf
    

    產生 tsv 格式的檔案。這比 Ls 好的地方在於欄位是以 tab 為分隔比較容易解析,而且顯示的欄位多很多。例如存取時間、Name Quotas、Space Quotas 等等。以前需要用 hadoop fs -count 才能看到 quota 的設定,用這個方式就一目了然。官方網站就是用 Pig 分析這個格式。

  •  

  • Indented:
    指令

    hdfs oiv -i fsimage_0000000000000000156 -o fsimage.txt -p Indented
    

    範例

    FS_IMAGE
      IMAGE_VERSION = -40
      NAMESPACE_ID = 610917725
      GENERATION_STAMP = 1022
      TRANSACTION_ID = 156
      IS_COMPRESSED = -40
      INODES [NUM_INODES = 17]
        INODE
          INODE_PATH = /
          REPLICATION = 0
          MODIFICATION_TIME = 2012-12-05 08:59
          ACCESS_TIME = 1970-01-01 08:00
          BLOCK_SIZE = 0
          BLOCKS [NUM_BLOCKS = -1]
          NS_QUOTA = 2147483647
          DS_QUOTA = -1
          PERMISSIONS
            USER_NAME = hdfs
            GROUP_NAME = supergroup
            PERMISSION_STRING = rwxr-xr-x
      INODES_UNDER_CONSTRUCTION [NUM_INODES_UNDER_CONSTRUCTION = 0]
      CURRENT_DELEGATION_KEY_ID = 0
      DELEGATION_KEYS [NUM_DELEGATION_KEYS = 0]
      DELEGATION_TOKEN_SEQUENCE_NUMBER = 0
      DELEGATION_TOKENS [NUM_DELEGATION_TOKENS = 0]
    

    用縮排的方式顯示,跟 Delimited 一樣可看到每個目錄及檔案的資訊,還多了 fsimage 的表頭及表尾。

  •  

  • XML:
    指令

    hdfs oiv -i fsimage_0000000000000000156 -o fsimage.xml -p XML
    

    範例

    <?xml version="1.0" ?>
    <FS_IMAGE>
    	<IMAGE_VERSION>-40</IMAGE_VERSION>
    	<NAMESPACE_ID>610917725</NAMESPACE_ID>
    	<GENERATION_STAMP>1022</GENERATION_STAMP>
    	<TRANSACTION_ID>156</TRANSACTION_ID>
    	<IS_COMPRESSED>-40</IS_COMPRESSED>
    	<INODES NUM_INODES="17">
    		<INODE>
    			<INODE_PATH>/</INODE_PATH>
    			<REPLICATION>0</REPLICATION>
    			<MODIFICATION_TIME>2012-12-05 08:59</MODIFICATION_TIME>
    			<ACCESS_TIME>1970-01-01 08:00</ACCESS_TIME>
    			<BLOCK_SIZE>0</BLOCK_SIZE>
    			<BLOCKS NUM_BLOCKS="-1">
    			</BLOCKS>
    			<NS_QUOTA>2147483647</NS_QUOTA>
    			<DS_QUOTA>-1</DS_QUOTA>
    			<PERMISSIONS>
    				<USER_NAME>hdfs</USER_NAME>
    				<GROUP_NAME>supergroup</GROUP_NAME>
    				<PERMISSION_STRING>rwxr-xr-x</PERMISSION_STRING>
    			</PERMISSIONS>
    		</INODE>
    	</INODES>
    	<INODES_UNDER_CONSTRUCTION NUM_INODES_UNDER_CONSTRUCTION="0">
    	</INODES_UNDER_CONSTRUCTION>
    	<CURRENT_DELEGATION_KEY_ID>0</CURRENT_DELEGATION_KEY_ID>
    	<DELEGATION_KEYS NUM_DELEGATION_KEYS="0">
    	</DELEGATION_KEYS>
    	<DELEGATION_TOKEN_SEQUENCE_NUMBER>0</DELEGATION_TOKEN_SEQUENCE_NUMBER>
    	<DELEGATION_TOKENS NUM_DELEGATION_TOKENS="0">
    	</DELEGATION_TOKENS>
    </FS_IMAGE>
    

    顯示的資訊和 Indented 一模一樣,只是用 XML 的方式呈現。

  •  

  • FileDistribution:
    指令

    hdfs oiv -i fsimage_0000000000000000156 -o fsimage.txt -p FileDistribution
    

    範例

    Size    NumFiles
    0       2
    2097152 44
    4194304 0
    6291456 0
    8388608 0
    10485760        24
    12582912        0
    14680064        0
    16777216        0
    18874368        0
    20971520        0
    

    顯示方式以檔案大小為主,列出不同的區間包含多少檔案。預設所分析的檔案最大是 128G,每 2MB 為一個區間列出檔案個數。雖然文件上寫可以用 -maxSize 來決定最大的檔案大小,用 -step 決定區間的大小,但是現在的版本這兩個參數並沒有作用。

  •  

  • NameDistribution:
    指令

    hdfs oiv -i fsimage_0000000000000000156 -o fsimage.txt -p NameDistribution
    

    範例

    Total unique file names 106
    0 names are used by 0 files between 100000-24 times. Heap savings ~0 bytes.
    0 names are used by 0 files between 10000-99999 times. Heap savings ~0 bytes.
    0 names are used by 0 files between 1000-9999 times. Heap savings ~0 bytes.
    0 names are used by 0 files between 100-999 times. Heap savings ~0 bytes.
    2 names are used by 36 files between 10-99 times. Heap savings ~1098 bytes.
    2 names are used by 14 files between 5-9 times. Heap savings ~384 bytes.
    3 names are used by 12 files 4 times. Heap savings ~258 bytes.
    1 names are used by 3 files 3 times. Heap savings ~56 bytes.
    6 names are used by 12 files 2 times. Heap savings ~227 bytes.
     
    Total saved heap ~2023bytes.
    

    這個功能文件上沒有寫,但是已經有實作。顯示方式以檔案名稱為主,列出有多少同名的檔案。不過顯示的方式過於粗糙,只有統計數據,並沒提供精確的檔案名稱以做後續的維護。
    這裡有一個有趣的地方 Heap savings。在 Hadoop 0.22 加入了 NameCache 的機制,因為執行 M/R jobs 常常會產生 part-00000,part-m-00000 或 part-r-00000 等同名的檔案。重覆的名稱都存在 namespace 裡會提高 NameNode 記憶體的使用量。NameCache 實作解決了這個問題,也降低了 NameNode 所需的 heap size。不過這種方式會稍微拖慢 Hadoop 啟動的速度,但是被 Hadoop 社群認為是在可接受的範圍。至於總共省了多少記憶體就可以從 Total saved heap 看出來。

 
2. 使用 Pig 分析 Hadoop Namespace
以下的案例主要是參考官方網站上的建議,再加上個人的經驗。分析的檔案格式以 Delimited 為主。

  • 每個目錄的 Space Quota 設定
    hdfs dfsadmin -setSpaceQuota 設定時沒有一個方式做完整的統計及管理,hdfs dfs -count 以 byte 為單位計算也不容易讀。利用 Pig 就可以產生一個簡單的總表。
     
    Pig script

    A = LOAD 'fsimage.txt' USING PigStorage('\t') AS (path:chararray,
                                                      replication:int,
                                                      modTime:chararray,
                                                      accessTime:chararray,
                                                      blockSize:long,
                                                      numBlocks:long,
                                                      fileSize:long,
                                                      namespaceQuota:long,
                                                      diskspaceQuota:long,
                                                      perms:chararray,
                                                      username:chararray,
                                                      groupname:chararray);
    
    B = FILTER A BY diskspaceQuota != -1;
    -- 以 GB 為單位顯示 diskspaceQuota 比便方便閱讀
    C = FOREACH B GENERATE path, username, diskspaceQuota/1073741824 as diskspaceQuota;
    D = ORDER C BY diskspaceQuota DESC;
    

    範例

    (/user/odin,odin,200)
    (/user/fenriswolf,fenriswolf,100)
    (/user/thor,thor,10)
    
  • 每個使用者的小檔案個數
    在初期使用上不太可能設定 Name Quotas 來阻擋使用者上傳檔案,但是太多的小檔案會造成 NameNode 的負擔。以下的報表就可以決定是否要合併檔案或依使用者來設定 Name Quotas 以防止狀況惡化。這個 script 還有調整的空間,因為 M/R jobs 也可以造成多個小檔案,要怎麼決定 FILTER 就看系統管理者的需求了。
    Pig script

    A = LOAD 'fsimage.txt' USING PigStorage('\t') AS (path:chararray,
                                                      replication:int,
                                                      modTime:chararray,
                                                      accessTime:chararray,
                                                      blockSize:long,
                                                      numBlocks:long,
                                                      fileSize:long,
                                                      namespaceQuota:long,
                                                      diskspaceQuota:long,
                                                      perms:chararray,
                                                      username:chararray,
                                                      groupname:chararray);
    -- 只找小於 64MB 的檔案並過濾 /tmp 目錄。/tmp 因為需要放很多暫存檔,加入計算並不合理
    B = FILTER A by fileSize < 67108864 and (NOT (path matches '/tmp.*'));
    C = FOREACH B GENERATE path, username;
    D = FOREACH (GROUP C BY username) GENERATE group, COUNT(C.path) AS count;
    E = ORDER D by count DESC;
    

    範例

    (hdfs,279485)
    (odin,241814)
    (fenriswolf,92919)
    (thor,53198)
    
  • 某時間區間沒有被存取過的檔案清單
    Hadoop cluster 的空間並不是無限的,當空間快滿需要砍資料的時候,系統管理者容易遇到的問題是,使用者跟他說資料都很重要不能砍。如果可以抓出沒被存取過的資料就可以幫助管理者提出有力的證據。Hadoop 0.19 的版本加入了存取時間(access time)這個屬性,但是用 hdfs dfs -ls -R 所顯示的只有修改時間(modification time),要使用 Hadoop API FileStatus 來操作也相對麻煩。這個 script 就可以提供相關的資訊。
    access time 這個屬性有一小時的時間差,他並不能完全反應現實中最後被讀取的時間。這取決於 dfs.namenode.accesstime.precision (舊版是 dfs.access.time.precision) 的定義。預設是 3600000(一小時),也就是在一小時內多次讀取同個檔案的話是不會更新 access time 的。因為所有更新的動作需要寫回 fsimage 裡,而寫入又需要 locking 的機制,如果所有讀取動作都寫回 fsimage 會造成 Hadoop 效能變差。另外,Hadoop 在 safemode 的時候也不會更新 access time。
    Pig script

    A = LOAD 'fsimage.txt' USING PigStorage('\t') AS (path:chararray,
                                                      replication:int,
                                                      modTime:chararray,
                                                      accessTime:chararray,
                                                      blockSize:long,
                                                      numBlocks:long,
                                                      fileSize:long,
                                                      namespaceQuota:long,
                                                      diskspaceQuota:long,
                                                      perms:chararray,
                                                      username:chararray,
                                                      groupname:chararray);
    -- 只找檔案大小大於 0 的並過濾 /tmp 目錄。/tmp 因為需要放很多暫存檔,加入計算並不合理
    B = FILTER A by fileSize != 0 and (NOT (path matches '/tmp.*'));
    C = FOREACH B GENERATE path, accessTime, modTime;
    -- 找今年內都沒被存取的檔案
    D = FILTER C BY modTime < '2012-01-01 00:00' and accessTime < '2012-01-01 00:00';
    E = ORDER D BY modTime, accessTime;
    

    範例

    (/user/fenriswolf/mr/20110910/part-m-04622,2011-09-12 13:24,2011-09-12 13:24)
    (/user/fenriswolf/mr/20110910/part-m-04621,2011-09-12 13:24,2011-09-12 13:24)
    (/user/fenriswolf/mr/20110910/part-m-04620,2011-09-12 13:24,2011-09-12 13:24)
    (/user/fenriswolf/mr/20110910/part-m-04619,2011-09-12 13:24,2011-09-12 13:24)
    
  • 從檔案大小看可能重覆的檔案
    這在測試環境最容易發生,每個人為了方便可能會把同一份資料放在自己的家目錄下。可以早點發現並做整理的話,除了省空間之外,也可減少變動造成兩份資料不一致的狀況。
    在大的 cluster 裡,M/R jobs 所產生的檔案大小相似率會非常的高,可能有成千上萬個檔案會被找出來但實際內容不一樣,所以下面的範例有濾掉這種情況。另外像標題所述,這個清單只是可能重覆的檔案,如果要更精確的資料就必須在 Pig script 裡再做 checksum 的機制。
    Pig script

    A = LOAD 'fsimage.txt' USING PigStorage('\t') AS (path:chararray,
                                                      replication:int,
                                                      modTime:chararray,
                                                      accessTime:chararray,
                                                      blockSize:long,
                                                      numBlocks:long,
                                                      fileSize:long,
                                                      namespaceQuota:long,
                                                      diskspaceQuota:long,
                                                      perms:chararray,
                                                      username:chararray,
                                                      groupname:chararray);
    -- 只找檔案大小大於 0 的並過濾 /tmp 目錄及所有 M/R jobs 產生的檔案
    B = FILTER A by fileSize != 0 and (NOT (path matches '/tmp.*|.*part-.*|.*part-m.*|.*part-r.*'));
    C = FOREACH B generate path, SUBSTRING(path, (int)LAST_INDEX_OF(path, '/') + 1, (int)SIZE(path)) as fileName, fileSize;
    D = GROUP C by (fileName, fileSize);
    -- 顯示檔案名稱,檔案大小,重覆的數量及檔案所在的清單
    E = FOREACH D generate group.fileName, group.fileSize, COUNT(C) as numDupes, C.path AS files;
    F = FILTER E by numDupes > 1L;
    G = ORDER F by numDupes DESC;
    

    範例

    (hadoop-common-2.0.0-cdh4.1.2.jar,2234642,2,{(/user/odin/lib/hadoop-common-2.0.0-cdh4.1.2.jar),(/user/fenriswolf/lib/hadoop-common-2.0.0-cdh4.1.2.jar)})
    (hadoop-auth-2.0.0-cdh4.1.2.jar,45332,2,{(/user/odin/lib/hadoop-auth-2.0.0-cdh4.1.2.jar),(/user/fenriswolf/lib/hadoop-auth-2.0.0-cdh4.1.2.jar)})
    

 
 
執行環境
CentOS 6.3
JDK 1.6.0_37
Cloudera CDH4.1.2
Pig 0.10.0-cdh4.1.2
 
參考資料
Offline Image Viewer Guide

廣告

2012/12/10 - Posted by | Hadoop | , ,

仍無迴響。

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com Logo

您的留言將使用 WordPress.com 帳號。 登出 / 變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 / 變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 / 變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 / 變更 )

連結到 %s

%d 位部落客按了讚: