MapReduce の定義:
MapReduce は、Map (マップ) + Reduce (法令)、つまり特定のプロセスに分解できます。
- マップ : 入力データセットは複数の小さな部分に分割され、処理のために異なるコンピューティングノードに割り当てられます。
- Shuffle and Sort: シャッフルして並べ替えます。マップ フェーズが終了すると、各マッパーによって生成されたキーと値のペアがキーごとに並べ替えられ、同じキーの値がマージされ、同じキーが後続のマッパーに送信されます。減らす
- Reduce: 削減されたコンピューティング。各コンピューティング ノードはキーと値のペアを個別に処理し、最終出力を生成します。
MapReduce は、分散コンピューティング プログラム用のプログラミング フレームワークであり、ユーザーが「Hadoop ベースのデータ分析アプリケーション」のコア フレームワークを開発するために使用されます。f の中核となる機能は、ユーザーが作成したビジネス ロジック コードとその独自のデフォルト コンポーネントを、Hadoop クラスター上で同時に実行される完全な分散コンピューティング プログラムに統合することです。
アドバンテージ:
- プログラミングが簡単: ユーザーはビジネス ロジックのみを気にします。フレームワークのインターフェースを実装します。
- 優れたスケーラビリティ: サーバーを動的に追加して、コンピューティング リソース不足の問題を解決できます。
- 高い耐障害性: いずれかのマシンに障害が発生した場合、タスクを他のノードに転送できます。
- 並列処理: クラスター内の複数の計算ノードを効果的に使用して並列計算を実行し、処理速度を向上させることができます。
- 大規模データ コンピューティング (TB、PB) および共同コンピューティング用の数千台のサーバーに最適
欠点:
- リアルタイム計算は苦手です。mysql
- ストリーミングコンピューティングは苦手です。スパークストリーミングフリンク
- DAG有向非巡回グラフ計算が苦手。スパーク
MapReduce アーキテクチャ:
MapReduce には、MapReduce タスクを実行するための 2 つのマシン ロールがあります。JobTracker と TaskTracker です。JobTracker はタスクのスケジュールに使用され、TaskTracker はタスクの実行に使用されます。Hadoop クラスターには、JobTracker が 1 つだけあります。
クライアントが JobTracker にジョブを送信すると、JobTracker はジョブを複数の TaskTracker に分割して実行し、TaskTracker は定期的にハートビート メッセージを送信します。TaskTracker タスクは他の TackTracker に割り当てられます。
MapReduce の実行プロセス:
- クライアントがジョブを開始する
- クライアントは JobTracker から JobID を要求します
- JobClient は、jar ファイル、構成ファイル、クライアントによって計算された入力分割情報など、ジョブの実行に必要なリソースを HDFS にコピーし、JobID という名前のフォルダーにアーカイブします。
- JobClient はタスクを JobTracker に送信します。
- JobTracker はジョブをスケジュールし、入力されたパーティション情報に従って各パーティションのマップ タスクを作成し、そのマップ タスクを taskTracker に割り当てて実行します。[写真の5/6段]
- TaskTracker は、JobTracker がまだ実行中であることを伝えるために、時々ハートビートを JobTracker に送信します。ハートビートには、マップ タスクの完了の進行状況などの多くの情報も含まれます。JobTracker はジョブの最後のタスクの完了情報を受け取ると、ジョブを「成功」として設定し、JobClient がその情報をユーザーに伝えます。
MapReduce の並列処理とチューニング
MapReduce 並列処理とは、MapReduce タスクの実行時に同時に処理されるデータ ブロックの数を指します。これは、システム リソースの使用率、タスクの実行効率、およびタスクの完了時間に密接に関係しています。並列度を正しく設定すると、タスクの並列性と全体的なパフォーマンスが向上します。
並列処理チューニングは、MapReduce タスクの並列処理パラメータを合理的に設定することにより、タスクの実行効率とリソース使用率を最適化することです。
-
マップ タスクの並列処理: 並列処理を適切に増やすことで、クラスター内のコンピューティング リソースを最大限に活用できます。
mapreduce.job.maps
Map タスクの数はパラメータを調整することで設定できます。通常、マップ タスクの数は、クラスター リソースを最大限に活用するために、クラスター内で使用可能な入力シャードの数またはコンピューティング スロットの数に設定できます。例えば:- ハードウェア構成が
2*12core
+ の場合64G
、適切なmap
並列度はノードあたり約 20 ~ 100 でmap
、map
実行時間はそれぞれ少なくとも 1 分であることが望ましいです。 - ジョブの各マップまたはリデュース タスクの実行時間が 30 ~ 40 秒しかない場合は、ジョブのマップまたはリデュース タスクの数を減らし、各タスク (マップ|リデュース) のセットアップとリダクションをスケジューラに追加します。この中間プロセスには数秒かかる場合があるため、各タスクが非常に速く実行されると、タスクの開始時と終了時に非常に多くの時間が無駄になります。
- ハードウェア構成が
-
タスクの並列性を下げる: 並列性を調整することで、タスクの実行効率を向上させることができます。
mapreduce.job.reduces
job.setNumReduceTasks(num) を手動で設定することも、パラメータを調整してReduce タスクの数を設定することもできます- データの分布が不均一な場合、
reduce
ステージ内でデータのスキューが発生する可能性があります。 ReduceTask
数値は恣意的に設定されるものではなく、ビジネスロジック要件も考慮する必要があります。場合によっては、グローバル集計結果を計算する必要があるため、1 つしかありませんReduceTask
- あまりにも多くの を実行しないようにしてください
ReduceTask
。ほとんどの場合job
、最適なreduce
数は最大でもreduce
クラスタ以下 ですreduce slots
。これは、小規模なクラスタの場合は特に重要です。
- データの分布が不均一な場合、
-
Combiner の使用: Combiner は、Map フェーズの後、データを Reduce タスクに渡す前に中間結果を結合する関数です。Combiner の使用方法を適切に設定することで、データ転送やディスク IO のオーバーヘッドが削減され、タスクの実行効率が向上します。
Combiner
使用される原則は、存在または不在がビジネス ロジックに影響を与えることはできないということです。- データ送信の削減: Combiner は、Map タスクのローカル マージの結果を次のステージの Reduce タスクに送信して、ネットワーク送信のオーバーヘッドを削減できます。
- ディスク IO の削減: コンバイナーの結果をマップ タスク内でローカルにマージできるため、ディスクの読み取りと書き込みの数とデータ量が削減されます。
- タスクの実行効率の向上: データ転送とディスク IO のオーバーヘッドを削減することで、Combiner はタスクの実行を高速化し、全体的なパフォーマンスを向上させることができます。
- データ局所性の最適化: 並列度を設定するときは、データの局所性を考慮することができ、同じデータ ブロックを処理するタスクは、そのデータ ブロックが配置されているノードにディスパッチされる必要があります。これにより、ネットワーク送信のオーバーヘッドが削減されます。データ。
-
リソースのチューニング: MapReduce タスクの並列処理のチューニングには、クラスター リソースのチューニングも含まれます。タスクの並列度や全体的なパフォーマンスは、ノードの数を増やしたり、コンピューティング リソースやストレージ リソースを増やしたり、タスク実行中のメモリ割り当てを調整したりすることで改善できます。
知らせ:
Combiner 関数は MapReduce フレームワークの必須要件ではなく、それが使用されるかどうかは特定の MapReduce プログラムによって異なります。Combiner を使用する前提は、入力と出力の型が一貫している必要があるということです。マージ操作は、カスタム Combiner 関数を実装するか、プリミティブ タイプ (Sum、Max、Min など) の組み込み Combiner 関数を使用することによって実装できます。
シャッフル機構:
Shuffle メカニズムとは、Map ステージの出力後のキーに従って、Mapper によって生成された中間のキーと値のペアをグループ化して並べ替え、同じキーの値を対応する Reducer タスクに分配するプロセスを指します。最後の集計操作。
シャッフルプロセスは主に 3 つのステップに分かれています。
- パーティション (パーティション): Map ステージでの出力後、指定されたパーティションに従って中間キーと値のペアを分割し、どのキーと値をどの Reducer タスクで処理するかを決定する必要があります。デフォルトのパーティション関数は、キーのハッシュ値に従ってパーティションを分割し、同じキーを持つデータが同じ Reducer に割り当てられるようにします。
- sort (並べ替え): パーティションの完了後、同じパーティションのキーと値のペアがキーに従って並べ替えられ、並べ替え後に同じキーと値が連続していることが保証されます。これは後続の集計操作に便利です。並べ替えは、外側行アルゴリズムまたは内側行アルゴリズムを使用して実装できます。具体的な実装は、システムの利用可能なメモリとデータ量によって異なります。
- 結合と転送: 並べ替え後、同じキーの値を結合し、集計のために対応する Reducer タスクに送信できます。ここではネットワーク伝送のプロセスを設計し、Map ノードから対応する Reducer ノードにデータを送信します。パフォーマンスを向上させるために、Combiner 関数を使用してローカル結合を行い、データ伝送のオーバーヘッドを削減できます。
Shuffle
バッファーのサイズはMapReduce
プログラムの実行効率に影響し、原理的にはバッファーが大きいほどディスク IO の数が減り、実行速度が速くなります。
MapReduce wordCount の例:
Java タイプ | Hadoop書き込み可能タイプ |
ブール値 | ブール値書き込み可能 |
バイト | バイト書き込み可能 |
内部 | IntWritable |
浮く | FloatWritable |
長さ | 長時間書き込み可能 |
ダブル | 二重書き込み可能 |
弦 | 文章 |
地図 | マップ書き込み可能 |
配列 | 配列書き込み可能 |
ヌル | NullWritabl |
文書内の単語の頻度を数える
1. pom 依存関係を導入します。
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>3.1.3</version>
</dependency>
2. シリアル化クラス Writable
[現在のケースでは、カスタムシリアル化インターフェイスは使用されません]
Hadoop には独自のシリアル化メカニズム (Writable) があり、Java のシリアル化と比較して、Hadoop のシリアル化はよりコンパクトで高速であり、複数の言語をサポートしています。
Hadoop のシリアル化手順:
- 書き込み可能なインターフェイスを実装する
- 逆シリアル化中に引数なしの構造を呼び出す必要があるため、シリアル化されたオブジェクトには引数のない構造が必要です
- シリアル化メソッド write() をオーバーライドする
- 逆シリアル化メソッド readFidlds() をオーバーライドします。
- 逆シリアル化とシリアル化の順序はまったく同じでなければなりません
- toString() をオーバーライドして結果をファイルに表示します
- Comparable インターフェイスを実装し、キーでシリアル化されたカスタム オブジェクトを転送します。
//1 实现Writable接口
@Data
public class FlowBeanWritable implements Writable, Comparable<FlowBeanWritable> {
private long upFlow;
private long downFlow;
private long sumFlow;
//2 提供无参构造
public FlowBeanWritable() { }
//4 实现序列化和反序列化方法,注意顺序一定要保持一致
@Override
public void write(DataOutput dataOutput) throws IOException {
dataOutput.writeLong(upFlow);
dataOutput.writeLong(downFlow);
dataOutput.writeLong(sumFlow);
}
@Override
public void readFields(DataInput dataInput) throws IOException {
this.upFlow = dataInput.readLong();
this.downFlow = dataInput.readLong();
this.sumFlow = dataInput.readLong();
}
//5 重写ToString
@Override
public String toString() {
return upFlow + "\t" + downFlow + "\t" + sumFlow;
}
// 6 如果作为Key传输,则还需要实现compareTo方法
@Override
public int compareTo(FlowBeanWritable o) {
// 倒序排列,从大到小
return this.sumFlow > o.getSumFlow() ? -1 : 1;
}
}
3. Mapper クラスを作成し、Mapper インターフェイスを実装します。
public class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
private Text outK = new Text();
private IntWritable outV = new IntWritable(1);
@Override
protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, IntWritable>.Context context) throws IOException, InterruptedException {
// 1 获取一行并将其转成String类型来处理
String line = value.toString();
// 2 将String类型按照空格切割后存进String数组
String[] words = line.split(" ");
// 3 依次取出单词,将每个单词和次数包装成键值对,写入context上下文中供后续调用
for (String word : words) {
// 先将String类型,转为text,再包装成健值对
outK.set(word);
context.write(outK, outV);
}
}
}
Mapper<LongWritable, Text, Text, IntWritable> ジェネリック型には 4 つのクラスがあり、実際にはキーと値のペアが 2 組あります。
- LongWritable、Text: 入力データを示し、LongWritable はデータの行数と同様のデータのインデックスを示し、Text は読み取られたファイルの内容を示します。通常、システムのデフォルトのキーと値のペアが使用されます。
- Text、IntWritable: は出力データを示し、Text は入力単語を示し、IntWritable は単語の出現数を示します。このキーと値のペアは、ビジネス要件に従って決定する必要があります。
4. Reducer クラスを作成し、Reduce 抽象クラスを継承します。
public class WordCountReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
IntWritable outV = new IntWritable();
@Override
protected void reduce(Text key, Iterable<IntWritable> values, Reducer<Text, IntWritable, Text, IntWritable>.Context context) throws IOException, InterruptedException {
int sum = 0;
for (IntWritable value : values) {
sum += value.get();
}
outV.set(sum);
//写出
context.write(key,outV);
}
}
Reducer<Text, IntWritable, Text, IntWritable> ジェネリック型には 4 つのクラスがあり、ここには 2 つのキーと値のペアもあります。
- Text、IntWritable: 最初のキーと値のペア。Mapper の出力ジェネリック型と一致している必要があります。
- Text、IntWritable: 出力結果データを表す 2 番目のキーと値のペア。ここでの出力は単語の出現数であるため、依然として Text および IntWritable 型です。
Reduce はグループごとに 1 回実行されます。つまり、同じキーが同じグループに割り当てられるため、ここでは各キーの重ね合わせの回数を計算するだけで済みます。
5. ドライバークラスの書き込み
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;
public class WordCountDriver {
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
// 获取配置信息以及job对象
Configuration conf = new Configuration();
Job job = Job.getInstance(conf);
// 关联当前Driver程序的jar
job.setJarByClass(WordCountDriver.class);
// 指定Mapper和Reducer
job.setMapperClass(WordCountMapper.class);
job.setReducerClass(WordCountReducer.class);
// 设置输入、输出的k、v类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
// 设置输入输出路径
FileInputFormat.setInputPaths(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
// 将job提交给yarn运行
Boolean result = job.waitForCompletion(Boolean.TRUE);
}
}