사전 샘플링
개념

샘플링

gabury1고친 사람 github-actions[bot]

샘플링은 전부 보는 대신 일부만 골라 보는 일입니다. 다룰 것이 너무 많을 때 그 가운데 몇 건만 남기고 나머지는 버립니다. 이 이름은 여러 분야가 함께 씁니다. 이 항목은 프로그램이 돌면서 바깥으로 내보내는 기록, 곧 텔레메트리를 골라 남기는 쪽을 다룹니다.

쉽고 빠른 이해

서버가 받은 요청 백 건 가운데 다섯 건의 기록만 남기고 나머지는 버립니다. 샘플링이 하는 일이 이것입니다.

요청이 늘면 기록도 같이 늘어납니다. 전부 남기면 보관 비용과 네트워크 사용량이 요청 수를 따라 불어납니다. 다 남기지 않아도 대체로 무슨 일이 벌어지는지는 알 수 있습니다. 그래서 일부만 남기는 쪽을 고릅니다.

도는 모양은 셋입니다.

  1. 남길 비율이나 조건을 미리 정합니다
  2. 기록이 생길 때마다 이 건을 남길지 판정합니다
  3. 남기기로 한 것만 내보내고 나머지는 버립니다

대가가 있습니다. 버린 건은 나중에 다시 볼 수 없습니다. 드물게 나는 실패일수록 버려지기 쉽습니다. 정작 봐야 할 건이 안 남아 있을 수 있습니다.

안 쓰는 때도 있습니다. 요청이 적거나, 과금·감사 기록처럼 한 건도 빠지면 안 되는 것은 샘플링하지 않습니다.

상세

국을 끓이다 간을 볼 때 냄비를 다 마시지 않습니다. 한 숟갈만 떠서 맛을 보고 냄비 전체의 간을 짐작합니다. 샘플링도 일부만 보고 전체를 짐작하는 일입니다.

다만 국은 잘 저으면 어디를 떠도 맛이 같습니다. 프로그램이 내보내는 기록은 그렇지 않습니다. 실패한 요청은 드물어서 아무 데나 떠서는 안 걸립니다. 그래서 무엇을 뜰지 고르는 규칙이 따라붙습니다.

프로그램이 돌면서 바깥으로 내보내는 기록을 통틀어 텔레메트리라고 합니다. 무엇이 얼마나 일어났는지 세어 둔 수치가 메트릭, 그때그때 남긴 문장이 로그, 요청 하나가 서비스들을 지나간 길이 트레이스입니다.

flowchart TD
    S["샘플링 · 이 가운데 일부만 남긴다"] --> T
    T["텔레메트리 · 내보내는 기록 전부"]
    T --> M["메트릭 · 세어 둔 수치"]
    T --> L["로그 · 그때그때 남긴 문장"]
    T --> R["트레이스 · 요청이 지나간 길"]
    R --> P["스팬 · 서비스 한 구간의 기록"]

이렇게 밖으로 드러난 기록만 보고 시스템 안에서 무슨 일이 있었는지 알아내는 성질이 관측성입니다. 샘플링은 그 기록을 만들거나 내보낼 때 일부만 고르는 일입니다. 고르는 규칙과 남기는 비율은 사람이 미리 정해 둡니다.

다 남길 수 없는 까닭

기록의 양은 요청 수를 따라갑니다. 요청이 열 배로 늘면 기록도 열 배가 됩니다. 서비스가 커진 것도 기능이 늘어난 것도 아닌데 보관할 양만 열 배가 됩니다.

비용은 세 군데서 듭니다. 기록을 만드느라 프로그램이 일을 더 합니다. 그것을 내보내느라 네트워크를 씁니다. 받아 둔 쪽에서는 디스크를 씁니다.

flowchart TD
    A["프로그램 · 기록을 만드느라 일을 더 한다"] --> B["네트워크 · 만든 기록을 내보낸다"]
    B --> C["받는 쪽 · 받아 둔 기록을 디스크에 쌓는다"]

그런데 남긴 기록의 대부분은 아무도 열어 보지 않습니다. 평범하게 성공한 요청의 기록은 볼 이유가 없습니다. 그래서 전부 남기는 대신 일부만 남기는 쪽을 고릅니다.

앞에서 고르기와 뒤에서 고르기

남길지 정하는 판단을 언제 내리느냐로 두 갈래가 됩니다. 요청이 들어오자마자 정하는 것을 헤드 샘플링, 요청이 끝난 뒤 정하는 것을 테일 샘플링이라고 부릅니다.

flowchart TD
    subgraph 앞["앞에서 고르기"]
      A1["요청이 들어온다"] --> A2["남길지 지금 정한다"]
      A2 --> A3["버리기로 한 건은 기록을 만들지 않는다"]
    end
    subgraph 뒤["뒤에서 고르기"]
      B1["기록을 일단 다 만든다"] --> B2["요청이 끝나기를 기다린다"]
      B2 --> B3["실패했거나 오래 걸린 건만 남긴다"]
    end

앞에서 고르면(헤드) 버릴 건은 기록을 만들지도 않으므로 비용이 적게 듭니다. 그런데 정하는 시점에는 이 요청이 나중에 실패할지 오래 걸릴지 알 수 없습니다.

뒤에서 고르면(테일) 결과를 보고 정할 수 있습니다. 실패했거나 오래 걸린 요청만 골라 남길 수 있습니다. 다만 판정할 때까지 모든 기록을 어딘가에 들고 있어야 합니다. 그 몫의 메모리와 처리가 따로 듭니다.

남길 것을 고르는 네 규칙

무엇을 남길지는 대개 아래 네 가지 가운데 하나로 정합니다. 트래픽 모양과 꼭 봐야 할 것이 선택을 가릅니다.

규칙 어떻게 고르나 어디에 맞나
고정 비율 정해 둔 비율만큼 무작위로 남깁니다 요청이 고르게 들어오는 서비스
초당 상한 초마다 몇 건까지만 남기고 나머지는 버립니다 트래픽이 널뛰는 서비스
조건부 실패했거나 오래 걸린 건만 남깁니다 드문 실패를 놓치면 안 될 때
우선순위 특정 사용자나 특정 경로는 늘 남깁니다 놓치면 안 될 요청이 정해져 있을 때

실무에서는 한 가지만 쓰기보다 섞어 씁니다. 실패한 건은 조건부로 전부 건져 두고, 성공한 건만 고정 비율로 줄이는 식입니다. 섞어 쓰면 판정에 순서가 생깁니다. 먼저 실패인지 보고, 아니면 정해 둔 비율로 거릅니다.

flowchart TD
    A["기록 한 건이 생긴다"] --> B{"실패했거나 오래 걸렸나"}
    B -->|예| C["무조건 남긴다"]
    B -->|아니오| D["정해 둔 비율로 뽑는다"]
    D --> E["남기거나 버린다"]

한 요청에 한 번만 하는 판정

요청 하나가 여러 서비스를 거치면 서비스마다 자기 구간의 기록을 남깁니다. 이 구간 기록 하나가 스팬입니다. 스팬을 이어 붙인 것이 트레이스입니다.

서비스마다 따로 동전을 던지면 앞단은 남기고 결제는 버리는 일이 생깁니다. 그러면 요청이 지나간 길이 중간에 끊깁니다. 남은 조각만 봐서는 어디서 시간을 썼는지 알 수 없습니다.

flowchart TD
    subgraph 이어짐["이어진 트레이스"]
      A1["앞단 스팬"] --> A2["결제 스팬"]
      A2 --> A3["배송 스팬"]
    end
    subgraph 끊김["끊긴 트레이스"]
      B1["앞단 스팬"] --> B2["결제 · 버림 · 기록 없음"]
      B2 --> B3["배송 스팬"]
    end

가운데 스팬이 없으면 결제에서 시간을 썼는지 알 수 없습니다.

그래서 판단은 맨 앞에서 한 번만 합니다. 남긴다는 표시를 요청과 함께 다음 서비스로 넘깁니다. 요청을 따라 이런 부속 정보를 넘기는 일을 컨텍스트 전파라고 부릅니다.

sequenceDiagram
    participant 앞단
    participant 결제
    participant 배송
    앞단->>결제: 요청 · 남긴다는 표시를 같이 보냄
    Note over 결제: 다시 판정하지 않고 표시를 따른다
    결제->>배송: 요청 · 같은 표시를 그대로 넘김

표시를 넘길 수단이 없을 때도 있습니다. 그때는 요청마다 붙는 고유한 번호를 씁니다. 이 번호가 트레이스 아이디입니다.

아래는 그 번호만 보고 남길지 정하는 규칙입니다.

Python
tid = "3f7ab2"              # 트레이스 아이디
keep = hash(tid) % 100 < 5  # 백에 다섯만 참

번호를 고르게 흩뜨리는 계산(해시)에 넣고, 그 값을 백으로 나눈 나머지가 다섯보다 작을 때만 남깁니다. 번호가 같으면 어느 서비스가 계산해도 답이 같습니다. 표시를 주고받지 않아도 판단이 갈리지 않는다는 뜻입니다.

남은 것으로 원래 수를 되짚기

백 건 가운데 다섯 건만 남겼다면 남은 건 수에 스물을 곱해야 원래 건수에 가까워집니다. 이렇게 버린 몫을 되돌려 계산하는 일을 가중치 보정이라고 부릅니다.

보정을 하지 않으면 대시보드의 요청 수가 원래보다 적게 나옵니다. 그래서 남길지 정할 때 쓴 비율을 기록에 같이 적어 둡니다. 나중에 세는 쪽이 그 비율을 보고 되돌립니다.

되짚어도 총합이나 평균은 대체로 맞습니다. 드문 값은 못 맞힙니다. 백 건에 한 번 나는 실패는 애초에 안 걸렸을 수 있습니다. 그러면 되돌릴 것도 없습니다.

flowchart TD
    subgraph 남김["남기는 쪽"]
      A["요청 100건"]
      B["5건만 남긴다 · 비율 5%를 기록에 같이 적는다"]
    end
    subgraph 셈["세는 쪽"]
      C["남은 5건에 스물을 곱한다"]
      D["약 100건"]
    end
    A --> B
    B --> C
    C --> D
    A --> E["백에 한 번 나는 실패 1건 · 애초에 안 걸렸다"]
    E --> F["되돌릴 것이 없다"]

치르는 것

버린 건은 되살릴 수 없습니다. 장애가 난 뒤에 그 요청의 기록을 찾으면 없습니다. 무엇을 버릴지는 장애가 나기 전에 정합니다. 정하는 때에는 나중에 무엇이 아쉬울지 모릅니다.

드문 것일수록 버려지기 쉽습니다. 무작위로 고르면 자주 일어나는 일은 잘 남고 드물게 나는 실패는 잘 안 남습니다. 봐야 할 것이 안 남는다는 뜻입니다.

비율은 한 번 정해 놓고 잊을 수 있는 값이 아닙니다. 트래픽이 널뛰면 고정 비율로는 한가할 때 너무 적게 남고 몰릴 때 너무 많이 남습니다. 그래서 들어오는 양을 보고 비율을 스스로 조절하는 방식을 쓰기도 합니다.

남은 기록끼리 견주는 일도 조심해야 합니다. 서비스마다 비율이 다르면 남은 건 수를 그대로 비교할 수 없습니다. 비율을 되돌린 뒤에야 같은 잣대가 됩니다.

안 쓰는 쪽이 맞는 때도 있습니다. 요청이 적어 전부 남겨도 부담이 없으면 그냥 다 남깁니다. 과금 내역이나 감사 기록처럼 한 건이 빠지면 안 되는 것도 샘플링 대상이 아닙니다.

같은 이름을 쓰는 다른 분야

뿌리는 같습니다. 전부 다루는 대신 일부만 집는다는 것입니다. 무엇을 집느냐가 분야마다 다릅니다.

분야 무엇을 집나
통계 모집단 전체를 조사하는 대신 그 일부인 표본을 뽑아 전체를 짐작합니다
소리·영상 끊임없이 변하는 값을 일정한 간격으로 찍어 숫자로 바꿉니다. 초당 몇 번 찍는지가 샘플링 레이트입니다
그래픽스 그림에서 한 점의 색을 읽어 옵니다. 이 읽기가 텍스처 샘플링입니다
성능 측정 프로그램을 멈춰 세우는 대신 일정 주기마다 지금 어느 함수를 도는지만 훔쳐봅니다. 이 방식의 프로파일링을 샘플링 방식이라고 부릅니다

소리를 숫자로 바꿀 때 찍는 간격을 너무 성기게 잡으면 원래 소리를 못 되살립니다. 없던 소리가 생기기도 합니다. 이 현상을 에일리어싱이라고 부릅니다. 드문 실패가 안 걸리는 것과 뿌리가 같은 문제입니다. 둘 다 성기게 집어서 원본에 있던 것을 놓친 것입니다.

관련 항목

샘플링으로 양을 줄이는 관측 신호

텔레메트리 · 메트릭 · 로그 · 트레이스 · 스팬 · 프로파일 · 이벤트

샘플링할 대상을 고르는 방식

헤드 샘플링 · 테일 샘플링 · 확률 샘플링 · 속도 제한 샘플링 · 적응형 샘플링 · 우선순위 샘플링 · 샘플링 비율

샘플링 판단을 서비스 사이로 실어 나르는 수단

트레이스 컨텍스트 · 트레이스 아이디 · 샘플링 플래그 · 컨텍스트 전파 · 전파기

샘플링을 실행하는 구성 요소

계측 · 수집기 · 에이전트 · 익스포터 · 사이드카 · 관측성 백엔드

샘플링을 대신하거나 뒤이어 양을 줄이는 수단

집계 · 다운샘플링 · 롤업 · 보존 기간 · 압축 · 카디널리티 폭발

샘플링한 값에서 전체를 되짚는 통계 개념

모집단 · 표본 · 가중치 보정 · 편향 · 신뢰 구간 · 대수의 법칙

샘플링이 속하는 상위 분류

관측성 · 모니터링 · 프로파일링 · 통계

같은 이름을 쓰는 다른 분야의 샘플링

샘플링 레이트 · 나이퀴스트 정리 · 에일리어싱 · 텍스처 샘플링 · 멀티샘플링 · 샘플링 프로파일러 · 아날로그-디지털 변환

다른 이름: sampling · 표본 추출 · 표집