Four teams, one slow checkout — traces, spans and time-to-culprit

Logs and dashboards are both recorded per service, so neither can say which hop of one request consumed the time — one record per hop of that single request, tied together, makes the slow hop name itself.

Scene 01

Four teams, one slow checkout

  1. Watch
  2. Try it
  3. Predict
  4. Capture
three ways to investigate one slow checkoutgatewaycheckoutcartinventorypaymentslog windows to openlogs · five teams, five windowsgateway12:04:07.118 POST /checkout 200 3.004s12:04:07.118 +1,142 other requests this secondcheckout[12:04:07] order 88117 done in 2.94s[12:04:07] 380 other orders in this windowcart+2.3 st=12:04:09.402 GET /cart ok 91mst=12:04:09.404 GET /cart ok 88msinventory12:04:07 inv stock-check ok 118ms12:04:07 inv stock-check ok 104mspayments-1.9 s12:04:05.538 charge ok 2604ms12:04:05.541 charge ok 96msdashboards · one per servicegatewayp99 820 msnormal · within budgetcheckoutp99 700 msnormal · within budgetcartp99 95 msnormal · within budgetinventoryp99 140 msnormal · within budgetpaymentsp99 240 msnormal · within budgetone trace · one shared id0750ms1.5s2.3s3.0s0 → 3.0 s (example)POST /checkout3.0scheckout2.9sGET /cartstock-checkcharge2.6sFive formats, no shared key, two clocks off by seconds — order holds inside one service only.TIME TO CULPRIT42 minexampletarget ≤ 5 minLogs: every line is true, and nothing says which lines belong to the same checkout. TTC 42 min (example).
five teams, five formats — and nothing in these lines says which of them belong to the same checkout
What to watch for

Where did the time go? A customer's checkout took 3 seconds instead of 200 milliseconds, and four teams each swear their own service is fast. Watch the same slow checkout investigated three ways — first the teams' logs, then their dashboards, then the request recorded hop by hop — and watch the clock in the corner, which counts the minutes until someone can name the service responsible.

Continue unlocks when the animation finishes.
Implementation

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

Request.walk
what each service writes down as the checkout passes through
def walk(checkout, path):
for service in path:
start = service.clock()
service.handle(checkout)
taken = service.clock() - start
service.own_log.append(line(start, taken))
service.own_numbers.record(taken)
hops_of(checkout).append(
hop(service, start, taken)
)
Investigator.find_slow_hop
which hop each way of looking can actually name
def find_slow_hop(checkout, path):
if how == 'logs':
for service in path:
lines = read(service.own_log)
guess_by_timestamp(lines, checkout)
return cannot_say
if how == 'dashboards':
for service in path:
read(service.own_numbers)
return cannot_say
hops = hops_of(checkout)
return slowest(hops)
Investigator.cost_of_search
what the search costs as the path grows
def cost_of_search(how, path):
if how == 'one recorded request':
open(one_screen)
return 1
work = 0
for service in path:
work += open(service.window)
work += learn(service.own_format)
work += ask(service.team)
return work

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

Scene 01 of 17, in the Why trace act — Per-service records can't blame a hop; one id can.. Logs and dashboards are both recorded per service, so neither can name the hop that consumed the time. One record per hop of a single request, tied together, makes the slow hop name itself.

Up next. One recorded request named the slow hop in a single screen. So what exactly gets recorded at each hop, and how do five records written on five machines become one picture?

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