Decide after you've seen the whole trace — tail-based sampling and the decision window

To judge a trace on whole-trace facts you must route every span of that trace to the same decision point, hold them for a window, and accept that anything arriving after the window is judged on its own.

Previously

A head decision is made before anyone knows how the request turned out. The only way to keep exactly the interesting traces is to decide after the fact.

Scene 09

Decide after you've seen the whole trace

  1. Watch
  2. Try it
  3. Predict
  4. Capture
tail sampling: decide after the trace — if you can see all of itinstrument → export → collect → sample → store → find → readinstrumentexportcollectsamplejudge after 30 sstorefindreadspans arriving4bf92f35…0e0e4736b30e6f18…2c47a9017a41c9d2…5e10b6c3routinground-robinany box takes any span→ each holds half a tracepolicy · keep errors + slowdecision point A4bf92f35…0e0e4736partial0/6 spansb30e6f18…2c47a901partial0/6 spans7a41c9d2…5e10b6c3partial0/6 spansbuffer 0 / 50k tracesdecision point B4bf92f35…0e0e4736partial0/6 spansb30e6f18…2c47a901partial0/6 spans7a41c9d2…5e10b6c3partial0/6 spansbuffer 0 / 50k tracesdecision windowbuffer 30s, then judge051swindow 30sorders-worker spans +45s? queue hopjudged without itthe window closed before the worker's spans arrivedtraces one box can judge whole0 of 3kept per 1,000 traces (example)fragments onlyorders-worker spans, +45 smissed the windowbuffered before any policy runs30k of 50k heldEvery box holds half of every trace, so every verdict is taken on a fragment of the evidence.
What to watch for

How do you keep exactly the traces worth keeping, when whether a trace is worth keeping — did anything error, was the whole checkout over 2 s — is only knowable after the request is over? You wait. Watch six spans of each trace arrive from Shopfront's services and get handed to two decision points, which hold them instead of writing them straight to storage. Count the filled segments on each box as the spans land, and watch both memory meters at the same time.

Continue unlocks when the animation finishes.
Implementation

Highlighted lines are the ones running in the diagram right now.

Router.route
the front tier picks which box a span goes to
# routing_key: traceID is the default for traces
def route(span, boxes):
if routing_key == "round_robin":
i = next_index() # whoever is next
else:
i = consistent_hash(span.trace_id) % len(boxes)
boxes[i].send(span)
# membership change moves ~R/N of the trace ids
TailSampler.on_span
hold every arriving trace, keep or not
decision_wait = 30s # default
num_traces = 50_000 # circular buffer
def on_span(span):
tid = span.trace_id
if tid not in buffer: # judged ones were popped
if len(buffer) == num_traces:
evict_oldest() # ..._dropped_too_early
buffer[tid] = new_trace()
start_timer(tid, decision_wait)
buffer[tid].spans.append(span)
TailSampler.decide
the timer fires; judge what is in the buffer
def decide(tid):
trace = buffer.pop(tid)
spans = trace.spans
kept = False
if "status_code" in policies:
kept |= any(sp.status == ERROR for sp in spans)
if "latency" in policies:
kept |= duration(spans) > 2s
if "probabilistic" in policies:
kept |= hash(tid) < 0.01
if kept:
storage.write(spans)

Where this sits in Build a distributed tracing system (Jaeger / Zipkin style)

Scene 09 of 17, in the Sampling act — You can't keep it all; decide once, and don't lie.. To judge a trace on whole-trace facts you must route every span of it to the same decision point, hold them for a window, and accept that anything arriving later is judged on its own — the queue hop again.

Up next. Deciding late means every span of one trace has to meet somewhere outside the application. Before a span can reach anywhere at all, it has to leave the process — without making the customer wait.

All 17 scenes in Build a distributed tracing system (Jaeger / Zipkin style) · Every curriculum

Built with Arqly
Every scene in Build a distributed tracing system (Jaeger / Zipkin style) builds on the one before it.All 17 Build a distributed tracing system (Jaeger / Zipkin style) scenes