Deep Dives: Reading Order
This directory is the reference core of the curriculum: 21 deep-dive chapters
that together explain how Apache Tez turns a DAG object into a distributed
computation running across a YARN cluster. Each chapter is self-contained and
verified against a real Tez checkout, but they form a dependency graph — read
in the order below the first time through, then use this page as a lookup index
when you return to fix a bug.
Every chapter follows the same shape: a "what you can do after this" opening,
role-based sections that each start with a runnable grep/find, real code
excerpts attributed by module + class (never by line number, because code
moves between branches), at least one diagram, a reading exercise, a "common
bugs and symptoms" table, and a Validation: prove you understand this
gate. Treat that gate as the definition of "read."
The system in one picture
A Tez job has four tiers: the client builds a plan and launches an AM; the
YARN layer schedules containers; the AM (DAGAppMaster) drives the
DAG's state machines and hands work to containers; the tasks run your
input/processor/output code and shuffle data between stages.
┌───────────────────────────────────────────────────────────────────────┐
│ CLIENT JVM (tez-api) │
│ DAG.create() → verify() → DAGPlan(proto) │
│ TezClient.start() ─────────────► YARN RM: submitApplication │
│ TezClient.submitDAG() ──(RPC or staged tez-dag.pb)──► AM │
│ DAGClient.getDAGStatus()/waitForCompletion() ◄── status │
└───────────────────────────────────────────────────────────────────────┘
│ launches ▲ RPC status/kill
▼ │
┌───────────────────────────────────────────────────────────────────────┐
│ DAGAppMaster JVM (tez-dag) │
│ DAGClientServer ── AsyncDispatcher (single thread, the only mutation)│
│ │ ├─ DAGImpl ─ VertexImpl ─ TaskImpl ─ TaskAttemptImpl│
│ │ ├─ TaskSchedulerManager ─► YARN RM (AMRM heartbeat) │
│ │ ├─ ContainerLauncherManager ─► YARN NM (launch) │
│ │ ├─ TaskCommunicatorManager (umbilical RPC server) │
│ │ └─ HistoryEventHandler / RecoveryService (ATS, log) │
└───────────────────────────────────────────────────────────────────────┘
│ launches containers ▲ umbilical: getTask,
▼ │ heartbeat, done, events
┌───────────────────────────────────────────────────────────────────────┐
│ TASK CONTAINER JVM (tez-runtime-internals + tez-runtime-library) │
│ TezChild → LogicalIOProcessorRuntimeTask │
│ Inputs → Processor → Outputs; Sorter/IFile → ShuffleManager/Fetcher │
└───────────────────────────────────────────────────────────────────────┘
flowchart TB
subgraph Client["Client JVM · tez-api"]
DAG["DAG / Vertex / Edge"] --> TCL["TezClient"]
DC["DAGClient (poll/kill)"]
end
subgraph YARN["YARN"]
RM["ResourceManager"]
NM["NodeManagers"]
end
subgraph AM["DAGAppMaster JVM · tez-dag"]
DISP["AsyncDispatcher"]
DI["DAGImpl→VertexImpl→TaskImpl→TaskAttemptImpl"]
SCH["TaskSchedulerManager"]
CL["ContainerLauncherManager"]
TCM["TaskCommunicatorManager"]
end
subgraph Task["Task container JVM · runtime"]
RT["LogicalIOProcessorRuntimeTask"]
IPO["Inputs → Processor → Outputs"]
end
TCL -->|submitApplication| RM
RM -->|launch AM| AM
TCL -->|submitDAG RPC| DISP
DISP --> DI
SCH <-->|AMRM heartbeat| RM
CL -->|launch container| NM
NM --> Task
Task <-->|umbilical| TCM
DC -->|getDAGStatus / tryKillDAG| DISP
The through-line: events are the only way to mutate AM state, everything the client sees is a snapshot, and every plan is self-sufficient so the AM can run it (or recover it) without calling back to the client. Hold those three ideas and the 21 chapters stop feeling like trivia.
The module map — a maintainer's mental model
Before the chapters, internalize where code lives. These are the Maven modules
you will cd into (verified against the checkout's root pom.xml):
| Module | What lives here | You touch it when |
|---|---|---|
tez-api | The public API and wire format: DAG/Vertex/Edge, all *Descriptors, TezConfiguration, TezClient/DAGClient, the .proto files, serviceplugins/api. No YARN server deps. | Adding config, changing the DAG model, evolving the client or a protocol |
tez-common | Cross-cutting utilities shared by client, AM, and tasks: TezUtils, counters plumbing, reflection, IO helpers. | Adding a shared utility; touching counter serialization |
tez-dag | The AM: DAGAppMaster, the DAGImpl/VertexImpl/TaskImpl/TaskAttemptImpl state machines, schedulers (rm/), launchers (launcher/), recovery, the runtime dag.impl.Edge. Also LocalClient. | 90% of AM bugs; scheduling, recovery, lifecycle |
tez-runtime-library | The pluggable I/O: sorters, IFile, ShuffleManager, Fetcher, MergeManager, the ordered/unordered KV inputs/outputs, built-in VertexManagerPlugins. | Shuffle/sort bugs; new edge I/O; partitioners |
tez-runtime-internals | The task-side engine: TezChild, LogicalIOProcessorRuntimeTask, the umbilical client, input/output/processor context impls. | How a task actually runs; umbilical issues |
tez-mapreduce | MapReduce compatibility: MRInput/MROutput, split generation, the mapreduce/mapred shims, MRInputAMSplitGenerator. | Reading Hadoop InputFormats; MR-on-Tez |
tez-tests | Integration tests and MiniTezCluster: end-to-end jobs, fault injection, TestFaultTolerance. | Reproducing cluster behavior; new integration coverage |
hadoop-shim (+ hadoop-shim-impls) | Version-portable adapters over Hadoop APIs that differ across releases, loaded via HadoopShimsLoader. | Supporting a new Hadoop version |
Two more you will meet but this section does not cover in depth: tez-plugins
(ATS/Timeline history backends, aux shuffle service) and tez-examples
(OrderedWordCount and friends, the smallest real DAGs to trace).
Tip: The single most important boundary is
tez-apivstez-dag. TheEdgeyou build (org.apache.tez.dag.api.Edge, tez-api) is a dumb plan record; theEdgethat routes events (org.apache.tez.dag.app.dag.impl.Edge, tez-dag) owns theEdgeManager. Same name, different worlds. When a colleague says "look at VertexImpl / Edge / DAG," always ask which module.
Reading order and rationale
Group 1 — The DAG model and the client
These four define "what is a Tez job" and how it is submitted and observed, before any execution machinery. Start here; without the DAG model in your head every later chapter reads as noise.
| # | File | You will be able to… | Consumed by |
|---|---|---|---|
| 1 | dag-model.md | Build a DAG by hand; recite the three EdgeProperty enums; predict the EdgeManager; enumerate DAG.verify() checks; explain the DAGPlan protobuf | Level 1 (all labs); Level 2 lab 2.1 |
| 2 | logical-physical.md | Explain how a logical DAG gains concrete parallelism at runtime via VertexManagerPlugins | Level 4 lab 4.2; Level 5 lab 5.1 |
| 3 | tez-client.md | Trace create() → start() → submitDAG(); distinguish session/non-session/local; describe the AM launch context and prewarm | Level 3 lab 3.1; Level 7 lab 7.1 |
| 4 | dag-client.md | Tell which backend (AM/RM/Timeline) answered a status; explain the long-poll and the source waterfall; use tryKillDAG correctly | Level 3 lab 3.1; Level 8 lab 8.1 |
Group 2 — AM lifecycle and dispatch
How the AM comes up and how it mutates state. These must precede every per-entity lifecycle chapter.
| # | File | You will be able to… | Consumed by |
|---|---|---|---|
| 5 | dag-app-master.md | Map any early AM log line to a method; list the child services and dispatcher registrations; explain recovery on attempt 2; use ServicePluginsDescriptor | Level 3 lab 3.2; Level 8 lab 8.2 |
| 6 | state-machines.md | Use Hadoop's StateMachineFactory; state the dispatcher invariants; write a state-machine test | Level 4 labs 4.1, 4.3, 4.4 |
| 7 | event-routing.md | Navigate the event hierarchy and apply the "events are the only mutation API" rule | Level 4 (all labs) |
Group 3 — Per-entity lifecycle
Read 8 → 9 → 10 in order; each refers back to events (7) and state-machine primitives (6).
| # | File | You will be able to… | Consumed by |
|---|---|---|---|
| 8 | vertex-lifecycle.md | Trace VertexImpl NEW → SUCCEEDED plus failure/kill paths | Level 4 lab 4.2 |
| 9 | task-lifecycle.md | Explain TaskImpl, speculation, and max-failed-attempts | Level 4 lab 4.3 |
| 10 | task-attempt-lifecycle.md | Follow TaskAttemptImpl through container assignment and termination causes | Level 4 lab 4.4; Level 8 lab 8.2 |
Group 4 — Input / Processor / Output
The code inside the task JVM (tez-runtime-internals + tez-runtime-library).
| # | File | You will be able to… | Consumed by |
|---|---|---|---|
| 11 | ipo-abstractions.md | Implement LogicalInput/LogicalOutput/Processor; use merged inputs | Level 5 lab 5.1; Level 7 lab 7.1 |
| 12 | tez-runtime.md | Explain LogicalIOProcessorRuntimeTask, TezChild, and the umbilical from the task side | Level 5 lab 5.1 |
Group 5 — Shuffle, sort, and counters
| # | File | You will be able to… | Consumed by |
|---|---|---|---|
| 13 | shuffle-sort.md | Walk sorters, IFile, ShuffleManager, Fetcher, MergeManager | Level 5 labs 5.2, 5.3 |
| 14 | counters-diagnostics.md | Read/emit TezCounters; understand ATS publication and diagnostics | Level 8 lab 8.1 |
Do not debug a shuffle problem without reading 13 cold first.
Group 6 — Scheduling and resources
| # | File | You will be able to… | Consumed by |
|---|---|---|---|
| 15 | scheduler.md | Explain TaskSchedulerManager, YarnTaskSchedulerService, and AMRM heartbeats | Level 6 lab 6.2 |
| 16 | container-reuse.md | Trace AMContainerImpl, reuse policy, and idle timeouts | Level 6 labs 6.1, 6.2 |
| 17 | yarn-integration.md | Reason about YARN tokens, the AMRM client, AM failover, and log aggregation | Level 6 lab 6.2 |
Group 7 — Modes and integrations
| # | File | You will be able to… | Consumed by |
|---|---|---|---|
| 18 | local-mode.md | Debug a DAG in-process with LocalContainerLauncher, no YARN | Level 2 labs |
| 19 | hive-integration.md | Explain Hive's TezTask, edge usage, dynamic partition pruning, ATS spans | Level 7 (Hive labs) |
Group 8 — Failure, recovery, and testing
| # | File | You will be able to… | Consumed by |
|---|---|---|---|
| 20 | failure-handling.md | Reason about task retry, vertex rerun, AM restart, and recovery records | Level 8 lab 8.2 |
| 21 | testing-framework.md | Use MiniTezCluster, MockContainerLauncher, DrainDispatcher, and fault injection | Level 2 labs; Level 4 labs |
Which chapter answers which question
| If you are asking… | Read |
|---|---|
What are the fields of an edge and which EdgeManager gets picked? | dag-model.md |
Why is my vertex stuck with parallelism -1? | dag-model.md, then logical-physical.md |
| How does a logical vertex get real task counts at runtime? | logical-physical.md |
Why did start() hang / submitDAG throw SessionNotRunning? | tez-client.md |
| Why does my session AM keep shutting down? | tez-client.md, dag-app-master.md |
Why is getDAGStatus returning stale/RM-sourced data? | dag-client.md |
| Where do I read counters after the job finished? | dag-client.md, counters-diagnostics.md |
| What services does the AM start, and in what order? | dag-app-master.md |
| How does the AM survive a crash? | dag-app-master.md, failure-handling.md |
| How do I plug in a custom scheduler/launcher/communicator? | dag-app-master.md, scheduler.md |
| How do I write a state-machine transition/test? | state-machines.md |
| What events exist and who may emit them? | event-routing.md |
| Why is a vertex/task/attempt stuck in state X? | vertex-lifecycle.md, task-lifecycle.md, task-attempt-lifecycle.md |
| How do I write an Input/Processor/Output? | ipo-abstractions.md |
| How does a task JVM actually run my processor? | tez-runtime.md |
| Why is shuffle slow / a fetcher failing? | shuffle-sort.md |
| Which counters exist and how are they published? | counters-diagnostics.md |
| Why aren't containers being reused? | container-reuse.md, scheduler.md |
| How do tokens / AM failover / log aggregation work? | yarn-integration.md |
| How do I debug without a cluster? | local-mode.md |
| How does Hive drive Tez? | hive-integration.md |
| How do task retry and vertex rerun decisions get made? | failure-handling.md |
| How do I write a reliable integration/fault test? | testing-framework.md |
What a maintainer should internalize from each chapter
- dag-model — the plan is immutable and self-sufficient;
verify()is the contract; the twoEdgeclasses. - logical-physical — parallelism is often decided in the AM, not the client;
VertexManagerPlugins reshape the graph legally. - tez-client — three submission paths behind one method; session
start()launches the AM, non-session defers it; the IPC-size fallback. - dag-client — status is a snapshot with a source; the AM→cache→Timeline→RM
waterfall; the server-side long-poll makes
waitForCompletioncheap. - dag-app-master — the single-threaded dispatcher is the only mutation path; recovery is per-DAG; the scheduler/launcher/communicator are plugins.
- state-machines / event-routing — every transition is an event; handlers must not block; the state machine is the source of truth.
- vertex / task / task-attempt lifecycle — the exact states and the legal transitions; where failure and kill diverge.
- ipo-abstractions / tez-runtime — the task's
initialize→start→run→closecontract; the umbilical is the task's only line home. - shuffle-sort / counters — where bytes and time actually go; how to measure it.
- scheduler / container-reuse / yarn-integration — how containers are asked for, kept, and reclaimed; the YARN contracts underneath.
- local-mode / hive-integration — the two most common real-world entry points into Tez.
- failure-handling / testing-framework — how Tez tolerates faults, and how you prove your change does too.
Order vs index
The deep-dives are an index: they exist to be looked up. Your first pass should follow the groups above. When you return to fix a bug, jump straight to the most relevant chapter and follow its cross-links. Do not skip the Validation section at the end of any chapter — it is the gate before you may claim to have read it, and the difference between "I saw the code" and "I can change the code."