答案是,「它不能做到」。至少,不適用於將hadoop流式傳輸到源於hadoop之外的快速壓縮文件的特定情況。 (1)嘗試使用hadoop的內置快速壓縮,如高度無咖啡因所示,或者(2)編寫我自己的流模塊來消耗和解壓縮snappy文件。
對於選項(1),似乎hadoop在使用snappy壓縮文件時向文件添加了一些標記。由於我的文件在hadoop之外使用快速壓縮,hadoop的內置編解碼器無法解壓縮文件。
這個問題的一個症狀是堆空間錯誤:
2013-04-03 20:14:49,739 FATAL org.apache.hadoop.mapred.Child (main): Error running child : java.lang.OutOfMemoryError: Java heap space
at org.apache.hadoop.io.compress.BlockDecompressorStream.getCompressedData(BlockDecompressorStream.java:102)
at org.apache.hadoop.io.compress.BlockDecompressorStream.decompress(BlockDecompressorStream.java:82)
at org.apache.hadoop.io.compress.DecompressorStream.read(DecompressorStream.java:76)
at java.io.InputStream.read(InputStream.java:85)
...
當我切換到一個更大的實例,並拍成了mapred.child.java.opts設置,我得到了一個新的錯誤:
java.io.IOException: IO error in map input file s3n://my-bucket/my-file.snappy
Hadoop的快速編解碼器不適用於外部生成的文件。
對於選項(2),問題在於hadoop streaming不區分\ n,\ r和\ r \ n換行符。由於快速壓縮最終會在整個壓縮文件中散佈這些字節代碼,這是致命的。這是我的錯誤跟蹤:
2013-04-03 22:29:50,194 WARN org.apache.hadoop.mapred.Child (main): Error running child
java.lang.RuntimeException: PipeMapRed.waitOutputThreads(): subprocess failed with code 1
at org.apache.hadoop.streaming.PipeMapRed.waitOutputThreads(PipeMapRed.java:372)
at org.apache.hadoop.streaming.PipeMapRed.mapRedFinished(PipeMapRed.java:586)
at org.apache.hadoop.streaming.PipeMapper.close(PipeMapper.java:135)
at org.apache.hadoop.mapred.MapRunner.run(MapRunner.java:57)
...
隨着Hadoop的Java類的一些工作(見here,例如)我們或許可以修復\ r VS \ n問題。但正如我最初所說,我的目標是在hadoop流模塊內部構建,而不需要接觸Java。有了這個限制,似乎沒有辦法解決這個問題。
最後,我回到了生成這個羣集消耗的文件的傢伙,並說服他們切換到gzip或lzo。在選項(2)中,我玩弄了不同字符上的分割記錄(例如textinputformat.record.delimiter = X),但它感覺非常黑,並且無論如何都不起作用。
PPS - 另一個解決方法是編寫腳本從S3下載文件,解壓縮它們,然後運行-copyFromLocal將它們拖入HDFS。從計算上來說,這沒有什麼問題,但從工作流的角度來看,它會引入各種麻煩。
來源
2013-04-04 20:31:58
Abe
我聽說你對LZO和snappy的看法,對於其他人在未來做類似的事情,我也推薦LZO。就我而言,管理存儲到S3的團隊有其他原因希望更加快樂,並且不會對我們在hadoop上的表現造成太大的傷害。所以我們堅持快速壓縮。 – Abe 2013-04-03 20:08:49
此外,您提到的基於魔術文件擴展名的檢測不適用於許多hadoop版本。我正在使用AWS EMR AMI 2.3.3,版本1.0.3,並沒有在那裏工作。我也嘗試了幾個其他的EMR版本,但沒有喜悅。 – Abe 2013-04-03 20:11:19