SequenceFile 解決hadoop小檔案問題

來源:互聯網
上載者:User


SequenceFile Formats2010-10-27 18:50

 

Overview

SequenceFile is a flat file consisting of binary key/value pairs. It is extensively used in MapReduce as input/output formats. It is also worth noting that, internally, the temporary outputs of maps are stored using SequenceFile.

The SequenceFile provides a Writer, Reader and Sorter classes for writing, reading and sorting respectively.

There are 3 different SequenceFile formats:

  1. Uncompressed key/value records.
  2. Record compressed key/value records - only 'values' are compressed here.
  3. Block compressed key/value records - both keys and values are collected in 'blocks' separately and compressed. The size of the 'block' is configurable.

The recommended way is to use the SequenceFile.createWriter methods to construct the 'preferred' writer implementation.

The SequenceFile.Reader acts as a bridge and can read any of the above SequenceFile formats.

 

SequenceFile Formats

This section describes the format for the latest 'version 6' of SequenceFiles.

Essentially there are 3 different file formats for SequenceFiles depending on whether compression and block compression are active.

However all of the above formats share a common header (which is used by the SequenceFile.Reader to return the appropriate key/value pairs). The next section summarises the header:

SequenceFile Common Header
  • version - A byte array: 3 bytes of magic header 'SEQ', followed by 1 byte of actual version no. (e.g. SEQ4 or SEQ6)

  • keyClassName - String
  • valueClassName - String
  • compression - A boolean which specifies if compression is turned on for keys/values in this file.

  • blockCompression - A boolean which specifies if block compression is turned on for keys/values in this file.

  • compressor class - The classname of the CompressionCodec which is used to compress/decompress keys and/or values in this SequenceFile (if compression is enabled).

  • metadata - SequenceFile.Metadata for this file (key/value pairs)

  • sync - A sync marker to denote end of the header.

All strings are serialized using Text.writeString api.

The formats for Uncompressed and RecordCompressed Writers are very similar:

Uncompressed & RecordCompressed Writer Format
  • Header

  • Record
    • Record length
    • Key length
    • Key
    • (Compressed?) Value
  • A sync-marker every few k bytes or so.

The sync marker permits seeking to a random point in a file and then re-synchronizing input with record boundaries. This is required to be able to efficiently split large files for MapReduce processing.

The format for the BlockCompressedWriter is as follows:

BlockCompressed Writer Format
  • Header

  • Record Block

    • A sync-marker to help in seeking to a random point in the file and then seeking to next record block.

    • CompressedKeyLengthsBlockSize

    • CompressedKeyLengthsBlock

    • CompressedKeysBlockSize

    • CompressedKeysBlock

    • CompressedValueLengthsBlockSize

    • CompressedValueLengthsBlock

    • CompressedValuesBlockSize

    • CompressedValuesBlock

    The compressed blocks of key lengths and value lengths consist of the actual lengths of individual keys/values encoded in ZeroCompressedInteger format.

簡介: 
SequenceFile 是一個由二進位序列化過的key/value的位元組流組成的文本隱藏檔,它可以在map/reduce過程中的input/output 的format時被使用。在map/reduce過程中,map處理檔案的臨時輸出就是使用SequenceFile處理過的。
SequenceFile分別提供了讀、寫、排序的操作類。
SequenceFile的操作中有三種處理方式:
1) 不壓縮資料直接儲存。 //enum.NONE
2) 壓縮value值不壓縮key值儲存的儲存方式。//enum.RECORD
3) key/value值都壓縮的方式儲存。//enum.BLOCK

SequenceFile提供了若干Writer的構造靜態擷取。
//SequenceFile.createWriter();

SequenceFile.Reader使用了橋接模式,可以讀取SequenceFile.Writer中的任何方式的壓縮資料。

三種不同的壓縮方式是共用一個資料頭,流方式的讀取會先讀取頭位元組去判斷是哪種方式的壓縮,然後根據壓縮方式去解壓縮並還原序列化位元組流資料,得到可識別的資料。

流的儲存頭位元組格式:
Header:
*位元組頭”SEQ”, 後跟一個位元組表示版本”SEQ4”,”SEQ6”.//這裡有點忘了 不記得是怎麼處理的了,回頭補上做詳細解釋
*keyClass name
*valueClass name
*compression boolean型的儲存標示壓縮值是否轉變為keys/values值了
*blockcompression boolean型的儲存標示是否全壓縮的方式轉變為keys/values值了
*compressor 壓縮處理的類型,比如我用Gzip壓縮的Hadoop提供的是GzipCodec什麼的..
*中繼資料 這個大家可看可不看的

所有的String類型的寫操作被封裝為Hadoop的IO API,Text類型writeString()搞定。

未壓縮的和只壓縮values值的方式的位元組流頭部是類似的:
*Header
*RecordLength記錄長度
*key Length key值長度
*key 值
*是否壓縮標誌 boolean
*values

package com.netease.hadooplucene.lucene.test;import java.io.File;import java.io.IOException;import java.util.*;import java.lang.String;import java.lang.Object;import java.net.URI;import org.apache.hadoop.fs.Path;import org.apache.hadoop.conf.*;import org.apache.hadoop.io.*;import org.apache.hadoop.mapred.*;import org.apache.hadoop.util.*;import org.apache.hadoop.io.compress.*;import org.apache.hadoop.fs.*;import com.netease.hadooplucene.lucene.util.HadoopService;public class SequenceFileTest {                public static void writeSequceFile(String uri)throws IOException{        FileSystem fs = HadoopService.getInstance().getHDFSClient();        Path path = new Path(uri);        IntWritable key = new IntWritable();        Text value = new Text();        SequenceFile.Writer writer = null;        try {            writer = SequenceFile.createWriter(fs, fs.getConf(), path, key.getClass(), value.getClass());            for (int i = 0; i < 100; i++) {                String tt = String.valueOf(100 - i);                key.set(i);                value.set(tt);                System.out.printf("[%s]/t%s/t%s/n", writer.getLength(), key, value);                writer.append(key, value);            }        } finally {            IOUtils.closeStream(writer);        }    }        //    public static File getFile(String uri){//        FileSystem fs = HadoopService.getInstance().getHDFSClient();//        Path path = new Path(uri);//        SequenceFile.Reader reader=new SequenceFile.Reader(fs, path, fs.getConf());//        reader.//        reader.//    }    public static void main(String[] args) throws IOException {        String uri = args[0];//        Configuration conf = new Configuration();//        FileSystem fs = FileSystem.get(URI.create(uri), conf);            }}

前天項目組裡遇到由於sequenceFile 的壓縮參數設定為record 而造成儲存空間的緊張,後來設定為block 壓縮方式的壓縮方式,儲存空間佔用率為record 方式的1/5 。問題雖解決了,但是還不是很清楚這兩種方式是如何工作以及他們的區別是啥。昨天和今天利用空閑時間,細細的看了一遍sequenceFile 這個類和一些相關類的源碼。

sequenceFile 檔案儲存體有三種方式:可以通過在程式調用 enum CompressionType { NONE RECORD BLOCK } 指定,或通過設定檔io.seqfile.compression.type 指定,這三種儲存方式如:

 

 

 

對於Record 壓縮這種儲存方式,RecordLen 表示的是key 和value 的佔用的byte 之和,Record 壓縮方式中 key 是不壓縮 ,value 是壓縮後的值,在record 和非壓縮這兩種方式,都會隔幾條記錄插入一個特殊的標號來作為一個同步點Sync ,作用是當指定讀取的位置不是記錄首部的時候,會讀取一個同步點的記錄,不至於讀取資料的reader “迷失”。 每兩千個byte 就插入一個同步點,這個同步點佔16 byte ,包括同步點標示符:4byte ,一個同步點的開銷是20byte 。

對於block 這種壓縮方式, key 和value 都是壓縮的 ,通過設定io.seqfile.compress.blocksize 這個參數決定每一個記錄塊壓縮的資料量,預設大小是1000000 byte ,這個值具體指的是key 和value 緩衝所佔的空間,每要往檔案寫一條key/value 時,都是將key 和value 的長度以及key 和value 的值緩衝在keyLenBuffer keyBuffer valLenBuffer valBuffer 這四個DataOutputStream 中,當keyBuffer.getLength() + valBuffer.getLength() 大於或等於io.seqfile.compress.blocksize 時,將這些資料當做一個block 寫入sequence 檔案,如所示 每個block 之間都會插入一個同步點。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.