Hadoop TDG 2 – I/O

Data Integrity

HDFS transparently checksums all data written to it and by default verifies checksums when reading data. A separate checksum is created for every io.bytes.per.checksum bytes of data. The default is 512 bytes, and since a CRC-32 checksum is 4 bytes long, the storage overhead is less than 1%.

关于数据一致性, Hadoop通过CRC-32的校验和来保证

 

Compression

Compression and Input Splits

关注一下这个问题, 并不是每一种压缩都支持splits, 比如gzip就不支持, 知道gzip的原理就知道, 他通过指针指向前面已经出现过的数据, 所以单独给你一块, 你无法解压.

 

Serialization

Serialization is the process of turning structured objects into a byte stream for transmission over a network or for writing to persistent storage. Deserialization is the reverse process of turning a byte stream back into a series of structured objects.

序列化问题倒是比较重要的, 因为分布式计算, node之间的数据传输都需要序列化和反序列化的过程.

Hadoop uses its own serialization format, Writables, which is certainly compact and fast, but not so easy to extend or use from languages other than Java.

 

The Writable Interface

The Writable interface defines two methods: one for writing its state to a DataOutput binary stream, and one for reading its state from a DataInput binary stream:

package org.apache.hadoop.io;
import java.io.DataOutput;
import java.io.DataInput;
import java.io.IOException;
public interface Writable {
    void write(DataOutput out) throws IOException;
    void readFields(DataInput in) throws IOException;
}
这个抽象接口, 到很容易理解, 序列化和反序列化就是, 把类型数据输出成二进制流, 再从二进制流将类型数据恢复出来.

 

  
可见Hadoop提供了很全的类型封装,

Java primitive Writable implementation Serialized size (bytes) 
boolean           BooleanWritable           1 
byte               ByteWritable               1 
int                  IntWritable                 4 
                     VIntWritable               1–5 
float               FloatWritable              4 
long               LongWritable               8 
                    VLongWritable             1–9 
double            DoubleWritable            8 
String            Text 
byte[]            BytesWritable 
                    NullWritable                0, used as a placeholder, a key or a value can be declared as a NullWritable when you don’t need to use that position 
                    ObjectWritable           General-purpose wrapper, useful when a field can be of more than one type. 问题是浪费空间, writes the classname of the wrapped type every time it is serialized 
                    GenericWritable          用于优化ObjectWritable, 当可能的类型比较少, 我们又可以预先知道, 定义static array of types, 这样序列化的时候只需要记下array index, 而不用记录class name 
Arrays            ArrayWritable 
                    TwoDArrayWritable     two-dimensional arrays 
Map              MapWritable               java.util.Map<Writable, Writable> 
SortedMap     SortedMapWritable      java.util.SortedMap<WritableComparable, Writable>

 

细心点会发现, 里面没有对set和list经行封装, 所以怎么表示这两种结构?

Conspicuous by their absence are Writable collection implementations for sets and lists
set can be emulated by using a MapWritable (or a SortedMapWritable for a sorted set), with NullWritable values
For lists of a single type of Writable, ArrayWritable is adequate, 
but to store different types of Writable in a single list, you can use GenericWritable to wrap the elements in anArrayWritable. Alternatively, you could write a general ListWritable using the ideas from MapWritable.

                 

WritableComparable and Comparators

WritableComparable, 顾名思义, 就是在序列化的基础上, 还能支持sort, 这个很有用, 由于hadoop需要对key进行排序, 所以所有的key都必须是WritableComparable类型.

所以对于Writable, 需要多实现一个compareTo function.

 

但当Hadoop经行shuffle sort时, 需要sort大量的中间结果, 所以为了sort, 需要把byte stream反序列化成类型, 然后sort结束再序列化成byte stream. 这样当数据量很大时, 效率会比较低, 所以可以定义Comparators来进行优化.

This interface permits implementors to compare records read from a stream without deserializing them into objects, thereby avoiding any overhead of object creation.

这样就避免了反序列化和序列化的overhead, 但是有个问题是, 并不是所有的类型都可以同bytes steaming进行sort的, 所以不是所有的WritableComparable都可以用compactors进行优化.

package org.apache.hadoop.io;
import java.util.Comparator;
public interface RawComparator<T> extends Comparator<T> {
    public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2);
}

Serialization Frameworks

Although most MapReduce programs use Writable key and value types, this isn’t mandated by the MapReduce API. In fact, any types can be used; the only requirement is that there be a mechanism that translates to and from a binary representation of each type.

上面说了, Writable是不错, 不过有个问题就是无法用于Java以外的语言, 所以需要有其它的serialization framework

 

Avro (http://avro.apache.org/docs/current/index.html

Apache Avro# is a language-neutral data serialization system. 
The project was created by Doug Cutting (the creator of Hadoop) to address the major downside of Hadoop Writables: lack of language portability. 
Having a data format that can be processed by many languages (currently C, C++, Java, Python, and Ruby) makes it easier to share datasets with a wider audience than one tied to a single language. It is also more futureproof, allowing data to potentially outlive the language used to read and write it.

Avro就用于解决上面的语言扩展性问题... 
与Avro类似的二进制序列化framework, 还有Thrift和Protocol buffer, 提供通讯数据序列化的功能和RPC服务.

区别, 或者说Avro的特点在底下这个比较blog里面说的比较清楚

 

Apache Avro 与 Thrift 比较

http://www.tbdata.org/archives/1307

 

Thrift是一个面向编程的系统, 完全依赖于IDL->Binding Language的代码生成。 Schema也“隐藏”在生成的代码中了,完全静态。为了让系统识别处理一个新的数据源,必须走编辑IDL,代码生成,编译载入的流程。

可见, Thrift是种传统的序列化的方案, 比如把java类进行序列化, 那么类对象的schema本身就包含在类定义里面, 所以在序列化的时候, 需要把Java的类定义代码转化为IDL格式, 并保存为schema文件. 
IDL, 接口定义语言, 可以看成一种伪码, 可以简单的和其他各种编程语言进行互相转换 
然后把类对象中包含的数据进行序列化, 结果如下, 每个Field data前面都是需要带Tag的,这个Tag用于标识这个域的类型和顺序ID(IDL中定义,用于Versioning)。在同一批数据里面,这些Tag的信息是完全相同的,当数据条数大的时候这显然就浪费了。

然后当反序列化的时候, 我们首先要有个code generation的过程, 把IDL文件翻译成目标语言代码的过程, 然后再去读数据, 并用生成的类代码产生相应的类对象, 完成反序列化的过程.

 

而Avro在支持Thrift的这种方法的同时, 还提出另外一种更为灵活的方案...

Avro-specific方式(Thrift的方式相似),依赖代码生成产生特定的类,并内嵌JSON Schema. 
Avro-generic方式支持Schema的动态加载,用通用的结构(map)代表数据对象,不需要编译加载直接就可以处理新的数据源。

首先Avro也是可以支持Thrift那样的静态序列化的方式的, Avro-specific方式

Avro-generic方式和Thrift最大的不同是, 它的schema以Json格式存储, 这样便于将schema也放在data file中(开头位置), 如下图.

在反序列化的时候, 我们不需要先得到IDL, 再产生code, 然后在读数据. 
而是可以直接从data file中读出schema, 并根据schema动态加载后面的数据.

Avro规定一个标准的序列化的格式,即无论是文件存储还是网络传输,数据的Schema(in JSON)都出现在数据的前面。数据本身并不包含任何Metadata(Tag). 
在文件储存的时候,schema出现在文件头中。在网络传输的时候Schema出现在初始的握手阶段. 
这样的好处一是使数据self describe,提高了数据的透明度和可操作性,二是减少了数据本身的信息量提高存储效率,可谓一举二得了

 

总结, Avro除了具备, 跨多语言, 支持RPC, 二进制格式...还有如下特色,

Avro provides functionality similar to systems such as ThriftProtocol Buffers, etc. Avro differs from these systems in the following fundamental aspects.

  • Dynamic typing: Avro does not require that code be generated. Data is always accompanied by a schema that permits full processing of that data without code generation, static datatypes, etc. This facilitates construction of generic data-processing systems and languages.
  • Untagged data: Since the schema is present when data is read, considerably less type information need be encoded with data, resulting in smaller serialization size.
  • No manually-assigned field IDs: When a schema changes, both the old and new schema are always present when processing data, so differences may be resolved symbolically, using field names.

 

File-Based Data Structures

SequenceFile是一种<key,value>的二进制的文件格式, 因为如果将<key,value>以文件格式存放的话, 必然会导致时空效率问题. 
所以Hadoop在存放map的中间结果时都是使用SequenceFile来存放<key,value>的, SequenceFile还有另外一个用处就是, 将多个小文件组合成单个文件. 
但它的问题是, 首先只支持Java, 其他语言开发Hadoop就无法使用

Avro就可以解决这个问题, 跨语言的, 而且结构更为紧凑, 而且附带schema数据可以自解释, 而且可以存放除<key,value>以外的其他类型

MapFile is a sorted SequenceFile with an index to permit lookups by key. MapFile can be thought of as a persistent form of java.util.Map (although it doesn’t implement this interface), which is able to grow beyond the size of a Map that is kept in memory.

 

浅析Hadoop文件格式

http://www.infoq.com/cn/articles/hadoop-file-format

1 SequenceFile

SequenceFile是Hadoop API 提供的一种二进制文件,它将数据以<key,value>的形式序列化到文件中。这种二进制文件内部使用Hadoop 的标准的Writable 接口实现序列化和反序列化。它与Hadoop API中的MapFile 是互相兼容的。Hive 中的SequenceFile 继承自Hadoop API 的SequenceFile,不过它的key为空,使用value 存放实际的值, 这样是为了避免MR 在运行map 阶段的排序过程。如果你用Java API 编写SequenceFile,并让Hive 读取的话,请确保使用value字段存放数据,否则你需要自定义读取这种SequenceFile 的InputFormat class 和OutputFormat class。

图1:Sequencefile 文件结构

 

3 Avro

Avro是一种用于支持数据密集型的二进制文件格式。它的文件格式更为紧凑,若要读取大量数据时,Avro能够提供更好的序列化和反序列化性能。并且Avro数据文件天生是带Schema定义的,所以它不需要开发者在API 级别实现自己的Writable对象。最近多个Hadoop 子项目都支持Avro 数据格式,如Pig 、Hive、Flume、Sqoop和Hcatalog。

图3:Avro MR 文件格式

 

4. 文本格式

除上面提到的3种二进制格式之外,文本格式的数据也是Hadoop中经常碰到的。如TextFile 、XML和JSON。 文本格式除了会占用更多磁盘资源外,对它的解析开销一般会比二进制格式高几十倍以上,尤其是XML 和JSON,它们的解析开销比Textfile 还要大,因此强烈不建议在生产系统中使用这些格式进行储存。 如果需要输出这些格式,请在客户端做相应的转换操作。 文本格式经常会用于日志收集,数据库导入,Hive默认配置也是使用文本格式,而且常常容易忘了压缩,所以请确保使用了正确的格式。另外文本格式的一个缺点是它不具备类型和模式,比如销售金额、利润这类数值数据或者日期时间类型的数据,如果使用文本格式保存,由于它们本身的字符串类型的长短不一,或者含有负数,导致MR没有办法排序,所以往往需要将它们预处理成含有模式的二进制格式,这又导致了不必要的预处理步骤的开销和储存资源的浪费。

本文章摘自博客园,原文发布日期:2012-09-06

时间: 2024-11-02 15:38:40

Hadoop TDG 2 – I/O的相关文章

Hadoop TDG 2 -- introduction

首先我们为什么需要Hadoop? The good news is that Big Data is here. The bad news is that we are struggling to store and analyze it. 面对海量的数据,我们需要高效的分析和存储他们,而Hadoop可以做到这点, This, in a nutshell, is what Hadoop provides: a reliable shared storage and analysis system

Hadoop TDG 3 – MR Features

Counters There are often things you would like to know about the data you are analyzing but that are peripheral to the analysis you are performing. For example, if you were counting invalid records and discovered that the proportion of invalid record

Hadoop TDG 3 – MR Job

Anatomy of a MapReduce Job Run   Classic MapReduce (MapReduce 1) A job run in classic MapReduce is illustrated in Figure 6-1. At the highest level, there are four independent entities: • The client, which submits the MapReduce job.  • The jobtracker,

Hadoop TDG 2 – Development Environment

GenericOptionsParser, Tool, and ToolRunner Hadoop comes with a few helper classes for making it easier to run jobs from the command line.  GenericOptionsParser is a class that interprets common Hadoop command-line options and sets them on a Configura

小功告成,在WIN7上配置上了HADOOP,终于可以一窥真容啦

主要参考文档: http://blog.csdn.net/ruby97/article/details/7423088 以后,慢慢熟悉具体操作吧. sky@koala /home/hadoop-0.20.2 $ cd conf sky@koala /home/hadoop-0.20.2/conf $ dos2unix hadoop-env.sh dos2unix: converting file hadoop-env.sh to Unix format ... sky@koala /home/h

Eclipse查看Hadoop源码

1.开发环境 1.Hadoop-1.2.1 2.apache-ant-1.8.0 2.新建Java项目 项目叫"Hadoop_sourcecode" 3.拷贝Hadoop中源码 Hadoop包中src文件文件夹下core.hdfs.mapred文件夹拷贝到项目的src中 4.改变目录结构 删除原来的目录结构:   增加新的目录结构:        选定后的目录结构      5.添加Jar包 需要包含进来的jar包: "\hadoop-1.2.1\lib"中所有ja

如何低成本、高效率搭建Hadoop/Spark大数据处理平台

随着人们逐渐认识到 "大数据"的价值,互联网.电商到金融业.政企等各行业开始处理海量数据.如何低成本.敏捷高效地搭建大数据处理平台,成为影响大数据创新效率的关键. 为了让用户以最简便地方式享用阿里云全球资源,在云端构建敏捷弹性.高可靠和高性价比的大数据平台,近日,阿里云在成都云栖大会上发布了一款Hadoop/Spark场景专用的ECS存储优化型实例D1规格族,单实例提供最高56核CPU,224GB内存,168TB本地盘容量,5GB/S总吞吐,PPS达120万+.这对Hadoop/Spa

Win7下安装Hadoop

1.本人电脑是Win7 64位系统的: 2.JDK 版本: 3.Cygwin 版本: 官网自行下载 4.Hadoop 版本: 官网自行下载,下载稳定版的吧 下面就开始安装啦~~~~ 一. 安装JDK,安装时注意,最好不要安装到带有空格的路径名下,例如:Programe Files,否则在配置Hadoop的配置文件时会找不到JDK.我安装的路径为C:\Java\jdk1.7.0_21,安装完配置环境变量: 1. 安装完成后开始配置环境变量,右击我的电脑,点击属性 2. 在出现的对话框中选择高级系统

eclipse/intellij idea 远程调试hadoop 2.6.0

很多hadoop初学者估计都我一样,由于没有足够的机器资源,只能在虚拟机里弄一个linux安装hadoop的伪分布,然后在host机上win7里使用eclipse或Intellj idea来写代码测试,那么问题来了,win7下的eclipse或intellij idea如何远程提交map/reduce任务到远程hadoop,并断点调试? 一.准备工作 1.1 在win7中,找一个目录,解压hadoop-2.6.0,本文中是D:\yangjm\Code\study\hadoop\hadoop-2.