ProtocolBuffer和lzo技术Hadoop系统上的使用

来源:互联网 发布:蒙奇奇淘宝旗舰店 编辑:程序博客网 时间:2024/05/22 23:26

转自:http://www.searchtb.com/2010/09/pb-lzo-used-in-hadoop.html

概述

基于hadoop的集群分布式数据处理目前是淘宝搜索中心最重要的数据处理平台,在集群物理条件确定的情况下,有几个方面影响了数据处理的速度。

1、数据大小 (影响磁盘IO和网络IO)
2、数据格式 (影响数据的解析及构造速度)
3、并行度

使用 protocolBuffer + lzo技术,能帮我们做到数据小解析快并行度高这三点, 能帮我们大幅度提高处理的速度。下面详细介绍一下如何编译部署及开发相关代码。

hadoop介绍

请参考 分布式计算开源框架Hadoop介绍 和 官方网站http://hadoop.apache.org

protocolBuffer介绍

官方网站http://code.google.com/intl/zh-CN/apis/protocolbuffers/docs/overview.html
Google定义的一套数据协议,用于数据的结构化和序列化。 Google绝大部分模块数据交互基于此数据协议。

1、平台无关、语言无关。
2、二进制、数据自描述。
3、提供了完整详细的操作API。
4、高性能 比xml要快20-100倍
5、尺寸小 比xml要小3-10倍 –高可扩展性
6、数据自描述、前后兼容

适用于

1、不同的平台、系统、语言、模块之间高效的数据交互
2、用于构建大型的复杂系统,降低数据层面的耦合度和复杂度

这里要特别着重说的是protocolBuffer是一种数据协议,就像tcp/ip协议一样,只要是遵守此协议的任何系统之间都能高效的进行数据交互。
第二个特别要说的是 数据自描述。 也就是说拿到任何一个protocolBuffer的数据文件,我们不需要任何其他的辅助信息,就能顺利的解析出其中的数据信息。
这2点是最本质的。
google同时提供了一套代码生成工具,能根据用户自定义的.proto文件,生成c++/java/python的 代码,用于调用protocolBuffer的内核API . 给我们使用提供了很大的便利
.proto文件 详细请参考 官方网站 http://code.google.com/intl/zh-CN/apis/protocolbuffers/docs/overview.html

lzo介绍

LZO是一种高压缩比和解压速度极快的编码, 特点是

解压缩速度非常快。
LZO是无损压缩,压缩后的数据能准确还原
lzo是基于block分块的,允许数据被分解成chunk,能够被并行的解压

下面说一下如何,部署编译 hadoop protocolBuffer 和 lzo , 我下面提到的hadoop是基于 0.19.3版本的,需要很多额外的修改源码的工作。 如果你使用的是 hadoop-0.20+ , 就省了这些麻烦的事情了, 可以不用修改代码 直接编译。

下面是一大堆的安装编译配置等的,这里不转了,有兴趣的直接看原文吧。。。

运行使用

压缩命令:

hadoop jar ~/hadoop_sta/hadoop/contrib/streaming/hadoop-0.19.2-dev-streaming.jar -input /app/aa.txt -output /test-lzo -mapper cat -reducer cat -jobconf mapred.output.compress=true -jobconf mapred.output.compression.codec=org.apache.hadoop.io.compress.LzoCodec

给lzo压缩文件加索引:

hadoop jar /home/admin/hadoop_sta/hadoop/lib/hadoop-lzo-0.4.4.jar com.hadoop.compression.lzo.LzoIndexer /test-lzo/

给lzo文件加索引的目的是为了让lzo支持 splitable,这样hadoop可以并行处理,所以这一步很关键,生成的文件后缀 .index
我们在 hadoop-lzo-0.4.4.jar 另一个mapreduce版本的 创建索引的工具DistributedLzoIndexer
解压命令:

hadoop jar ~/hadoop_sta/hadoop/contrib/streaming/hadoop-0.19.2-dev-streaming.jar-inputformat org.apache.hadoop.mapred.LzoTextInputFormat-input /test-lzo -output /test-txt -mapper cat -reducer cat

如何编写 读取 写出 protocolBuffer + lzo 文件的mapreduce程序

编写.proto文件
具体语法请参考protocolBuffer网站
例子:

<package com.taobao.proto;message auction{  optional string id = 1;  optional bytes  title = 2;  optional string user = 3;  optional string pict_url = 4;  optional uint32 category = 5;}

使用protoc程序生成java代码
protoc –java_out=. auction.proto
生成的文件是 com/taobao/proto/Auction.java 文件

实现定制的inputFormat和outputFormat
主要是下面的3个类, 相关的代码 在 我提供elephant-bird下载包的 taobao 目录下都有
AuctionProtobufWritable.java

package com.taobao.proto.mapred.io; import com.taobao.proto.Auction.auction;import com.twitter.elephantbird.mapred.io.ProtobufWritable;import com.twitter.elephantbird.util.TypeRef; public class AuctionProtobufWritable extends ProtobufWritable<auction> {         public AuctionProtobufWritable() {                 super(new TypeRef<auction>(){});         } }


AuctionLzoProtobufBlockInputFormat.java

AuctionLzoProtobufBlockInputFormat.java package com.taobao.proto.mapred.input; import com.taobao.proto.Auction.auction;import com.twitter.elephantbird.mapred.input.LzoProtobufBlockInputFormat;import com.taobao.proto.mapred.io.AuctionProtobufWritable;import com.twitter.elephantbird.util.TypeRef; public class AuctionLzoProtobufBlockInputFormat extends LzoProtobufBlockInputFormat<auction, AuctionProtobufWritable> {        public AuctionLzoProtobufBlockInputFormat()        {                 setTypeRef(new TypeRef<auction>(){});                 setProtobufWritable(new AuctionProtobufWritable());        }}


AuctionLzoProtobufBlockOutputFormat.java

package com.taobao.proto.mapred.output; import com.taobao.proto.Auction.auction;import com.twitter.elephantbird.mapred.output.LzoProtobufBlockOutputFormat;import com.taobao.proto.mapred.io.AuctionProtobufWritable;import com.twitter.elephantbird.util.TypeRef; public class AuctionLzoProtobufBlockOutputFormat extends LzoProtobufBlockOutputFormat<auction, AuctionProtobufWritable> {        public AuctionLzoProtobufBlockOutputFormat()        {                 setTypeRef(new TypeRef<auction>(){});        }}


编写mapreduce程序

job 的设置:

job.setOutputKeyClass(NullWritable.class);job.setOutputValueClass(AuctionProtobufWritable.class);job.setInputFormat(AuctionLzoProtobufBlockInputFormat.class);job.setOutputFormat(AuctionLzoProtobufBlockOutputFormat.class);

mapper和reduce类:

import com.google.protobuf.ByteString;import com.taobao.proto.Auction;import com.taobao.proto.Auction.auction;import com.taobao.proto.mapred.io.*;import com.taobao.proto.mapred.input.*;import com.taobao.proto.mapred.output.*; public static class proto2protoMapper extends MapReduceBase implements    Mapper<LongWritable, AuctionProtobufWritable, NullWritable, AuctionProtobufWritable>{         @Override        public void map(LongWritable key, AuctionProtobufWritable value,                         OutputCollector<NullWritable, AuctionProtobufWritable> outCollector, Reporter reporter)         throws IOException         {                 auction pa = value.get();                 auction.Builder builder = auction.newBuilder();                 if (pa.hasId())              builder.setId(pa.getId());                 if (pa.hasTitle())           builder.setTitle(pa.getTitle());                 if (pa.hasUser())            builder.setUser(pa.getUser());                 ......                 AuctionProtobufWritable pw = new AuctionProtobufWritable();                 pw.set(builder.build());                 outCollector.collect(NullWritable.get(),  pw);         }}


编译成jar包
ant 编译

如何运行

hadoop jar dist/taobao-proto-auction-1.0.jar com.taobao.proto.proto2proto /yewang/xml2proto /yewang/proto2proto

streaming调用方式,和map reduce处理程序 python样例

编写.proto文件
复用上面的 例子一样

使用protoc 生成 python代码

protoc –python_out=../python/ auction.proto

生成的文件是 auction_pb2.py

编写map reduce 脚本

#!/home/admin/Python/bin/python# -*- coding: utf-8 -*-# Filename: reducer.py# Author: yewang@taobao.com clm971910@gmail.comimport auction_pb2import sysimport base64 pa = auction_pb2.auction()f = open("/dev/stdin", "rb") while True:        line = f.readline();         if len(line) == 0:                break;         # 处理掉换行符 , (streaming.jar 帮我们加的)        line = line.strip();         # 切分出keyValue, (streaming.jar 帮我们加的)        keyValue = line.split("\t");         # base64 解码        value = base64.standard_b64decode(keyValue[1]);         # 解析 成 proto 对象        pa.ParseFromString(value);         # 输出部分内容, 需要带上key, \t分隔,用于选择合适的reducer        # print "1\t" + pa.title;        # 如果想要输出proto , 需要将proto对象转换成字符串, 然后base64编码        print "1\t" + base64.standard_b64encode(value); f.close()

如何运行

hadoop jar -libjars dist/taobao-proto-auction-1.0.jar /home/admin/hadoop_sta/hadoop/contrib/streaming/hadoop-0.19.2-dev-streaming.jar  -input /yewang/testproto -output /yewang/testStreaming4  -file /home/admin/yewang/elephant-bird/taobao/src/python/auction_pb2.py -file /home/admin/yewang/elephant-bird/taobao/src/python/mapper.py -file  /home/admin/yewang/elephant-bird/taobao/src/python/reducer.py  -inputformat com.taobao.proto.mapred.input.AuctionLzoProtobufBlockB64InputFormat -outputformat com.taobao.proto.mapred.output.AuctionLzoProtobufBlockB64OutputFormat  -reducer reducer.py -mapper mapper.py