When the picture itself lies — clock skew, gaps and the uninstrumented hop
Every span's times come from the clock of the machine that recorded it and those clocks disagree, so viewers quietly shift timestamps to make a child fit inside its parent — and an empty gap has at least five possible causes that nothing in the data distinguishes.
Self time and the critical path are read off timestamps, and off the spans that happen to be there. Both of those assumptions are worth checking.
Scene 14a
When the picture itself lies
- Watch
- Try it
- Predict
- Capture
Can you trust the shape of a trace? Every span's start and end are stamped by the clock of the machine that recorded it, and machines in a fleet do not agree about what time it is — plain time synchronisation leaves tens of milliseconds of disagreement, which is wider than plenty of spans you care about. Watch the same two spans of one call drawn twice: once with the numbers the two machines actually reported, then once after the viewer quietly repairs them.
Highlighted lines are the ones running in the diagram right now.
def finish_span(span):span.start_time = local_clock.now() - span.elapsedspan.end_time = local_clock.now()span.process.tags['ip'] = host_ipexporter.export(span)
def adjust_trace(trace):for child in trace.spans:parent = trace.by_id[child.parent_id]if host_of(child) == host_of(parent):continuedelta = calculate_delta(child, parent)if delta == 0:continuechild.start += deltachild.warnings.append(f'shifted {delta}ms for clock skew')
def calculate_delta(child, parent):if child.duration > parent.duration:return parent.start - child.startif (child.start >= parent.startand child.end <= parent.end):return 0latency = (parent.duration - child.duration) / 2return parent.start + latency - child.start
def explain_gap(prev, next):gap_ms = next.start - prev.endcandidates = ['the two spans are genuinely adjacent','queue or scheduler wait','a hop nobody instrumented','a span dropped or not yet arrived','network, TLS, serialization','a stop-the-world pause',]return Gap(gap_ms, cause=UNKNOWN,candidates=candidates)
Where this sits in Build a distributed tracing system (Jaeger / Zipkin style)
Scene 14a of 17, in the Store & read act — Key by trace id, find it, read it, distrust it.. Every span's times come from the clock of the machine that recorded it, and those clocks disagree. Viewers quietly shift timestamps to make a child fit its parent, folding real network and queue wait into the parent.
Up next. One trace can mislead you in ways you cannot detect from inside it. A million traces average that out — so what can you build from all of them at once?
All 17 scenes in Build a distributed tracing system (Jaeger / Zipkin style) · Every curriculum