LabHub
배우기 러닝패스 코스

분산 트레이싱이 끊기는 자리 · 밖에서 온 문맥을 어디까지 믿나 · 실습

밖에서 온 baggage 를 그대로 믿었다

LabHub 에서 이어서 보기

목표

baggage 와 tracestate 를 직접 넣고 꺼내면서, baggage 가 저절로 스팬 속성이 되지 않는다는 것과 그 헤더가 모든 하류 요청에 실린다는 것을 숫자로 확인하고, 밖에서 들어온 문맥에 허용 목록 필터를 만들어 두 번째 서비스까지 같은 규칙으로 처리합니다.

왜 중요한가

트레이스가 이어져도 여섯 홉 아래 스팬에는 '어느 테넌트의 요청인가' 가 없다. baggage 는 그 값을 요청 전체에 나르라고 있는 자리인데, 넣어 두기만 해서는 아무 데도 나타나지 않는다 — 각 서비스가 꺼내서 자기 스팬에 옮겨 적어야 질의할 수 있는 자료가 된다. 반대로 값을 넉넉히 넣으면 그 바이트가 하류로 나가는 모든 요청에 붙어, 호출이 많은 경로에서만 지연이 늘고 프록시의 헤더 상한에 걸린다. 그리고 공개 API 앞에서 받은 baggage 는 남이 쓴 문자열이라, 그대로 속성으로 옮기면 지표의 카디널리티를 남이 정하게 된다. tracestate 는 같은 요청에 실리지만 업무 값을 넣는 자리가 아니라 추적 도구가 자기 위치를 적는 자리이고, 항목 수와 길이에 규격이 정한 규칙이 있다.

단계

1. /root/tp-baggage/carry.py 를 만드세요. 덤프 경로는 환경변수 TRACELAB_OUT 에서 읽고 없으면 /root/tp-baggage/carry.jsonl 을 씁니다. 서비스 이름은 shop-edge, 스팬 이름은 checkout 입니다. 그 스팬 안에서 baggage 에 tenant=acmecheckout.tier=gold 를 넣고, 빈 dict 에 traceparentbaggage 를 함께 주입한 뒤 그 dict 를 덤프와 같은 디렉터리carry.json 에 JSON 으로 적으세요. 그리고 프로그램을 한 번 돌리세요.
2. /root/tp-baggage/attrs.py 를 만드세요. 덤프 기본 경로는 /root/tp-baggage/attrs.jsonl 입니다. /opt/app/tracelab/tp_baggage/requests.json 에서 nameok 인 요청의 헤더를 꺼내 문맥을 추출하고, 그 문맥 아래 SERVER 스팬 두 개를 만듭니다. 첫 번째 price.raw 는 아무 속성도 붙이지 않고, 두 번째 price.tagged 에는 baggage 에서 꺼낸 값을 속성 tenantcheckout.tier 로 옮겨 적으세요. 서비스 이름은 shop-pricing 입니다. 프로그램을 돌린 뒤 두 스팬의 attributes 를 눈으로 비교하세요.
3. /root/tp-baggage/budget.py 를 만들어 /opt/app/tracelab/tp_baggage/candidates.json 의 후보 네 묶음을 각각 baggage 헤더로 만들고 비용을 재세요. 덤프 기본 경로는 /root/tp-baggage/budget.jsonl 이고, 덤프와 같은 디렉터리의 budget.tsv 에 머리글 없이 네 줄을 탭으로 나눠 적습니다 — <id>, <넣은 항목 수>, <헤더에 실제로 실린 항목 수>, <헤더 바이트 수>, <keep|drop>. 마지막 칸은 W3C Baggage 규격이 전달을 보장하는 범위(항목 수와 바이트 수) 안이면 keep, 벗어나면 drop 입니다. 후보마다 budget 이라는 스팬을 하나씩 남기고 속성 baggage.id·baggage.entries·baggage.bytes 를 붙이세요.
4. /root/tp-baggage/sanitize.py 를 만드세요. 덤프 기본 경로는 /root/tp-baggage/sanitize.jsonl 입니다. /opt/app/tracelab/tp_baggage/requests.jsonhostile 요청에서 baggage 를 추출한 뒤, 열쇠가 tenant·checkout.tier·region 중 하나이고 값이 정규식 ^[a-z0-9][a-z0-9._-]{0,31}$ 에 맞는 항목만 남기세요. 남은 것만 담은 새 문맥을 만들어 baggage 헤더로 주입하고 덤프와 같은 디렉터리의 kept.json 에 적습니다. SERVER 스팬 POST /checkout 을 그 요청의 부모 아래 만들고 속성 baggage.in·baggage.kept·baggage.dropped 에 개수를 넣고, 이벤트 baggage.dropped 의 속성 keys 에 버린 열쇠를 사전순으로 쉼표로 이어 적으세요. 서비스 이름은 shop-edge 입니다.
5. /root/tp-baggage/tsread.py 를 만들어 /opt/app/tracelab/tp_baggage/tracestates.json 의 헤더 여섯 개를 판정하세요. 덤프 기본 경로는 /root/tp-baggage/tsread.jsonl 이고, 덤프와 같은 디렉터리의 tsreport.tsv<id>, <항목 수>, <헤더 글자 수>, <ok|bad> 를 탭으로 나눠 여섯 줄 적습니다. ok 는 항목 수가 규격의 상한 이하이고, 열쇠가 소문자·숫자로 시작해 소문자·숫자와 _·-·*·/ 만 쓰며, 값이 규격의 글자 수 상한 이하이고 쉼표나 등호를 담지 않을 때입니다. 추가로 /root/tp-baggage/05-limits.txt 에 세 줄 max_members=·max_value_chars=·propagate_min_chars= 를 규격에서 읽은 숫자로 적으세요. 항목마다 tracestate.read 스팬을 하나씩 남기고 속성 ts.id·ts.members·ts.ok 를 붙입니다.
6. /root/tp-baggage/tsmutate.py 를 만들어 같은 여섯 헤더를 나가는 헤더로 바꾸세요. 규칙은 넷입니다 — (1) 우리 항목은 labhub=r1 이고 언제나 맨 왼쪽에 온다, (2) 우리 열쇠가 이미 있으면 지우고 새로 앞에 넣는다(두 번 나오면 안 된다), (3) 나머지 항목의 순서는 그대로 둔다, (4) 항목 수가 규격의 상한을 넘으면 128자를 넘는 항목을 뒤에서부터 먼저 지우고, 그래도 넘으면 끝에서부터 지운다. 덤프 기본 경로는 /root/tp-baggage/tsmutate.jsonl 이고, 덤프와 같은 디렉터리의 tsout.tsv<id><나가는 헤더> 를 탭으로 나눠 여섯 줄 적습니다. 항목마다 tracestate.out 스팬을 남기고 속성 ts.id·ts.out 을 붙이세요.
7. 앞 단계에서 손으로 넣었던 값을 /root/tp-baggage/policy.json 한 곳으로 모으세요. baggage 아래에 allow(허용 열쇠 배열), value_pattern(값 정규식), max_entries, max_bytes 를 두고, tracestate 아래에 key, value, max_members, drop_over_chars, position 을 둡니다. max_entriesmax_bytes 는 규격이 보장하는 범위 안이어야 하고, max_membersdrop_over_chars 는 규격의 숫자와 같아야 하며 positionleft 입니다. allow 에는 사람을 식별하는 열쇠를 넣지 마세요.
8. /root/tp-baggage/gateway.py 를 만들어 /root/tp-baggage/policy.json 을 읽고 /opt/app/tracelab/tp_baggage/requests.json 의 요청 네 건 전부를 처리하세요. 요청마다 baggage 를 규칙대로 거르고 tracestate 를 6단계 규칙대로 바꾼 뒤, 그 요청의 부모 아래 SERVER 스팬 gateway 를 하나씩 남기고 속성 req.name·baggage.kept·baggage.dropped·tracestate.members 를 붙입니다. 덤프 기본 경로는 /root/tp-baggage/gateway.jsonl 이고, 덤프와 같은 디렉터리의 gateway.tsv<name>, <남긴 수>, <버린 수>, <나가는 tracestate 항목 수> 를 탭으로 나눠 네 줄 적습니다. 서비스 이름은 shop-gateway 입니다.

참고

단계 8개

  1. baggage 를 넣어 다음 서비스로 흘린다
  2. baggage 는 저절로 스팬 속성이 되지 않는다
  3. baggage 한 줄이 나가는 모든 요청에 실린다
  4. 밖에서 들어온 baggage 에 허용 목록을 건다
  5. tracestate 의 규칙을 규격에서 읽어 적용한다
  6. 들어온 tracestate 를 보존하며 우리 항목을 앞에 넣는다
  7. 규칙을 기계가 읽는 파일로 굳힌다
  8. 두 번째 서비스에 규칙을 그대로 적용한다