Hadoop的I/O操作

firefule發表於2021-09-09

原文地址: ,歡迎大家訪問。

HDFS的資料完整性

HDFS會對寫入的所有資料計算校驗和,並在讀取資料時驗證校驗和。我們在寫入資料的時候最後一個處理的datanode會去驗證校驗和,如果錯誤的話會丟擲IOException的子異常。且每個datanode都會記錄每次驗證校驗和的日誌,這樣可以方便我們排查錯誤發生的時間。datanode還會主動的定期驗證儲存在該datanode上所有資料的校驗和,當發現錯誤時會向namenode彙報並進行資料修復。

壓縮

codec

我們透過實現CompressionCodec介面來描述我們壓縮-解壓縮演算法,CodepressionCodec裡有兩個方法,分別是createOutputStream(OutputStream out)和createInputStream(InputStream in),前者是對寫入輸出資料流的資料進行壓縮,而後者則是對輸入資料流的資料進行解壓縮。一個CodepressionCodec的實現對應著一種壓縮-解壓縮演算法。

壓縮格式 字尾 對應的CompressionCodec實現 是否可切分
DEFALATE .deflate org.apache.hadoop.io.compress.DefaultCodec
gzip .gz org.apache.hadoop.io.compress.GzipCodec
bzip2 .bz2 org.apache.hadoop.io.compress.BZip2Codec
LZ4 .lz4 org.apache.hadoop.io.compress.Lz4Codec
Snappy .snappy org.apache.hadoop.io.compress.SnappyCodec

透過CompressionCodecFactory推斷CompressionCodec

CompressionCodecFactory.getCodec()方法可以根據檔案的副檔名來推斷要使用那種CompressionCodec的實現。

@Testpublic void fileDecompressor() throws IOException {
    FSDataInputStream in = null;    try {
        CompressionCodecFactory factory = new CompressionCodecFactory(configuration);
        Path inPath = new Path("/test/codec/test.txt.gz");
        CompressionCodec codec = factory.getCodec(inPath);
        in = fs.open(new Path("/test/codec/test.txt.gz"));
        IOUtils.copyBytes(codec.createInputStream(in), System.out, 4096);
    } finally {
        in.close();
    }
}

程式碼中包含的某些變數的定義我沒有粘過來,如果需要測試的話可以檢視完整的程式碼。

壓縮和輸入分片

DEFALATE、gzip、bzip2、LZO、LZ4、Snappy幾種壓縮格式中,只有bzip2是支援切分的。對於大檔案來說最好不要使用不支援切分整個檔案的壓縮格式,因為這麼做會失去資料的本地特性,大量的網路傳輸進而造成MapReduce應用效率低下。

在MapReduce中使用壓縮

如果MapReduce程式的輸入檔案是壓縮的,那麼MapReduce程式會使用上面透過CompressionCodecFactory推斷CompressionCodec的方式推斷出對應的codec,然後再讀取檔案的時候自動解壓縮檔案。
如果我們想壓縮MapReduce作業的輸入資料的話,則還需要進行相應的配置,具體如何配置我會在後面的文章中進行說明,期待吧。

序列化

序列化指將結構化的物件轉化為位元組流以便在網路上傳輸或寫到磁碟儲存的過程。與之對應的反序列化就是將位元組流轉換成結構化物件的過程。

Writeable介面

Hadoop使用的是自己的序列化格式Writable,緊湊且速度快,但是對Java之外的其他語言並不是很友好。Hadoop本身提供了很多Writable類,Java的基本型別都有被封裝,正對String的Text,BytesWritable,NullWritable,ArrayWritable等等。

  • 實現定製的Writeable
    這裡我們定製一個UserWriteable物件,包含了name和address兩個屬性。

public class UserWriteable implements Writable {    private String name;    private String address;    public String getName() {        return name;
    }    public UserWriteable setName(String name) {        this.name = name;        return this;
    }    public String getAddress() {        return address;
    }    public UserWriteable setAddress(String address) {        this.address = address;        return this;
    }    public void write(DataOutput dataOutput) throws IOException {
        dataOutput.writeChars(name);
        dataOutput.writeChars(address);
    }    public void readFields(DataInput dataInput) throws IOException {        // 先進先出原則,與write方法對應
        name = dataInput.readLine();
        address = dataInput.readLine();
    }
}
  • write

    • 將物件的屬性寫入二進位制流(DataOutput)。

  • readFields

    • 從二進位制流(DataInput)中還原物件屬性。

  • 為什麼不用Java的序列化機制

    • 該機制與語言密切相關。

    • 太複雜。



作者:名字想好沒
連結:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/1834/viewspace-2819766/,如需轉載,請註明出處,否則將追究法律責任。

相關文章