学習Hadoopのは徹底的に理解してシャッフル原理は非常に重要ですが、私は多くの人が「Definitive GuideのHadoopの4」何回か見たことを信じて、本当に徹底的にその真の原則を理解していませんでした。この記事を読んだ後、私はあなたがシャッフル大きな助けを理解するだろうと信じています。
公式の定義に:行う仕分けシステム、プロセス入力パス低減としてマップ出力は、シャッフルをいいます。(読書が無知に見えることを余儀なくされていない)
人気の条件、出力は消化のプロセス全体を開始し、シャッフルと呼ばれる入力を減らすためにマップから生成されます。黒のフレーム部下:
循環バッファの説明:
各マップタスクは、循環バッファを持つことになります。100メガバイト(io.sort.mb属性)が閾値0.8のデフォルトのサイズは、80メガバイト(io.sort.spill.percent属性)であります
しきい値に達すると、バックグラウンドスレッドが流出書き込みファイルの指定されたディレクトリmapred.local.dir(流出)ディスクの新しい内容を書き始めました。ディスクの最初のパーティションに書き込む前に、並べ替え、[コンバイナ]。地図タスクタスクは、N個のディスク・ファイルを生成することがあります。
計算マップタスクの完了、N生成されたファイルの後、その後、一つのファイルにファイルをマージします。
下に示すように、第1の場合にのみN <3の後に、新しいファイルがディスクPatition合成(パーティション)に書き込まれ、ソート(並べ替え)手順、結合していない実行コンバイナ(クラスかどうかを指定するための合成):
N> = 3の場合、以下に示すようPatitionは(パーティション)を合成した後に、新しいファイルが書き込まれるソート(指定されたクラスコンバイナことを条件とする)を合わせ、フロントディスクとコンバイナを介して(ソート):
思考:为什么只有当N>=3时,合成文件才会执行combiner呢?
这是因为如果N< 3时,执行combiner虽然减少了文件的大小,但是同时产生了一定的系统开销。由于减少的文件大小不大,权衡利弊后,确定N< 2时不在执行combiner操作。
当该map task全部执行完之后,对应的reduce task将会拷贝对应分区的数据(该过程称为fetch),如下图所示:
其它的map task任务完成后,对应的reduce task也同样执行fetch操作,如下图所示:
每个map任务的完成时间可能不同,因此只要有一个任务完成,reduce任务就开始复制其输出。该阶段被称为reduce的复制阶段。reduce任务有少量复制线程,因此能够并行取得map输出。默认值是5个线程,但这个默认值可以通过设置mapred.reduce.parallel.copies属性改变。
复制完所有map输出后,reduce任务进入合并阶段,该阶段将合并map输出,并维持其顺序排序(相当于执行了sort),如果指定了combiner,在写入磁盘前还会执行combiner操作。
那么具体是如何合并的呢?
合并因子默认是10,可以通过io.sort.factor属性设置。合并过程是循环进行了,可能叫经过多趟合并。目标是合并最小数量的文件以便满足最后一趟的合并系数。假设有40个文件,我们不会在四趟中每趟合并10个文件从而得到4个文件。相反,第一趟只合并4个文件,随后的三趟分别合并10个文件。再最后一趟中4个已合并的文件和余下的6个(未合并的)文件合计10个文件。具体流程如下图所示:
注:これは最後の旅行はいつも減らすために直接組み込まれているので、それは、ディスクに書き込まれるデータの量を最小限に抑えることを目的としただけで最適化対策を、だ、合併の数は変更されません。
あなたが理解していれば、特定の原則はそれをシャッフルここを参照してください、そうでない場合は、問題で、我々はWORDCOUNTケースと再びコーミングのプロセス全体を渡しません。
最初のマップタスクコードは次のとおりです。
public class WCMapper extends Mapper< LongWritable, Text, Text, LongWritable> {
public void map(LongWritable ikey, Text ivalue, Context context) throws IOException, InterruptedException {
String line = ivalue.toString();
String words[] = line.split(" ");
for (String word : words) {
context.write(new Text(word), new LongWritable(1));
}
}
}
パーティション(ルール:アルファベット順の4つのゾーン、すなわちAI、JQ、RZ、その他)プロセスは、同じ単語は、図2に示すように時間は、カンマで区切られたが存在するであろう、一緒にマージされます。この時点でソートされていないことに注意してください。次のようにゾーニングコードは次のとおりです。
package cn.geekmooc;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Partitioner;
public class WCPatitioner extends Partitioner<Text, LongWritable> {
@Override
public int getPartition(Text key, LongWritable value, int numPartitions) {
int first_char = key.charAt(0);
if(first_char>=97&&first_char<=105){
return 0;
}else if(first_char>=106&&first_char<=113){
return 1;
}else if(first_char>=114&&first_char<=122){
return 2;
}else{
return 3;
}
}
}
下に示すように、ソート操作を実行すると、デフォルトの照合辞書はもちろん、あなたが照合を指定することができ、キーの昇順にソートされ、ソート順:
次のように合成動作は、次以降の加算、WCCombinerクラスコードの各単語を行います。
package cn.geekmooc;
import java.io.IOException;
import java.util.Iterator;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
public class WCCombiner extends Reducer<Text, LongWritable, Text, LongWritable> {
@Override
protected void reduce(Text key, Iterable<LongWritable> values,
Reducer<Text, LongWritable, Text, LongWritable>.Context context) throws IOException, InterruptedException {
System.out.println(key.toString()+":"+values.toString());
long count = 0;
Iterator<LongWritable> iter = values.iterator();
while(iter.hasNext()){
count += iter.next().get();
}
context.write(key, new LongWritable(count));
}
}
結果を図コンバイナに示されています
:、実行されるタスクをマッピングN流出ファイルを生成し、Nは、2つの状況の組み合わせファイル
のファイル結合をマージするときにクラスがコンバイナを指定するかどうか、実行されない、1.N <3。
2.N> = 3、コンバイナ結合動作は、以下に示すように、クラスを指定するために実行した場合。
次に、フェッチステージ入力(またはコピー)
次に、マージ終了を減らします
その後、合併への最後の旅行を行い、その結果は直接減らすために
次のようにクラスコードを減らします:
package cn.geekmooc;
import java.io.IOException;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
public class WCReducer extends Reducer<Text, LongWritable, Text, LongWritable> {
@Override
protected void reduce(Text key, Iterable<LongWritable> values,
Reducer<Text, LongWritable, Text, LongWritable>.Context context) throws IOException, InterruptedException {
System.out.println(key.toString()+":"+values.toString());
long count = 0;
for (LongWritable val : values) {
count += val.get();
}
context.write(key, new LongWritable(count));
}
}
後タスクの実行、出力を減らします: