ProtocolBuffer和lzo技術Hadoop系統上的使用

轉自: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, AuctionProtobufWritab
le>
 
{
        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, AuctionProtobufWrit
able>
 
{
        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, AuctionProtobufWrit
able, 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: [email protected] [email protected]
import auction_pb2
import sys
import 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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章