目錄
Hadoop 序列化
爲什麼要序列化
一般來說,“活的”對象只生存在內存裏,關機斷電就沒有了。而且“活的”對象只能由本地的進程使用,不能被髮送到網絡上的另外一臺計算機。 然而序列化可以存儲“活的”對象,可以將“活的”對象發送到遠程計算機。
什麼是序列化
序列化就是把內存中的對象,轉換成字節序列(或其他數據傳輸協議)以便於存儲(持久化)和網絡傳輸。 反序列化就是將收到字節序列(或其他數據傳輸協議)或者是硬盤的持久化數據,轉換成內存中的對象。
爲什麼不用Java的序列化?
Java的序列化是一個重量級序列化框架(Serializable),一個對象被序列化後,會附帶很多額外的信息(各種校驗信息,header,繼承體系等),不便於在網絡中高效傳輸。所以,hadoop自己開發了一套序列化機制(Writable),精簡、高效。
爲什麼序列化對Hadoop很重要?
因爲Hadoop在集羣之間進行通訊或者RPC調用的時候,需要序列化,而且要求序列化要快,且體積要小,佔用帶寬要小。所以必須理解Hadoop的序列化機制。序列化和反序列化在分佈式數據處理領域經常出現:進程通信和永久存儲。
Hadoop中各個節點的通信是通過遠程調用(RPC)實現的,那麼RPC序列化要求具有以下特點:
1.緊湊:緊湊的格式能讓我們充分利用網絡帶寬,而帶寬是數據中心最稀缺的資
2.快速:進程通信形成了分佈式系統的骨架,所以需要儘量減少序列化和反序列化的性能開銷,
這是基本的;
3.可擴展:協議爲了滿足新的需求變化,所以控制客戶端和服務器過程中,需要直接引進相應的協議,
這些是新協議,原序列化方式能支持新的協議報文;
4.互操作:能支持不同語言寫的客戶端和服務端進行交互;
5.常用數據序列化類型
常用的數據類型對應的hadoop數據序列化類型
Java類型 Hadoop Writable類型
boolean BooleanWritable
byte ByteWritable
int IntWritable
float FloatWritable
long LongWritable
double DoubleWritable
string Text
map MapWritable
array ArrayWritable
Hadoop序列化定義步驟
自定義bean對象實現序列化接口(Writable)
自定義bean對象要想序列化傳輸,必須實現序列化接口,需要注意以下7項。
(1)必須實現Writable接口
(2)反序列化時,需要反射調用空參構造函數,所以必須有空參構造
public FlowBean() {
super();
}
(3)重寫序列化方法
@Override
public void write(DataOutput out) throws IOException {
out.writeLong(upFlow);
out.writeLong(downFlow);
out.writeLong(sumFlow);
}
(4)重寫反序列化方法
@Override
public void readFields(DataInput in) throws IOException {
upFlow = in.readLong();
downFlow = in.readLong();
sumFlow = in.readLong();
}
(5)注意反序列化的順序和序列化的順序完全一致
(6)要想把結果顯示在文件中,需要重寫toString(),可用”\t”分開,方便後續用。
(7)如果需要將自定義的bean放在key中傳輸,則還需要實現comparable接口,
因爲mapreduce框中的shuffle過程一定會對key進行排序。
@Override
public int compareTo(FlowBean o) {
// 倒序排列,從大到小
return this.sumFlow > o.getSumFlow() ? -1 : 1;
}
示例
import org.apache.hadoop.io.Writable;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
public class PersonWritable implements Writable {
private Person person;
public PersonWritable() {
this.person = new Person();
}
public void setPerson(Person person) {
this.person = person;
}
public Person getPerson() {
return person;
}
// 重寫序列化接口
public void write(DataOutput dataOutput) throws IOException {
dataOutput.writeUTF(person.getName());
dataOutput.writeInt(person.getAge());
dataOutput.writeUTF(person.getSex());
}
// 重寫反序列化接口,這裏的順序要與序列化的順序一致
public void readFields(DataInput dataInput) throws IOException {
person.setName(dataInput.readUTF());
person.setAge(dataInput.readInt());
person.setSex(dataInput.readUTF());
}
}
Hadoop 壓縮
爲什麼要在Hadoop中引入壓縮
Hadoop是一個分佈式的計算框架,內部的HDFS是一個分佈式存儲文件系統,Mapreduce是分佈式的計算框架。
既然是分佈式系統,在運行中不可避免的各個結點之間需要通過網絡進行通信。以Mapreduce計算過程爲例,在整個計算過程中
有兩次輸入文件,兩次輸出文件。
MapInput->MapTask->Output MapResult ->ReduceInput->ReduceTask->Output ReduceResult
假設現在有一個2PB大小的文件需要計算,在不使用壓縮算法時,按文件塊256M進行split,
那麼會產生split=1024*1024*2/256=8192,就是8192個map任務,假設hadoop所在物理機是8核, 16G內存。
現在設置每個map任務使用1核,2G內存,每兩個map任務使用一個jvm,那麼就需要物理機512臺,但是現在機房只有300臺
機器,這時我們就需要將輸入的文件變小但數據又不能變,那麼就需要使用壓縮來完成這個任務。
可以在MapInput, Output MapResult, Output ReduceResult時使用壓縮算法,不但可以減少I/O的壓力,還能減少Reduce在拉取
MapResult的網絡傳輸數據流量。
注意:只有在需要時,才使用壓縮,否則反而會造成效率低下
運算密集型的job,少用壓縮
IO密集型的job,多用壓縮
Hadoop 支持的壓縮類別
壓縮算法 | Linux | haoop 自帶 | 算法 | 文件擴展名 | 是否可切割 | 設置壓縮後原來的程序是否需要修改 | 對應編解碼器 |
DEFLATE | 支持 | 支持 | DEFLATE | .deflate | 否 | 與文本處理類似不需要修改 | org.apache.hadoop.io.compress.DefaultCodec |
Gzip | 支持 | 支持 | DEFLATE | .gz | 否 | 與文本處理類似不需要修改 | org.apache.hadoop.io.compress.GzipCodec |
Bzip2 | 支持 | 支持 | bzip2 | .bz2 | 是 | 與文本處理類似不需要修改 | org.apache.hadoop.io.compress.Bzip2Codec |
Lzo | 需要安裝 | 需要安裝 | lzo | .lzo | 是 | 需要創建索引,需要指定輸入格式 | com.hadoop.compression.lzo.LzopCodec |
Snappy | 需要安裝 | 需要安裝 | snappy | .snappy | 否 | 與文本處理類似不需要修改 | org.apache.hadoop.io.compress.SnappyCodec |
各種壓縮方式詳解
Gzip壓縮
優點:壓縮率比較高,而且壓縮/解壓速度也比較快;hadoop本身支持,在應用中處理gzip格式的文件就和直接處理文本一樣;大部分linux系統都自帶gzip命令,使用方便。
缺點:不支持split。
應用場景:當每個文件壓縮之後在130M以內的(1個塊大小內),都可以考慮用gzip壓縮格式。譬如說一天或者一個小時的日誌壓縮成一個gzip文件,運行mapreduce程序的時候通過多個gzip文件達到併發。hive程序,streaming程序,和java寫的mapreduce程序完全和文本處理一樣,壓縮之後原來的程序不需要做任何修改。
lzo壓縮
優點:壓縮/解壓速度也比較快,合理的壓縮率;支持split,是hadoop中最流行的壓縮格式;可以在linux系統下安裝lzop命令,使用方便。
缺點:壓縮率比gzip要低一些;hadoop本身不支持,需要安裝;在應用中對lzo格式的文件需要做一些特殊處理(爲了支持split需要建索引,還需要指定inputformat爲lzo格式)。
應用場景:一個很大的文本文件,壓縮之後還大於200M以上的可以考慮,而且單個文件越大,lzo優點越越明顯。
使用需要安裝:https://blog.csdn.net/qq_23013309/article/details/103106860
lzo的使用注意事項
1.LzoCodec比LzopCodec更快, LzopCodec爲了兼容LZOP程序添加了如 bytes signature, header等信息
2.如果使用 LzoCodec作爲Reduce輸出,則輸出文件擴展名爲".lzo_deflate",它無法被lzop讀取;如果使用LzopCodec作爲
Reduce輸出,則擴展名爲".lzo",它可以被lzop讀取
3.生成lzo index job的”DistributedLzoIndexer“無法爲 LzoCodec,即 ".lzo_deflate"擴展名的文件創建index
4.”.lzo_deflate“文件無法作爲MapReduce輸入,”.LZO"文件則可以。
snappy壓縮
優點:高速壓縮速度和合理的壓縮率。
缺點:不支持split;壓縮率比gzip要低;hadoop本身不支持,需要安裝;
應用場景:當mapreduce作業的map輸出的數據比較大的時候,作爲map到reduce的中間數據的壓縮格式;或者作爲一個mapreduce作業的輸出和另外一個mapreduce作業的輸入。
使用需要安裝:https://blog.csdn.net/qq_23013309/article/details/103106899
bzip2壓縮
優點:支持split;具有很高的壓縮率,比gzip壓縮率都高;hadoop本身支持,但不支持native;在linux系統下自帶bzip2命令,使用方便。
缺點:壓縮/解壓速度慢;不支持native。
應用場景:適合對速度要求不高,但需要較高的壓縮率的時候,可以作爲mapreduce作業的輸出格式;或者輸出之後的數據比較大,處理之後的數據需要壓縮存檔減少磁盤空間並且以後數據用得比較少的情況;或者對單個很大的文本文件想壓縮減少存儲空間,同時又需要支持split,而且兼容之前的應用程序(即應用程序不需要修改)的情況。
壓縮參數配置
core-site.sml
輸入壓縮
<property>
<name>io.compression.codecs</name>
<value>
org.apache.hadoop.io.compress.GzipCodec,
org.apache.hadoop.io.compress.DefaultCodec, #zlib->Default
org.apache.hadoop.io.compress.BZip2Codec,
com.hadoop.compression.lzo.LzoCodec,
com.hadoop.compression.lzo.LzopCodec,
org.apache.hadoop.io.compress.Lz4Codec,
org.apache.hadoop.io.compress.SnappyCodec,
</value>
</property>
mapred-site.xml
<property>
啓用mapper輸出壓縮
<name>mapreduce.map.output.compress</name>
<value>true</value> 默認false
</property>
<property>
設置壓縮的類型
<name>mapreduce.map.output.compress.codec</name>
<value>org.apache.hadoop.io.compress.BZip2Codec</value>
</property>
<property>
啓用reduce輸出壓縮
<name>mapreduce.output.fileoutputformat.compress</name>
<value>true</value> 默認false
</property>
<property>
設置壓縮的類型
<name>mapreduce.output.fileoutputformat.compress.codec</name>
<value>org.apache.hadoop.io.compress.BZip2Codec</value>
</property>
<property>
SequenceFile輸出使用的壓縮類型:NONE和BLOCK
<name>mapreduce.output.fileoutputformat.compress.type</name>
<value>BLOCK</value> 默認RECORD
</property>
存儲文件類型
HDFS是一個文件系統,理論上是可以存放任何類型的文件。比如我們一般見到的.txt類型的文本文件等,但是做爲一個大數據
框架爲了提高效率,也有推薦文件存儲類型。
SequenceFile
SequenceFile簡介
1.sequenceFile文件是Hadoop用來存儲二進制形式的[Key,Value]對而設計的一種平面文件(Flat File)。
2.可以把SequenceFile當做是一個容器,把所有的文件打包到SequenceFile類中可以高效的對小文件進行存儲和處理。
3.SequenceFile文件並不按照其存儲的Key進行排序存儲,SequenceFile的內部類Writer提供了append功能。
4.SequenceFile中的Key和Value可以是任意類型Writable或者是自定義Writable。
5.在存儲結構上,SequenceFile主要由一個Header後跟多條Record組成,
Header主要包含了Key classname,value classname,存儲壓縮算法,用戶自定義元數據等信息,
此外,還包含了一些同步標識,用於快速定位到記錄的邊界。每條Record以鍵值對的方式進行存儲,用來表示它的字符數組可以一次解析成:記錄的長度、Key的長度、Key值和value值,並且Value值的結構取決於該記錄是否被壓縮。
SequenceFile 文件的結構
版本:包括3個字節的SEQ,和真實版本號(e.g. SEQ4 or SEQ6)
key的類名 //e.g. org.apache.hadoop.io.IntWritabe
value的類名 //
是否壓縮 //boolean
是否是塊壓縮 //boolean
壓縮編解碼器 //compression codec
元數據 //真實數據
同步點 //定位數據,判斷數據的結尾和起始
SequenceFile的壓縮
SeqFile內部提供壓縮機制,包含以下三種壓縮:
不壓縮:不壓縮
記錄壓縮:只壓縮value
塊壓縮:多個Key和Value聚集成block,以block爲單位進行壓縮,block的大小可以配置
注:壓縮算法可通過CompressionCodec指定
MapFile
MapFile是個文件夾,包含index和data文件,是一種比較特殊的自帶排序的SeqFile。
Index是索引文件,存放少量Key,在讀取時會將其加載到內存,用於提高檢索速度
Data文件是真實數據文件 兩者均爲SequenceFile類型
使用示例