Hadoop ジョブでよくある問題を診断する

ビッグデータBeginner
オンラインで実践に進む

はじめに

小売業者のバッチは昨日は成功しましたが、今日のコマンドはエラーを返しています。メッセージを読まずに繰り返すと、本当の原因を見落としたり、データを壊すような近道を選んだりしかねません。入力の不足、サービスのアドレスの誤り、処理タスクの失敗には、それぞれ違う対応が必要です。

ここでは、短い診断の手順をたどります。ファイルシステムと接続先を特定し、入力の存在と読み取り可否、出力パスを確認してから、受け付けられたアプリケーションの状態とログを調べます。クライアント側のエラーは、アプリケーションの投入前に起こる場合があります。投入されたアプリケーションには YARN の識別子があり、その診断情報から追加の証拠を得られます。

この実験では、特定の印を付けた入力記録を拒否するコンパイル済みの学習用アプリケーションなど、複数の失敗を意図的に用意しています。これらは偶然のインフラ障害ではなく、管理された学習用の例です。証拠を残したまま、別の入力と出力パスで正常な WordCount を完了します。Java の記述、サービスの再インストール、フォーマット、広範囲な削除は必要ありません。すべてのデータは独立して準備されており、ターミナルを使います。

接続エラーと入力のエラーを診断する

このステップでは、実際のクライアントエラーを読み、サービスのアドレスの誤りと、存在しないファイルを区別します。

ローカルの作業ディレクトリから始めます。

cd /home/labex/project

まず、設定されたファイルシステムを再確認します。

hdfs getconf -confKey fs.defaultFS

hdfs://localhost:9000 のはずです。今度は、NameNode が待ち受けていないポート 1 に、意図的にクライアントを接続させます。以下の -D プロパティは、この実行の接続再試行を制限し、接続タイムアウトを2,000ミリ秒にします。意図的なエラーが長引かないようにするもので、共有の設定は編集しません。

> file 2>&1 というリダイレクトは、通常の出力をローカルファイルに保存し、エラー出力も同じ場所に送ります。次のコマンドは、失敗するのが期待される動作です。

hdfs dfs -Dipc.client.connect.max.retries=0 -Dipc.client.connect.timeout=2000 -ls hdfs://localhost:1/user/labex > /home/labex/project/output/connection-error.log 2>&1

保存したエラーを読みます。

cat /home/labex/project/output/connection-error.log

接続の失敗または拒否と、間違ったアドレスを探してください。ファイルシステムの一覧取得が成功する前に起きたエラーです。HDFS のフォーマットやサービスの再インストールはしないでください。コマンドの接続先が間違っているためです。既定のパスを使い、設定された接続先に戻します。

hdfs dfs -ls /user/labex/job-diagnostics/data

clean.txt と rejected.txt が表示され、接続が機能していることが分かります。一方、正常なファイルシステムに存在しないファイルを求めるのは、別の問題です。次のコマンドは、失敗するのが期待される動作です。

hdfs dfs -ls /user/labex/job-diagnostics/data/missing.txt > /home/labex/project/output/missing-input.log 2>&1

メッセージを調べます。

cat /home/labex/project/output/missing-input.log

指定したパスが存在しないと通知されるはずです。使い慣れた読み取り操作で、意図した入力を確認します。

hdfs dfs -cat /user/labex/job-diagnostics/data/clean.txt

2行の内容は notebook pen と notebook folder です。入力パスを直せば、ファイルが見つからない問題は解決します。サーバー設定を変えても解決しません。証拠としてエラーログを残してください。

既存の出力パスを見分ける

このステップでは、すでにある出力ディレクトリが拒否される理由を観察し、広範囲に削除せず保管する判断をします。

セットアップで、予約済みの出力場所を表す空の結果ディレクトリ existing を用意してあります。そのディレクトリ自体の項目を確認します。

hdfs dfs -ls -d /user/labex/job-diagnostics/results/existing

サンプルの MapReduce 出力形式は、新しい出力ディレクトリを作ることを前提にしています。ディレクトリが存在すると、処理アプリケーションが受け付けられる前に、クライアント側で拒否される場合があります。次のコマンドは、失敗するのが期待される動作です。

hadoop jar /opt/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.5.0.jar wordcount /user/labex/job-diagnostics/data/clean.txt /user/labex/job-diagnostics/results/existing > /home/labex/project/output/existing-output.log 2>&1

保存したメッセージを読みます。

cat /home/labex/project/output/existing-output.log

出力ディレクトリが存在するというメッセージ、または FileAlreadyExistsException を探してください。これはパスの競合であり、商品を数えるアルゴリズムが間違っている証拠ではありません。

YARN が受け付けたアプリケーションを一覧表示します。

yarn application -list -appStates ALL

これらのクライアントの間違いでは、完了した処理アプリケーションは作られないはずです。クライアントは投入の準備中にクラスターサービスに接続したり、識別子を得たりする場合がありますが、受け付けられたアプリケーションとその状態は別の証拠です。

予約済みのディレクトリを保ち、成功させる実行では新しい出力パスを使います。results 全体や元の入力を削除するのは、問題に必要な範囲を大きく超える変更です。

実際に失敗したアプリケーションを調べる

このステップでは、意図的に失敗する学習用アプリケーションを投入し、実際の YARN の識別子とログで失敗を説明します。

準備済みの controlled-failure.jar は、入力パスと新しい出力パスを受け取ります。その Mapper は、目印の BAD_RECORD を意図的に拒否します。Java コードを調べたり編集したりする必要はありません。目的は、受け付けられたアプリケーション内のタスクの失敗を、前のクライアントエラーと区別することです。

まず、印を付けた入力を読みます。

hdfs dfs -cat /user/labex/job-diagnostics/data/rejected.txt

通常の商品行に続いて BAD_RECORD があります。この学習用ジョブでは Map の試行回数を1回にし、同じ意図的な失敗を何度も繰り返さないようにしています。次のコマンドは、失敗するのが期待される動作です。

hadoop jar /home/labex/project/tools/controlled-failure.jar /user/labex/job-diagnostics/data/rejected.txt /user/labex/job-diagnostics/results/failed-example > /home/labex/project/output/failed-job.log 2>&1

プロンプトを待ってから、ログの末尾を読みます。

tail -n 25 /home/labex/project/output/failed-job.log

前の例とは違い、この実行には、投入された YARN アプリケーションとタスク失敗の証拠があるはずです。前の実験と同じアプリケーション一覧のパターンで、実際の ID を取得します。

yarn application -list -appStates ALL | grep -o 'application_[0-9]*_[0-9]*' > /home/labex/project/output/failed-application-id.txt

レポートを問い合わせて保存します。

yarn application -status "$(cat /home/labex/project/output/failed-application-id.txt)" > /home/labex/project/output/failed-application-status.txt

レポートを読みます。

cat /home/labex/project/output/failed-application-status.txt

アプリケーションの識別子、最終ステータス、診断情報を探してください。最終ステータスは FAILED のはずです。このレポートは手書きの失敗ラベルではなく、YARN から得た証拠です。実際の集約ログも読みます。

yarn logs -applicationId "$(cat /home/labex/project/output/failed-application-id.txt)" > /home/labex/project/output/failed-application.log

grep を使い、ログ内で既知の学習用診断メッセージを探します。

grep 'Training input rejected' /home/labex/project/output/failed-application.log

メッセージは印を付けた記録を示しています。単にコマンドが0以外で終わったという結果から、アプリケーションとタスクのログに裏付けられた具体的な説明まで進めました。失敗するたびにクラスターを再起動しようとせず、この証拠を残しましょう。

バッチの選択を修正して実行を完了する

このステップでは、正常な入力と新しい出力ディレクトリを使い、証拠に基づく短い診断記録を残します。

レポートで使う入力は clean.txt です。拒否されたファイルは学習用のサンプルでした。両方の元ファイルを残してください。既習の WordCount サンプルを正常なファイルだけに対して投入し、新しい結果ディレクトリを指定します。

hadoop jar /opt/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.5.0.jar wordcount /user/labex/job-diagnostics/data/clean.txt /user/labex/job-diagnostics/results/successful-run > /home/labex/project/output/successful-job.log 2>&1

このコマンドは正常に終了するはずです。入力には notebook が2回、pen と folder が1回ずつあります。結果を読みます。

hdfs dfs -cat '/user/labex/job-diagnostics/results/successful-run/part-*' | sort

期待される集計は次のとおりです。

folder 1
notebook 2
pen 1

成功したドライバーのログには、アプリケーション ID が含まれます。sort -u は並べ替えと同一行の重複除去を行い、この実行の ID を1つだけ残します。

grep -o 'application_[0-9]*_[0-9]*' /home/labex/project/output/successful-job.log | sort -u > /home/labex/project/output/successful-application-id.txt

実際に成功したアプリケーションの状態を確かめます。

yarn application -status "$(cat /home/labex/project/output/successful-application-id.txt)"

最終ステータスは SUCCEEDED のはずです。先ほどの証拠を、1つのローカル診断記録にまとめます。

cat /home/labex/project/output/connection-error.log /home/labex/project/output/missing-input.log /home/labex/project/output/existing-output.log /home/labex/project/output/failed-application-status.txt > /home/labex/project/output/diagnosis.md

修復の選択を追記します。printf はテキストを表示し、\n は改行、>> は保存した証拠を置き換えずに追記することを表します。

printf '\nRepair: select /user/labex/job-diagnostics/data/clean.txt and use the new /user/labex/job-diagnostics/results/successful-run output. Preserve original inputs and the existing result directory.\n' >> /home/labex/project/output/diagnosis.md

この記録は、エラー、観察、対処を結び付けます。サービスの停止や、自分のアクセス範囲外のプラットフォーム障害であれば、ストレージを再フォーマットせず、接続先とメッセージを記録して問題を報告してください。ここで学んだ問題には、特定のパスや入力の選択を直すだけで十分でした。

まとめ

接続エラー、入力不足、既存の出力パスを、受け付けられた YARN アプリケーション内のタスク失敗と区別しました。実際のアプリケーション状態とタスクログで意図的な拒否を説明し、正常な入力と新しい出力パスで正しいバッチを完了しました。

このコースの最後のチャレンジでは、これらの習慣を入力の整理と権限管理に組み合わせます。これまで練習した方法を使い、新しいバッチを独力で完了してください。