Definition · Conditional expectationFor a random variable X and an event B with P(B) > 0, the conditional expectation E[X | B] is the expectation of X computed over only the outcomes in which B happened, with their probabilities renormalised by dividing by P(B).
That is the whole definition, and it is all this lesson needs. Discrete Mathematics gives conditional probability in “Conditional Probability” and expectation in “Expected Value”; this combines them, and every use of it here is a finite enumeration of three outcomes rather than anything requiring machinery.
The reason it turns up is that the second cache level’s hit rate is not a number about requests. It is a number about the requests that reached it, which are exactly the ones that missed the first level.
Definition · Two levelsA request is served by L1 with probability h₁. If it misses, it is served by L2 with probability h₂ = P(L2 hit | L1 miss). If it misses both it is served by the origin. The global hit rate is the fraction served by either cache and the global miss rate is the fraction reaching the origin.
Every request pays t₁ for the L1 lookup, whether or not it hits. The ones that miss pay t₂ on top for the L2 lookup. The ones that miss both pay t₃ on top of that. Reading the branch forwards gives the mean directly, and enumerating the three outcomes gives the same number as a check.
h₁ = 80% = 4/5, h₂ = 50% = 1/2, t₁ = 1, t₂ = 5, t₃ = 50 ms
outcome probability latency contribution
L1 hit h₁ = 4/5 1 ms 4/5
L1 miss, L2 hit (1−h₁)h₂ = 1/10 6 ms 3/5
both miss (1−h₁)(1−h₂) = 1/10 56 ms 28/5
────────────────────────────────────────────────────────────
all = 1 35/5 = 7 ms
forwards: t₁ + (1−h₁)(t₂ + (1−h₂)t₃) = 1 + (1/5)(5 + (1/2)(50)) = 7
The three probabilities sum to 1 and the contributions sum to the mean, which is the check worth doing every time: if the column does not sum to 1, a conditional rate has been used as an unconditional one somewhere.
The two wrong answers, and why each is tempting
The first is adding the hit rates: 80% + 50% = 130%. It is easy to spot here because it exceeds 100%, and much harder to spot at h₁ = 40% and h₂ = 50%, where it gives a plausible 90% against a true global rate of 70%. Rates only add when the events are disjoint on the same population, and these are not on the same population at all.
The second is reading L2’s measured rate as a global one: “L2 is serving half our traffic.” It is serving half of the L1 misses, which is (1/5)(1/2) = 1/10 of all requests. The monitoring is not lying; it is answering a question about a population that the reader has substituted for another one.
Example · What a level is worthSet h₂ = 0 — an L2 that never hits — and 20% of requests reach the origin for a mean of 12 ms. Raise h₂ to 50% and the origin share halves to 10% and the mean falls to 7 ms. The halving of origin load is the whole point, by Hit Rate and Backend Load; the 12 ms is what a level that never hits still costs, because every L1 miss pays t₂ on the way to an origin it was going to reach anyway.
That last clause is the cost of a second level and it is easy to overlook. A level that rarely hits adds its lookup time to every request that misses the level above and returns nothing for it. The arithmetic is (1 − h₁)t₂ of pure overhead against (1 − h₁)h₂t₃ of saving, and the level is worth having when h₂t₃ > t₂ — which at h₂ = 50%, t₃ = 50 ms and t₂ = 5 ms it comfortably is.
One assumption to name: h₂ is treated as a single number, but the population reaching L2 is not a random sample of traffic. It is precisely the unpopular keys, because the popular ones were absorbed above — which is why a second level’s hit rate is generally much lower than the first’s and why it cannot be predicted by pointing the Zipf curve at L2’s size.