CS PAPERS DEEP READ · PAPER 71

Pivot Tracing

Mace, Roelke & Fonseca · Brown University · SOSP 2015 (Best Paper)

中文 →

What this paper did

An app you use is slow today. The engineer who has to explain why can only read the logs — the running tally the program happened to keep. The catch: that tally records whatever whoever wrote the code thought to record, and the thing you want to ask about today is probably not in it.

In 2015, three researchers at Brown proposed Pivot Tracing, which turns this around: you can put a question to a live system that cannot be stopped, watch answers stream back seconds later, and take the question away when you are done. And it can answer a kind of question nobody could answer before — such as "who, right now, is eating this machine's disk?"

First, something strange

A big system is layers stacked on layers: user jobs on top, a database in the middle, storage at the bottom. The disks at the bottom are saturated and everything is queueing. You ask: who is doing this? Nobody can tell you. Storage only knows "the database asked me to read." The database only knows "some job asked me to." The job only knows it submitted work. Every layer recognizes only the station immediately above it.

It is like a parcel depot that knows only which depot a package came from. Ask it which shopper placed the order and it genuinely does not know. The maddening part is that the answer is not missing — it is shredded across several systems, and no one holds all the pieces.

The idea

The old rule was: you must decide, while writing the code, what you will one day want to look up. Guess right and you can check afterwards. Guess wrong and you must edit the code, redeploy, and wait for the failure to happen again — which is how the expensive outages get away. Pivot Tracing changes the rule: don't record it up front; ask when you want to know.

How it pulls that off

First: the probes are temporary. The program is rewritten in place while it runs; a probe goes in, does its job, and comes back out — like hanging a counter in a shop that is still open for business, with no closing for renovation.

Second, and this is the genuinely new part: let the information ride along with the request. Give every request a small backpack. As it passes through the upper layer, that layer writes in "who I am and who I am running this errand for." The request is handed on and on, and when it finally reaches storage at the bottom, the probe there opens the backpack and sees where it came from — so "this read was N bytes" and "this was ordered by that job" are matched up on the spot.

Think of a hospital: the patient carries their own chart, so the blood lab never has to run back to reception to find out who this is. What matters is that the matching is not done by time — ten thousand things happen in the same millisecond across a datacenter, so guessing by clock is guessing wrong — but by "these two were on the same journey, one before the other."

One more thing makes it cheap: the backpack carries no ledger, just a line saying "this trip belongs to job X," and the arithmetic is done along the way, with only the result sent out at the end. The cost is real too: this only works if every component on the path faithfully passes the backpack along, and if one of them drops it, the thread of causality snaps right there.

What it changed

It changed how the question is posed: from "decide before shipping what to record" to "ask whenever you want." The word everyone now uses, observability, is measured by exactly this — can you answer a question you did not anticipate. And that small backpack now sits, under the name baggage, in the standard interfaces of mainstream tracing.

One line to remember

Give each request a backpack so the top layer can write in "who I am" and the bottom layer can open it and match — and "who is eating this disk right now" gets an answer for the first time; add probes that can be installed into and removed from a running system, and monitoring turns from bookkeeping-in-advance into asking-afterwards.

Want the causal join operator, how a query compiles into probes, and the measured overhead? → Switch to the deep read