Four alerts, one morning
Kabir has just joined the platform team. On his first on-call morning four messages arrive within an hour: an analyst gets “Connection refused”, the ingestion job can't create a folder, a report fails with “No live nodes contain current block”, and a second report has been sitting in ACCEPTED for twenty minutes while the cluster is half empty. He wants to restart everything. Arjun Sir asks him to open the playbook instead.
Shall I just restart the NameNode and the ResourceManager? That fixes most things, right?
A restart hides the evidence and sometimes makes things worse: a restarted NameNode spends minutes in safe mode. Read each message first. Every one of them names a layer: the network, HDFS, YARN, or the job itself. Find the layer, then run the one command that confirms it.
So the four alerts are four different problems?
Yes, and none of them needs a restart. Today we reproduce all four on our lab, then build a playbook from every real failure we met in this course, so that next time the message itself tells you where to look.
A troubleshooting playbook
A troubleshooting playbook (or runbook) is a documented, repeatable procedure for diagnosing and resolving operational incidents in a system. For Hadoop it combines a method (establish the symptom, its scope and recent changes; gather evidence from logs and metrics; form and test a hypothesis; apply the smallest safe fix; verify; record the incident) with a layered checklist that follows the dependency order of the platform: network and name resolution, HDFS (NameNode state and safe mode, DataNodes, block health), YARN (ResourceManager, NodeManagers, queues and limits), the application (ApplicationMaster, task attempts, input data) and security (authentication and authorisation). Each known symptom is mapped to its likely causes and the first command that confirms or rules them out. Incidents are closed with a blameless postmortem that improves the playbook, monitoring and automation.
A doctor doesn't operate on everyone who says “it hurts”. They ask where, since when, what changed, look at test results, and then treat. A playbook is that routine written down for Hadoop: read the message, find the layer, run one command to confirm, fix the smallest thing, and write down what you learned.
Words you'll meet in this lesson
From our lab (Hadoop 3.5.0, four incidents reproduced)
| Wrong port | hdfs dfs -ls hdfs://namenode:9000/ → Call From namenode/172.22.0.2 to namenode:9000 failed on connection exception: java.net.ConnectException: Connection refused (the NameNode listens on 8020) |
|---|---|
| Safe mode | Cannot create directory /incident_b. Name node is in safe mode. Reading menu.csv still worked. |
| Lost replica | A file written with dfs.replication=1 lived only on worker2; with that DataNode stopped, the read gave up after 16 s: No live nodes contain current block. DataNode started → read worked again. |
| Stuck job | Second job in ACCEPTED: Queue's AM resource limit exceeded. AM limit 768 MB, AM used 512 MB, while cluster memory was only 50% used. |
Troubleshooting at three levels
Beginner Read the message, find the layer
- Every Hadoop error message contains a clue word. Connection refused, UnknownHost: network or address. safe mode, block, replica: HDFS. queue, container, ACCEPTED: YARN. Exception at YourClass.java:27: your job.
- Ask three questions before touching anything: what exactly fails, who else is affected, and what changed recently.
- Never “just restart”. Look first, then change one thing.
Intermediate The method, step by step
- Symptom: copy the exact message and time. Scope: one job, one user, one node, one queue, everyone?
- Changes: a deploy, a config edit, a new data source, a node added or removed. Most incidents follow a change.
- Evidence:
hdfs dfsadmin -report,fsck,yarn node -list -all,yarn application -status,yarn logs, JMX metrics. - Hypothesis and one test that proves or disproves it. Then the smallest safe fix, then verify with the same command that showed the problem.
Advanced Operating like a platform team
- Turn every incident into a playbook entry and, where possible, an alert (Lesson 12.4) or an automated check.
- Separate mitigation (get the report out) from root cause (why the queue was too small). Track the second as a ticket.
- Write blameless postmortems with a timeline, the detection gap (our stale-DataNode alert came 296 s late), and concrete follow-ups.
- Practise: game days and DR drills (Lesson 12.2) find gaps before real incidents do.
Exam tip: For “How do you troubleshoot a failed Hadoop job?”, give the method (symptom → scope → recent changes → logs and metrics → hypothesis → smallest fix → verify → postmortem), the layer order (network, HDFS, YARN, application, security) and two real examples with their first command, e.g. safe mode → hdfs dfsadmin -safemode get; stuck in ACCEPTED → yarn application -status.
The layered checklist
Architecture at a glance
Start at the top with the exact message, then walk down the layers in dependency order. A layer can only work if the ones above it work. Each box lists the first commands to run there.
Key commands for each layer
| Layer | Command | What it tells you |
|---|---|---|
| Network | getent hosts namenode, hdfs getconf -confKey fs.defaultFS | Which address a name resolves to; which NameNode URI the client really uses |
| Daemons | jps | Which Java daemons are running on this machine |
| HDFS | hdfs dfsadmin -report, -safemode get | Live/dead DataNodes, capacity, safe mode |
| HDFS | hdfs fsck /path -files -blocks -locations | Missing, corrupt, under-replicated blocks and where replicas are |
| YARN | yarn node -list -all | RUNNING, UNHEALTHY, LOST, DECOMMISSIONED NodeManagers |
| YARN | yarn application -status <app> | State, final status and the diagnostics line |
| YARN | curl …:8088/ws/v1/cluster/scheduler | Queue usage, AM limit, user limits |
| Job | yarn logs -applicationId … -containerId … | The exception and stack trace of a failed attempt |
| Metrics | curl …:9870/jmx | The same numbers the monitoring system reads (Lesson 12.4) |
| Daemon logs | NameNode, ResourceManager logs (docker logs in our lab, $HADOOP_LOG_DIR on servers) | Why a daemon refused to start or stopped |
Symptom → likely cause → first command (real failures from this course)
| Message you see | Likely cause | First command | Lesson |
|---|---|---|---|
Connection refused (namenode:9000) | Wrong port, daemon down, or a name resolving to the wrong network | getent hosts, jps | 12.6, 12.1 |
UnknownHostException: nn-canteen | Name not resolvable (or that NameNode is down) | getent hosts nn-canteen | 7.2 |
Name node is in safe mode. | Startup, too few blocks reported, or manual safe mode | hdfs dfsadmin -safemode get | 12.6, 5.6 |
No live nodes contain current block | All replicas of a block on stopped/dead DataNodes | hdfs fsck /path -files -blocks -locations | 12.6 |
Timed out waiting 20000ms for a quorum | Majority of JournalNodes down: NameNode stops | jps on JournalNode hosts | 7.1 |
The DiskSpace quota … is exceeded … diskspace consumed = 384 MB | Space quota counts a whole block × replication | hdfs dfs -count -q -h /dir | 7.4 |
| Many under-replicated blocks, none missing | Job staging files asked for replication 10 | hdfs fsck / | grep -i "under rep" | 12.4 |
Stuck in ACCEPTED: Queue's AM resource limit exceeded. | Queue's ApplicationMaster limit (10% by default) | yarn application -status | 12.6 |
InvalidResourceRequestException | Asked for more than maximum allocation | yarn node -list -showDetails | 11.2 |
RM won't start: Queue configuration missing child queue names for root | Broken capacity-scheduler.xml | ResourceManager log | 11.4 |
Error: Java heap space | Task heap too small for what it keeps in memory | yarn logs of the attempt | 11.4 |
| Exit code 137 | Container killed (kill -9 or memory limit) | attempt diagnostics (REST) | 8.6 |
NumberFormatException: For input string: "abc" at ItemRevenue.java:27 | Bad input record | yarn logs, then search the data | 11.5 |
Too many counters: 121 max=120 | Dynamic counter per key | attempt diagnostics | 9.4 |
Illegal partition for chai (4) | Partitioner returned a wrong number | yarn logs | 9.2 |
NoSuchMethodException … <init>() | Writable without a no-argument constructor | yarn logs | 9.3 |
PipeMapRed.waitOutputThreads(): subprocess failed with code 1 | Streaming script crashed; real error in stderr | yarn logs -log_files stderr | 9.8 |
ClassNotFoundException: com.github.luben.zstd.RecyclingBufferPool | Jar on the client but not on the task classpath | check -libjars | 10.2 |
FileAlreadyExistsException / InvalidInputException | Output exists / input path wrong | hdfs dfs -ls both paths | 8.6 |
Client cannot authenticate via:[TOKEN, KERBEROS] | No Kerberos ticket | klist | 12.5 |
KerberosAuthException … Unable to obtain password from user | Keytab missing or not readable when the daemon started | klist -kt keytab | 12.5 |
| DR copy “succeeded” but old content remains | Plain DistCp skips same-name, same-size files | rerun with -update | 12.2 |
| Alert arrived minutes late | Stale-DataNode count recomputed on the heartbeat check (296 s in our lab) | check the metric's update interval | 12.4 |
Animated example: the 6 AM report that never came
- 06:05: the report is missing but no failure alert fired. Priya starts with the symptom and asks how far it spreads.
- 06:07:
yarn application -listshows the report has sat in ACCEPTED since 01:00. It never started. - 06:09:
yarn application -statussays “Queue's AM resource limit exceeded.” The cluster is only half full, so it's a queue limit, not capacity. - 06:14: the scheduler REST API shows the queue's ApplicationMaster share used up by a stuck long-running job.
- 06:16: the smallest safe fix: kill the stuck job, which can rerun. No config change and no restart under pressure.
- 06:48: the report is delivered. The postmortem adds an alert and a queue change. (Illustrative scenario, modelled on our lab's real incident D.)
Keep the playbook next to your monitoring: every alert from Lesson 12.4 should link to the playbook entry that says what to check first.
Four incidents on our lab
Run with trouble_lab.sh on the Module 8 lab (in “Run it on your PC”). Each step creates one incident, shows the exact message, and undoes it.
A. Connection refused
The machine answered, but nothing listens on port 9000. “Refused” means the host exists and the port is wrong or the daemon is down; “UnknownHost” would mean the name itself is wrong. Checkhdfs dfs -ls hdfs://namenode:9000/Call From namenode/172.22.0.2 to namenode:9000 failed on connection exception: java.net.ConnectException: Connection refusedhdfs getconf -confKey fs.defaultFS(8020 here) andjps.B. Safe mode
Writes fail, reads work: HDFS is read-only. Before leaving safe mode by hand, find out why it's on (hdfs dfsadmin -safemode enter hdfs dfs -mkdir /incident_b hdfs dfs -cat /user/hadoop/data/menu.csv | head -1 hdfs dfsadmin -safemode leaveSafe mode is ON Cannot create directory /incident_b. Name node is in safe mode. chai,drink,15,A Safe mode is OFF-safemode get, NameNode log): after a restart it waits for enough block reports, and forcing it off with missing DataNodes can expose missing blocks.C. The only replica is on a stopped DataNode
hdfs dfs -D dfs.replication=1 -put -f menu.csv /incident_c.csv hdfs fsck /incident_c.csv -files -blocks -locations docker exec lab8-worker2-1 hdfs --daemon stop datanode hdfs dfs -cat /incident_c.csvDatanodeInfoWithStorage[172.22.0.6 the only replica is on worker2; stopping its DataNode No live nodes contain current block the read gave up after 16 s DataNode back: chai,drink,15,Afsck … -locationsshowed the one replica's address. With replication 1 there is no second copy, so the client tries, waits and gives up. Starting the DataNode made the block available again: no data was lost, only unavailable. With replication 3 this read would have succeeded.D. A job stuck in ACCEPTED on a half-empty cluster
yarn application -list yarn application -status application_…_0019 curl -s http://resourcemanager:8088/ws/v1/cluster/schedulerapplication_1792661456575_0018 RUNNING application_1792661456575_0019 ACCEPTED Diagnostics : … Application is added to the scheduler and is not yet activated. Queue's AM resource limit exceeded. queue default | AM limit 768 MB | AM used 512 MByarn.scheduler.capacity.maximum-am-resource-percentis 0.1 by default: 10% of 6,144 MB ≈ 614 MB, which the scheduler rounds up to 768 MB. One 512 MB ApplicationMaster fits; a second would need 1,024 MB. The cluster had memory free, but the queue had no ApplicationMaster room.Write it down
Blameless: it records what the system allowed, not who submitted the long job. The detection gap and the actions are the most valuable lines.Title Nightly report stuck in ACCEPTED (incident D) Impact report 48 min late, 1 queue, no data loss Timeline 01:00 submitted · 06:05 noticed · 06:09 diagnosed · 06:16 mitigated Root cause queue AM limit (10%) filled by a long-running job Detection no alert for "ACCEPTED too long" ← gap Actions alert on ACCEPTED > 15 min · AM percent 0.1 → 0.3 for reports · job timeout
Under pressure, change one thing at a time and verify with the command that showed the problem. Two changes at once and you won't know which fixed it, or which made it worse.
From message to layer to fix
Six steps through the four real incidents and the method that solved each one.
- A: the client gets “Connection refused” for port 9000.
- B: a mkdir fails in safe mode while a read still works.
- C: the only replica sits on worker2; with its DataNode stopped the read gives up after 16 s.
- D: the second job waits in ACCEPTED because of the queue's ApplicationMaster limit.
- The fixes are small: leave safe mode on purpose, start the DataNode.
- Every incident ends with a written entry that makes the next one faster.
- The problem is in front of everything: the client is knocking on a port where nothing listens.
- The NameNode is up but in safe mode: it serves reads and refuses changes.
- worker2 holds the only replica; once it's down no DataNode can serve the block.
- The queue's ApplicationMaster budget (10% → 768 MB) is used by one AM; the second AM would exceed it.
- Leaving safe mode and starting the DataNode fix B and C; D waits for the first job or a bigger AM percent.
- Each incident lived in exactly one layer. Finding the layer is most of the work.
Playbooks at work
1. On-call in a payments company
Every alert links to a runbook entry: what it means, the first command, the safe mitigation, and whom to call. The on-call engineer follows it before improvising.
2. Blameless postmortems at an e-commerce company
After a festive-sale incident, the team writes a timeline and actions without naming a culprit. The actions (an alert, a quota, a test) are tracked like features.
3. Game days at a telecom operator
The platform team breaks things on purpose in staging (stop a DataNode, fill a queue, expire a ticket) and times how long the on-call team needs to diagnose each one with the playbook.
4. Automated health checks at a government data platform
Steps that are always the same (safe mode? missing blocks? lost NodeManagers? apps stuck in ACCEPTED?) run as a script every few minutes and post a summary, so humans start with the evidence.
5. Support tickets in a university research cluster
Students must attach the application ID, the exact message and the output of yarn application -status. Most tickets are solved from that alone, without logging in.
Simplified; organisations differ in tools and policies.
A symptom matcher for real error messages
The first step of every incident is reading the message. This matcher holds a few playbook rules (a pattern, the layer, the likely cause and the first command) and applies them to real messages from our lab.
import re
RULES = [
(r"Connection refused", "network", "wrong port or daemon down", "getent hosts; jps"),
(r"UnknownHostException", "network", "name not resolvable", "getent hosts <name>"),
(r"in safe mode", "HDFS", "NameNode is read-only", "hdfs dfsadmin -safemode get"),
(r"No live nodes contain", "HDFS", "every replica's DataNode is down", "hdfs fsck <path> -locations"),
(r"AM resource limit exceeded", "YARN", "queue's ApplicationMaster limit", "yarn application -status"),
(r"Java heap space", "job", "task heap too small", "yarn logs (attempt)"),
(r"cannot authenticate via", "security","no Kerberos ticket", "klist"),
]
def diagnose(message):
for pattern, layer, cause, first in RULES:
if re.search(pattern, message, re.IGNORECASE):
return layer, cause, first
return "unknown", "not in the playbook yet", "read the full log; add a rule"
messages = [
"Call From namenode/172.22.0.2 to namenode:9000 failed on connection exception: java.net.ConnectException: Connection refused",
"Cannot create directory /incident_b. Name node is in safe mode.",
"No live nodes contain current block",
"Application is added to the scheduler and is not yet activated. Queue's AM resource limit exceeded.",
"Illegal partition for chai (4)",
]
for m in messages:
layer, cause, first = diagnose(m)
print(f"{layer:8} | {cause:32} | {first}")(r"AM resource limit exceeded", "YARN", "queue's ApplicationMaster limit", "yarn application -status"),Each rule is one playbook row: a clue in the message, the layer, the likely cause and the command that confirms it.return "unknown", "not in the playbook yet", "read the full log; add a rule"A message with no rule is a gap in the playbook. After the incident, add a rule.
Run it on your PC: four incidents on purpose
Run this on your PC in the mr-lab folder with the Module 8 lab running. It creates each incident, prints the exact message, and puts things back: it leaves safe mode, restarts the DataNode it stopped and kills the two sleep jobs. It takes about 3 minutes.
Four incidents and their messages
# trouble_lab.sh: four common incidents reproduced on the Module 8 lab, with the exact message each one gives.
# Run on your PC.
NN="docker exec lab8-namenode-1"
clean() { grep -vE "^\s+at |INFO|^$|WARN.*retry|Retrying" | cut -c1-170; }
echo "== A. 'Connection refused': wrong port in the URI (8020 is right, 9000 was the Hadoop 1/2 habit)"
$NN hdfs dfs -ls hdfs://namenode:9000/ 2>&1 | grep -m1 -oE "Call From .* failed on connection exception: java.net.ConnectException: Connection refused"
echo "== B. 'Name node is in safe mode': writes fail, reads still work"
$NN hdfs dfsadmin -safemode enter 2>/dev/null
$NN hdfs dfs -mkdir /incident_b 2>&1 | grep -m1 -oE "Cannot create directory /incident_b. Name node is in safe mode."
echo " read still works: $($NN hdfs dfs -cat /user/hadoop/data/menu.csv 2>/dev/null | head -1)"
$NN hdfs dfsadmin -safemode leave 2>/dev/null
echo "== C. a file with ONE replica, and its DataNode goes down"
$NN bash -c 'hdfs dfs -D dfs.replication=1 -put -f /tmp/mr/menu.csv /incident_c.csv 2>/dev/null; hdfs fsck /incident_c.csv -files -blocks -locations 2>/dev/null | grep -oE "DatanodeInfoWithStorage\[[0-9.]+"'
ip=$($NN hdfs fsck /incident_c.csv -files -blocks -locations 2>/dev/null | grep -oE "DatanodeInfoWithStorage\[[0-9.]+" | grep -oE "[0-9.]+$" | head -1)
for w in worker1 worker2 worker3; do
if docker exec lab8-$w-1 hostname -i | grep -q "$ip"; then victim=$w; fi
done
echo " the only replica is on $victim; stopping its DataNode"
docker exec lab8-$victim-1 hdfs --daemon stop datanode
$NN bash -c 'start=$(date +%s); hdfs dfs -cat /incident_c.csv 2>&1 | grep -m2 -oE "Could not obtain block: [^ ]+|BlockMissingException|No live nodes contain current block"; echo " the read gave up after $(( $(date +%s) - start )) s"'
docker exec lab8-$victim-1 hdfs --daemon start datanode; sleep 15
echo " DataNode back: $($NN hdfs dfs -cat /incident_c.csv 2>/dev/null | head -1)"
$NN hdfs dfs -rm -skipTrash /incident_c.csv > /dev/null 2>&1
echo "== D. a job stuck in ACCEPTED"
T=/opt/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-3.5.0-tests.jar
for n in 1 2; do $NN bash -c "export HADOOP_CLASSPATH=$T; yarn org.apache.hadoop.mapreduce.SleepJob -libjars $T -m 30 -r 1 -mt 30000 -rt 1000 > /tmp/acc$n.log 2>&1" & sleep 3; done
sleep 25
docker exec lab8-resourcemanager-1 yarn application -list 2>/dev/null | grep -E "RUNNING|ACCEPTED" | awk -F'\t' '{print " ", $1, $6}' | tr -s ' '
app=$(docker exec lab8-resourcemanager-1 yarn application -list -appStates ACCEPTED 2>/dev/null | grep -o "application_[0-9_]*" | head -1)
docker exec lab8-resourcemanager-1 yarn application -status $app 2>/dev/null | grep -A2 "Diagnostics" | sed 's/^\s*/ /' | cut -c1-200
echo "-- the queue's limit on ApplicationMasters:"
docker exec lab8-namenode-1 curl -s http://resourcemanager:8088/ws/v1/cluster/scheduler | python3 -c '
import sys, json
q = json.load(sys.stdin)["scheduler"]["schedulerInfo"]["queues"]["queue"][0]
r = q["resources"]["resourceUsagesByPartition"][0]
print(" queue", q["queueName"], "| AM limit", r["amLimit"]["memory"], "MB | AM used", r["amUsed"]["memory"], "MB | maxAMPercent", q.get("maxAMPercent", q.get("maximumAMResourcePercent")))' 2>&1 | head -2
for a in $(docker exec lab8-resourcemanager-1 yarn application -list 2>/dev/null | grep -o "application_[0-9_]*"); do docker exec lab8-resourcemanager-1 yarn application -kill $a > /dev/null 2>&1; done
wait
# Run on your PC, in the mr-lab folder:
# bash trouble_lab.shReal output. The DataNode holding the single replica depends on placement (worker2 in our run). The diagnostics line is cut at 200 characters; the full line also prints the AM partition and resource numbers.
Walking the layers in order
A checklist in dependency order: stop at the first layer that fails. Watch layer and ok.
Worked examples: real problems, solved and traced in memory
Four incidents from different industries, each diagnosed from its message.
An analyst at a hospital network gets “UnknownHostException”
Problem statement
A notebook in the hospital analytics team fails with java.net.UnknownHostException: nn-records. Other users can read HDFS. What layer is it, and what is the first check?
message + scope: one user
same? False | fix the client config: hdfs://nn-records:8020 -> hdfs://nn-patients:8020
Approach
- UnknownHost: the name itself does not resolve (not “refused”).
- Scope is one user, so the cluster is fine; look at that client.
- Compare the client's fs.defaultFS with a working user's.
Solution: run it live
What happens in memory, step by step
Recorded from a real Python run: press Next to execute one line at a time. Watch variables change in each frame, and lists and dictionaries (numbered #1, #2 …) fill up as objects.
A telecom ingest job fails at midnight: safe mode
Problem statement
After planned maintenance on a telecom operator's cluster, the CDR ingest fails with “Name node is in safe mode.” hdfs dfsadmin -report shows 38 of 40 DataNodes live and the NameNode reports 99.7% of blocks. The threshold is 99.9%. What do you do?
38/40 live · 99.7% reported · threshold 99.9%
150,000 blocks not reported yet; threshold needs 49,950,000
Approach
- Safe mode is waiting for block reports.
- Two DataNodes are missing: start them, don't force safe mode off.
- Check what forcing would mean: some blocks have no live replica yet.
Solution: run it live
What happens in memory, step by step
Recorded from a real Python run: press Next to execute one line at a time. Watch variables change in each frame, and lists and dictionaries (numbered #1, #2 …) fill up as objects.
An e-commerce team's jobs wait in ACCEPTED
Problem statement
During a sale, 6 small jobs in the analytics queue sit in ACCEPTED. The queue has 200 GB, maximum-am-resource-percent 0.1 and each ApplicationMaster uses 4 GB. 5 are running. Why do the rest wait, and what is a safe change?
200 GB · AM 10% · 4 GB per AM
AM budget 20 GB -> 5 AMs; with 0.3: 15 AMs
Approach
- AM budget = 10% of the queue.
- Count how many AMs fit.
- Raise the percent for many small jobs, or wait.
Solution: run it live
What happens in memory, step by step
Recorded from a real Python run: press Next to execute one line at a time. Watch variables change in each frame, and lists and dictionaries (numbered #1, #2 …) fill up as objects.
A bank's report fails with Java heap space only on month end
Problem statement
A bank's reconciliation job succeeds every day but fails on the last day of the month with Error: Java heap space in one reduce task. Daily data is 40 GB; month-end adds a 25× spike for one account type. What is the likely cause and the first command?
one reducer · month end · 25× one key
normal reducer 0.8 GB, hot reducer 10.8 GB
Approach
- Only one reduce task fails: think skew (Lesson 8.5).
- A reducer holding all values of one hot key in memory runs out of heap.
- First: the failed attempt's log and the reduce input records per task.
Solution: run it live
What happens in memory, step by step
Recorded from a real Python run: press Next to execute one line at a time. Watch variables change in each frame, and lists and dictionaries (numbered #1, #2 …) fill up as objects.
Check yourself
Quick revision
Lesson 12.6 in one screen
- Method: symptom → scope → recent changes → evidence → hypothesis → smallest safe fix → verify → postmortem.
- Layers in order: network/DNS → HDFS → YARN → job → security; stop at the first broken one.
- Connection refused = host reached, port wrong or daemon down; UnknownHost = the name doesn't resolve.
- Safe mode: reads work, writes fail; find why before forcing
-safemode leave. - “No live nodes contain current block”: every replica's DataNode is down;
fsck -locations. - ACCEPTED on an idle cluster: check
yarn application -statusdiagnostics (AM limit, queue limits). - Job errors:
yarn logsof the failed attempt gives the exception and line (Lesson 11.5). - Blameless postmortem: timeline, root cause, detection gap, tracked actions; add a playbook rule and an alert.
Interview and viva questions
How do you troubleshoot a Hadoop cluster problem?
Record the exact error and time, establish the scope (one job, user, node, queue or the whole cluster) and what changed recently. Then check the layers in order: network and name resolution, HDFS (NameNode state, safe mode, DataNodes, blocks with dfsadmin -report and fsck), YARN (yarn node -list -all, application status and queue limits), the job (yarn logs of the failed attempt) and security (klist, permissions). Apply the smallest safe fix, verify with the same command, and write a postmortem.
Why is my YARN application stuck in ACCEPTED?
The scheduler has accepted it but cannot start its ApplicationMaster. Common causes are the queue's AM resource limit (maximum-am-resource-percent, 10% by default), the queue or user limit being used up, no NodeManager with enough free memory, or node labels that no node matches. yarn application -status shows the diagnostics, e.g. “Queue's AM resource limit exceeded.”
What does “Name node is in safe mode” mean?
The NameNode is read-only: it serves reads but refuses changes to the namespace. It enters safe mode at startup until enough DataNodes have reported their blocks (99.9% by default), or when an administrator turns it on. Check with hdfs dfsadmin -safemode get and find out why before leaving it by hand.
What does “Could not obtain block” or “No live nodes contain current block” mean?
The client could not read any replica of a block, usually because the DataNodes holding all replicas are down or unreachable. Use hdfs fsck <path> -files -blocks -locations to see where the replicas are, bring those DataNodes back, and check that important data has replication 3.
What is a blameless postmortem?
A written review after an incident that records the timeline, impact, root cause, why detection was late and the follow-up actions, without blaming individuals. It assumes people acted reasonably with the information they had and focuses on changing the system so the incident can't repeat.
Practice problems
Diagnosis exercises using the real messages and numbers from our lab.
Name the layer
For each message, print the layer: network, HDFS, YARN or job.
4 real messages
network <- Connection refused HDFS <- Name node is in safe mode. YARN <- Queue's AM resource limit exceeded. job <- Error: Java heap space
Show solution and explanation
msgs = {"Connection refused": "network", "Name node is in safe mode.": "HDFS",
"Queue's AM resource limit exceeded.": "YARN", "Error: Java heap space": "job"}
for m, layer in msgs.items():
print(f"{layer:8} <- {m}")How it works: The clue word in each message names its layer.
How late was the alert?
The DataNode stopped at 10:21:12 and the stale alert appeared at 10:26:08 (Lesson 12.4). How many seconds is the detection gap?
two times
296 s
Show solution and explanation
from datetime import datetime
a, b = datetime.strptime("10:21:12", "%H:%M:%S"), datetime.strptime("10:26:08", "%H:%M:%S")
print((b - a).seconds, "s")How it works: 296 s: the stale-node count is recomputed on the NameNode's heartbeat check.
AM budget
What is 10% of 6,144 MB, rounded up to a multiple of 256 MB?
6,144 MB · 0.1 · 256
768 MB
Show solution and explanation
import math
print(math.ceil(6144 * 0.1 / 256) * 256, "MB")How it works: 768 MB, the AM limit our scheduler reported.
Replicas left
Given each block's replica nodes and the stopped node, list blocks that become unreadable.
3 blocks · worker2 stopped
['blk_1']
Show solution and explanation
blocks = {"blk_1": ["worker2"], "blk_2": ["worker1", "worker2", "worker3"], "blk_3": ["worker2", "worker3"]}
down = {"worker2"}
print([b for b, nodes in blocks.items() if set(nodes) <= down])How it works: Only blk_1 (replication 1) is lost from view; the others still have a live replica.
Build a timeline
Turn incident notes into minutes since the first event, skipping lines without a time.
incident notes
+ 0 min report missing + 4 min AM limit found + 11 min stuck job killed + 43 min report delivered
Show solution and explanation
notes = ["06:05 report missing", "checked dashboards", "06:09 AM limit found", "06:16 stuck job killed", "06:48 report delivered"]
t0 = None
for n in notes:
first = n.split()[0]
if ":" not in first:
continue
h, m = map(int, first.split(":"))
t0 = t0 if t0 is not None else h * 60 + m
print(f"+{h * 60 + m - t0:3d} min {n[6:]}")How it works: Diagnosed in 4 minutes, mitigated in 11, delivered in 43: the timeline of a postmortem.
Is it the cluster or the job?
A job failed on 4 attempts on 4 different nodes with the same exception. Is the cause the nodes or the job/data?
4 attempts, 4 nodes, 1 exception
job or data
Show solution and explanation
attempts = [("worker1", "NumberFormatException"), ("worker2", "NumberFormatException"),
("worker3", "NumberFormatException"), ("worker1", "NumberFormatException")]
nodes = {n for n, _ in attempts}
errors = {e for _, e in attempts}
print("job or data" if len(errors) == 1 and len(nodes) > 1 else "look at the nodes")How it works: The same error on different nodes points at the code or the data (Lesson 11.5), not at a machine.
Cost of restarting first
A NameNode restart costs 12 minutes of safe mode during which 300 analysts can't write. Diagnosing first takes 5 minutes and needs no restart. Compare lost analyst-minutes.
12 min × 300 vs 5 min × 1
restart first: 3600 analyst-minutes lost; diagnose first: 5 engineer-minutes
Show solution and explanation
print("restart first:", 12 * 300, "analyst-minutes lost; diagnose first:", 5, "engineer-minutes")How it works: 3,600 analyst-minutes vs 5: “just restart” is expensive even when it works.
A tiny rule engine with priorities
Some messages match several rules (a Java heap space inside a failed Streaming task). Return the most specific rule (longest pattern).
rules + message
subprocess failed -> streaming script crashed
Show solution and explanation
import re
rules = {"Java heap space": "task heap too small", "subprocess failed": "streaming script crashed", "failed": "something failed"}
msg = "PipeMapRed.waitOutputThreads(): subprocess failed with code 1"
hits = [p for p in rules if re.search(p, msg)]
best = max(hits, key=len)
print(best, "->", rules[best])How it works: “subprocess failed” beats the generic “failed”: specific rules first, generic ones as a fallback.
Real-world scenario questions (asked in company interviews)
Troubleshooting questions test method more than memory. Interviewers want to hear how you think under pressure.
“A user says HDFS is down. What do you do?”
A classic open question.
The interviewer is checking: method before action.
Show a strong answer
- Get the exact message and time; check the scope: can I and other users list HDFS?
- Check the NameNode (jps, web UI,
hdfs dfsadmin -report,-safemode get) and the DataNodes. - If only that user fails, look at their client config and network (Connection refused, UnknownHost); if everyone fails, it's the NameNode or safe mode.
Jobs stuck in ACCEPTED, cluster 40% used
The business is waiting for a report.
The interviewer is checking: queue limits, not “add nodes”.
Show a strong answer
yarn application -statusdiagnostics: e.g. “Queue's AM resource limit exceeded” or user limit reached.- Scheduler REST/UI for that queue: AM limit vs AM used, capacity vs used, user limits.
- Mitigate (kill or move a stuck job), then fix: raise maximum-am-resource-percent for queues with many small jobs, add an alert for long ACCEPTED times.
fsck reports missing blocks after a rack power failure
One rack of 20 nodes went down; it's back now, but 30 blocks are still missing.
The interviewer is checking: calm recovery, not deleting data.
Show a strong answer
hdfs fsck / -list-corruptfileblocksto list the files;-locationsshows where replicas should be.- Check that all DataNodes of the rack really came back (dfsadmin -report), with all their disks mounted; missing disks are a common cause.
- Only for blocks that are truly gone: restore from DR/backup (Lesson 12.2) or re-ingest; never run
fsck -deletefirst.
“The same incident happened three times this quarter”
A director asks why.
The interviewer is checking: postmortems that lead to change.
Show a strong answer
- Each time it was mitigated but the root-cause action wasn't owned or finished: track postmortem actions like product work.
- Add detection (an alert), prevention (a quota, a config check in CI) and a playbook rule, so the fourth time is short or impossible.
- Keep reviews blameless so people report near-misses early.