hadoopの怪しいMRエラー追跡


hadoopの怪しいMRエラー追跡
自動回転http://f.dataguru.cn/thread-56030-1-1.html
私が使っているのはhadoop 1.0.2です.
この二日間はhbaseの小さいコードを遍歴するMRと小さなコードを書いています.バックグランドでMRを実行する時、バックグランドは比較的に怪しい誤りを出すことができて、この誤りは時にはちょうどMR任務を開始して出して、時には実行の過程の中で報告して、
java.lang.Throwable: Child Error 
at org.apache.hadoop.mapred.TaskRunner.run(TaskRunner.java:258) 
Caused by: java.io.IOException: Task process exit with nonzero status of 1. 
at org.apache.hadoop.mapred.TaskRunner.run(TaskRunner.java:251) 

13/01/24 10:35:09 WARN mapred.JobClient: Error reading task outputhttp://master:50060/tasklog?plaintext=true&attemptid=attempt_attempt_201301241037_0001_r_000002_0&filter=stdout 
13/01/24 10:35:09 WARN mapred.JobClient: Error reading task outputhttp://master:50060/tasklog?plaintext=true&attemptid=attempt_attempt_201301241037_0001_r_000002_0&filter=stderr 
13/01/24 10:35:13 INFO mapred.JobClient: Task Id : attempt_attempt_201301241037_0001_r_000002_0, Status : FAILED 
インターネットで多くの資料を調べましたが、各大名の意見がまちまちで、ほとんどが$ある人は確かにこのように解決しました.実はこの実際の問題はやはり間違った日記の灰色部分の表示を参照してください.この住所を直接開けても、実は何も見えません.$HADOOPUHOME/log/userlogs/{jobid}/{atemptid}探しに行くなら、普通は比較的正確です.
私のこのエラーに対応したのは
launchJvmAndWait(setupCmds, vargs, stdout, stderr, logSize, workDir);
tracker.getTaskTrackerInstrumentation().reportTaskEnd(t.getTaskID());
if (exitCodeSet) {
if (!killed && exitCode != 0) {
if (exitCode == 65) {
tracker.getTaskTrackerInstrumentation().taskFailedPing(t.getTaskID());
}
throw new IOException("Task process exit with nonzero status of " +
exitCode + ".");
}
}
これは明らかです.exitCodeによって判断されたのです.65という状況しか認められません.続いて後をつけます.
launchJvmAndWaitの方法を調べてみます.実際のMRタスクはChild JVMを作成しました.名前はどう呼ばれますか?そのまま呼びましょう.任務の種類によって、mapとreduce JVMMnagerを分けます.これは$実際にここのために準備していますが、配置をしないとデフォルトのパラメータがありますが、mapをより良くして、より速く実行したいなら、mapで使うjvmパラメータを最適化して、taskの数に応じて、対応数のjvmを作成します.1.0.2のコード位置はorg.apache.hadoop.mapred.JvmManagerの122行です.方法名はlaunchJvmです.
public void launchJvm(TaskRunner t, JvmEnv env
) throws IOException, InterruptedException {
if (t.getTask().isMapTask()) {
mapJvmManager.reapJvm(t, env);
} else {
reduceJvmManager.reapJvm(t, env);
}
}
続いてreappJvm方法を調べます.反復的にChildを譲らせます. jvmは走り始める;この中は混乱しています.様々な状態の判断はもちろんここのコメントも信じています.クリックしてみてください.
private synchronized void reapJvm( 
TaskRunner t, JvmEnv env) throws IOException, InterruptedException {
if (t.getTaskInProgress().wasKilled()) {
//the task was killed in-flight
//no need to do the rest of the operations
return;
}
boolean spawnNewJvm = false;
JobID jobId = t.getTask().getJobID();
//Check whether there is a free slot to start a new JVM.
//,or, Kill a (idle) JVM and launch a new one
//When this method is called, we *must* 
// (1) spawn a new JVM (if we are below the max) 
// (2) find an idle JVM (that belongs to the same job), or,
// (3) kill an idle JVM (from a different job) 
// (the order of return is in the order above)
int numJvmsSpawned = jvmIdToRunner.size();
JvmRunner runnerToKill = null;
if (numJvmsSpawned >= maxJvms) {
//go through the list of JVMs for all jobs.
Iterator<Map.Entry<JVMId, JvmRunner>> jvmIter = 
jvmIdToRunner.entrySet().iterator();

while (jvmIter.hasNext()) {
JvmRunner jvmRunner = jvmIter.next().getValue();
JobID jId = jvmRunner.jvmId.getJobId();
//look for a free JVM for this job; if one exists then just break
if (jId.equals(jobId) && !jvmRunner.isBusy() && !jvmRunner.ranAll()){
setRunningTaskForJvm(jvmRunner.jvmId, t); //reserve the JVM
LOG.info("No new JVM spawned for jobId/taskid: " + 
jobId+"/"+t.getTask().getTaskID() +
". Attempting to reuse: " + jvmRunner.jvmId);
return;
}
//Cases when a JVM is killed: 
// (1) the JVM under consideration belongs to the same job 
// (passed in the argument). In this case, kill only when
// the JVM ran all the tasks it was scheduled to run (in terms
// of count).
// (2) the JVM under consideration belongs to a different job and is
// currently not busy
//But in both the above cases, we see if we can assign the current
//task to an idle JVM (hence we continue the loop even on a match)
if ((jId.equals(jobId) && jvmRunner.ranAll()) ||
(!jId.equals(jobId) && !jvmRunner.isBusy())) {
runnerToKill = jvmRunner;
spawnNewJvm = true;
}
}
} else {
spawnNewJvm = true;
}

if (spawnNewJvm) {
if (runnerToKill != null) {
LOG.info("Killing JVM: " + runnerToKill.jvmId);
killJvmRunner(runnerToKill);
}
spawnNewJvm(jobId, env, t);
return;
}
//*MUST* never reach this
LOG.fatal("Inconsistent state!!! " +
"JVM Manager reached an unstable state " +
"while reaping a JVM for task: " + t.getTask().getTaskID()+
" " + getDetails() + ". Aborting. ");
System.exit(-1);
}
最終的な方法はspawnNewJvmに実行されました.この方法の中にはThreadを起動し、JvmRunnerのThreadがあります.中にはchild Jvmstartがあります.threadのrun方法を見ました.中にはrunChildの方法があります.
exitCode = tracker.getTaskController().launchTask(user,
jvmId.jobId.toString(), taskAttemptIdStr, env.setup,
env.vargs, env.workDir, env.stdout.toString(),
env.stderr.toString());
これはjvmの終了コードを作ったものです.これはtaskの軌跡類です.つまりtaskの運転状態を記録します.taskコントローラを呼び出して、任務を実行します.task制御類は抽象類です.具体的な実現類は2つあります.mapred-siteに具体的なコントロールクラスを設定できます.もちろんデフォルトのコントロールクラスです.名前は:org.apphe.hadoop.mapred.Default TaskyController、もう一つは:org.apphe.hadoop.mapred.LinuxTaskyController、もちろん自分で自分のコントロールクラスを書くことができます.mapred-siteで配置すればいいです.
次にDefaultTasControllerのlaunchTask方法を見てみます.最終的にこの終了コードを作る根源を見つけました.new shell Command Exector、bashの命令を実行します.exitCodeはbashの実行状況によって戻ります.
String commandFile = writeCommand(cmdLine, rawFs, p);
rawFs.setPermission(p, TaskController.TASK_LAUNCH_SCRIPT_PERMISSION);
shExec = new ShellCommandExecutor(new String[]{
"bash", "-c", commandFile},
currentWorkDirectory);
shExec.execute();
} catch (Exception e) {
if (shExec == null) {
return -1;
}
int exitCode = shExec.getExitCode();
LOG.warn("Exit code from task is : " + exitCode);
LOG.info("Output from DefaultTaskController's launchTask follows:");
logOutput(shExec.getOutput());
その後、スレッド内のudateOnJvmExit(jvmId、exitCode)の呼び出しにより、実際に前の反復は巡回してタスクスレッドの状態を確認し、問題がありました.jvmの終了コードを更新して、killはタスクを削除します.
私達はlogsの下のタスクログでエラーを見ました.赤い部分は明らかに上のコードが印刷されています.下の階はthreadの実現のため、システムレベルのブロックがあるかもしれません.JvmManagerがchild jvmを殺せないかもしれませんが、反復を除去しました.次の4行目のログ出力です.
2013-01-24 10:41:36,101 WARN org.apache.hadoop.mapred.DefaultTaskController: Exit code from task is : 1
2013-01-24 10:41:36,101 INFO org.apache.hadoop.mapred.DefaultTaskController: Output from DefaultTaskController's launchTask follows:
2013-01-24 10:41:36,101 INFO org.apache.hadoop.mapred.TaskController: 
2013-01-24 10:41:36,101 INFO org.apache.hadoop.mapred.JvmManager: JVM Not killed jvm_201301241037_0001_r_-1615671564 but just removed
2013-01-24 10:41:36,101 INFO org.apache.hadoop.mapred.JvmManager: JVM : jvm_201301241037_0001_r_-1615671564 exited with exit code 1. Number of tasks it ran: 0
2013-01-24 10:41:36,101 WARN org.apache.hadoop.mapred.TaskRunner: attempt_201301241037_0001_r_000002_0 : Child Error
java.io.IOException: Task process exit with nonzero status of 1.
at org.apache.hadoop.mapred.TaskRunner.run(TaskRunner.java:258)
ここで、私たちの根問いは終わりです.まとめてみます.
mr作業を提出して、jobを形成して、jobは2つの部分に分けて、map-job、r-jobの下で一定の数量のtaskを分けて、すべてのtaskは実は下の階は1つのThreadで、専門のTask Controllerが管理に行って、リアルタイムのは状態と実行の情況を判断します;簡単に見えるが、実現するのは複雑だ.