Skip to content
About
Main content

Task re-execution and blacklisting

Why does a large job need re-execution to finish at all, and what does blacklisting a node cost?

What it is. At job scale, failure stops being rare. Take a batch job with n = 10⁴ tasks, each with failure probability p = 10⁻³. The probability that no task fails is

(1 − p)ⁿ ≈ e⁻¹⁰ ≈ 4.5 × 10⁻⁵.

(Check: n × p = 10⁴ × 10⁻³ = 10, and (1 − p)ⁿ ≈ e^(−np) = e⁻¹⁰.) A job of this size almost always contains a failure. Job-level success is not something you can buy from reliable parts. It must be manufactured by re-execution. This is why batch engines have retry built in, while a single-process program does not: the same p that is negligible at n = 10 is certain at n = 10⁴. It is Wanjiru's billing-rollup.

Re-executing a failed task up to k times changes the formula from (1 − p)ⁿ to (1 − pᵏ)ⁿ. With k = 3: pᵏ = 10⁻⁹, so (1 − 10⁻⁹)^10,000 ≈ 1 − 10⁻⁵, nearly 1. This works only if attempts are independent, the third time this article has depended on that condition.

tasks in the job
failure probability of one task attempt
attempts allowed per task
no retry (k = 1)k = 2k = 3
Data table
Chance the whole job succeeds, by tasks (p = 10⁻³ per attempt)
Tasks nseriesP(job succeeds)
10no retry (k = 1)0.99
11.9no retry (k = 1)0.988
14.1no retry (k = 1)0.986
16.8no retry (k = 1)0.983
20no retry (k = 1)0.98
23.7no retry (k = 1)0.977
28.2no retry (k = 1)0.972
33.5no retry (k = 1)0.967
39.8no retry (k = 1)0.961
47.3no retry (k = 1)0.954
56.2no retry (k = 1)0.945
66.8no retry (k = 1)0.935
79.4no retry (k = 1)0.924
94.4no retry (k = 1)0.91
112no retry (k = 1)0.894
133no retry (k = 1)0.875
158no retry (k = 1)0.853
188no retry (k = 1)0.828
224no retry (k = 1)0.799
266no retry (k = 1)0.766
316no retry (k = 1)0.729
376no retry (k = 1)0.687
447no retry (k = 1)0.64
531no retry (k = 1)0.588
631no retry (k = 1)0.532
750no retry (k = 1)0.472
891no retry (k = 1)0.41
1.06Kno retry (k = 1)0.347
1.26Kno retry (k = 1)0.284
1.5Kno retry (k = 1)0.224
1.78Kno retry (k = 1)0.169
2.11Kno retry (k = 1)0.121
2.51Kno retry (k = 1)0.081
2.99Kno retry (k = 1)0.05
3.55Kno retry (k = 1)0.029
4.22Kno retry (k = 1)0.015
5.01Kno retry (k = 1)0.007
5.96Kno retry (k = 1)0.003
7.08Kno retry (k = 1)0.001
8.41Kno retry (k = 1)0
10Kno retry (k = 1)0
11.9Kno retry (k = 1)0
14.1Kno retry (k = 1)0
16.8Kno retry (k = 1)0
20Kno retry (k = 1)0
23.7Kno retry (k = 1)0
28.2Kno retry (k = 1)0
33.5Kno retry (k = 1)0
39.8Kno retry (k = 1)0
47.3Kno retry (k = 1)0
56.2Kno retry (k = 1)0
66.8Kno retry (k = 1)0
79.4Kno retry (k = 1)0
94.4Kno retry (k = 1)0
112Kno retry (k = 1)0
133Kno retry (k = 1)0
158Kno retry (k = 1)0
188Kno retry (k = 1)0
224Kno retry (k = 1)0
266Kno retry (k = 1)0
316Kno retry (k = 1)0
376Kno retry (k = 1)0
447Kno retry (k = 1)0
531Kno retry (k = 1)0
631Kno retry (k = 1)0
750Kno retry (k = 1)0
891Kno retry (k = 1)0
1.06Mno retry (k = 1)0
1.26Mno retry (k = 1)0
1.5Mno retry (k = 1)0
1.78Mno retry (k = 1)0
2.11Mno retry (k = 1)0
2.51Mno retry (k = 1)0
2.99Mno retry (k = 1)0
3.55Mno retry (k = 1)0
4.22Mno retry (k = 1)0
5.01Mno retry (k = 1)0
5.96Mno retry (k = 1)0
7.08Mno retry (k = 1)0
8.41Mno retry (k = 1)0
10Mno retry (k = 1)0
10k = 21
11.9k = 21
14.1k = 21
16.8k = 21
20k = 21
23.7k = 21
28.2k = 21
33.5k = 21
39.8k = 21
47.3k = 21
56.2k = 21
66.8k = 21
79.4k = 21
94.4k = 21
112k = 21
133k = 21
158k = 21
188k = 21
224k = 21
266k = 21
316k = 21
376k = 21
447k = 21
531k = 20.999
631k = 20.999
750k = 20.999
891k = 20.999
1.06Kk = 20.999
1.26Kk = 20.999
1.5Kk = 20.999
1.78Kk = 20.998
2.11Kk = 20.998
2.51Kk = 20.997
2.99Kk = 20.997
3.55Kk = 20.996
4.22Kk = 20.996
5.01Kk = 20.995
5.96Kk = 20.994
7.08Kk = 20.993
8.41Kk = 20.992
10Kk = 20.99
11.9Kk = 20.988
14.1Kk = 20.986
16.8Kk = 20.983
20Kk = 20.98
23.7Kk = 20.977
28.2Kk = 20.972
33.5Kk = 20.967
39.8Kk = 20.961
47.3Kk = 20.954
56.2Kk = 20.945
66.8Kk = 20.935
79.4Kk = 20.924
94.4Kk = 20.91
112Kk = 20.894
133Kk = 20.875
158Kk = 20.853
188Kk = 20.828
224Kk = 20.799
266Kk = 20.766
316Kk = 20.729
376Kk = 20.687
447Kk = 20.64
531Kk = 20.588
631Kk = 20.532
750Kk = 20.472
891Kk = 20.41
1.06Mk = 20.347
1.26Mk = 20.284
1.5Mk = 20.224
1.78Mk = 20.169
2.11Mk = 20.121
2.51Mk = 20.081
2.99Mk = 20.051
3.55Mk = 20.029
4.22Mk = 20.015
5.01Mk = 20.007
5.96Mk = 20.003
7.08Mk = 20.001
8.41Mk = 20
10Mk = 20
10k = 31
11.9k = 31
14.1k = 31
16.8k = 31
20k = 31
23.7k = 31
28.2k = 31
33.5k = 31
39.8k = 31
47.3k = 31
56.2k = 31
66.8k = 31
79.4k = 31
94.4k = 31
112k = 31
133k = 31
158k = 31
188k = 31
224k = 31
266k = 31
316k = 31
376k = 31
447k = 31
531k = 31
631k = 31
750k = 31
891k = 31
1.06Kk = 31
1.26Kk = 31
1.5Kk = 31
1.78Kk = 31
2.11Kk = 31
2.51Kk = 31
2.99Kk = 31
3.55Kk = 31
4.22Kk = 31
5.01Kk = 31
5.96Kk = 31
7.08Kk = 31
8.41Kk = 31
10Kk = 31
11.9Kk = 31
14.1Kk = 31
16.8Kk = 31
20Kk = 31
23.7Kk = 31
28.2Kk = 31
33.5Kk = 31
39.8Kk = 31
47.3Kk = 31
56.2Kk = 31
66.8Kk = 31
79.4Kk = 31
94.4Kk = 31
112Kk = 31
133Kk = 31
158Kk = 31
188Kk = 31
224Kk = 31
266Kk = 31
316Kk = 31
376Kk = 31
447Kk = 31
531Kk = 30.999
631Kk = 30.999
750Kk = 30.999
891Kk = 30.999
1.06Mk = 30.999
1.26Mk = 30.999
1.5Mk = 30.999
1.78Mk = 30.998
2.11Mk = 30.998
2.51Mk = 30.997
2.99Mk = 30.997
3.55Mk = 30.996
4.22Mk = 30.996
5.01Mk = 30.995
5.96Mk = 30.994
7.08Mk = 30.993
8.41Mk = 30.992
10Mk = 30.99

Blacklisting restores independence

When failures cluster on one node (a bad disk, a bad network card), retrying on the same node gives dependent attempts. So (excluding a node from scheduling) is an online classifier that decides which failures are caused by the node. Like every classifier working on little evidence, it has two errors with different costs:

  • Blacklist a healthy node: you lose capacity. Under broad, load-induced failure you can blacklist the entire fleet, a real and spectacular production outcome.
  • Fail to blacklist a sick node: tasks keep landing on it, and the retry count is consumed by the same fault.

So every implementation has decay on entries (a node returns after some time), a quota (never exclude more than a fraction), and a scope decision (per stage or per application). Structurally this is the same object as a : a guess with unequal costs and no ground truth.

The unit of failure is not the unit of retry

Re-executing a task recovers a task. But losing an executor (a worker process) loses its cached blocks and its shuffle files too, so other tasks' completed work dies with it. This repeats at every level: container, node, zone (a separate data centre building within a region).

Not covered here. Speculative execution (starting a second copy of a slow task) treats slowness rather than failure and is a different model. The record that kills every attempt is the of Making a repeat harmless.