지속 프로파일러를 손으로 만든다
목표
5초짜리 CPU 프로파일을 끊김 없이 이어 받는 작은 수집기를 만들고, 그렇게 쌓인 창들로 「언제부터 무엇이 뜨거워졌나」를 찾고, 원하는 시간 범위를 합쳐 보고, 저장 비용과 수집 부담을 숫자로 잽니다. Pyroscope 같은 지속 프로파일러가 안에서 하는 일을 손으로 한 번 해 봅니다.
왜 중요한가
앞 실습들은 「지금 느리다」고 알고 나서 프로파일을 받았습니다. 그런데 장애는 대개 지나간 뒤에 보고됩니다. 그때 받은 프로파일에는 이미 아무것도 없습니다. 지속 프로파일링은 프로파일을 늘 조금씩 받아 시간 축 위에 쌓아 두는 방식입니다. 그래서 「어제 14시 배포 뒤부터」 같은 질문에 답할 수 있고, 배포 전후 창을 골라 견줄 수 있습니다.
그 대가는 두 가지입니다. 저장 공간(창 하나의 크기 × 하루 창 수 × 서비스 수 × 프로파일 종류)과 수집 부담입니다. 표본 기반 프로파일러의 부담은 작다고 알려져 있지만, 「작다」를 내 서비스에서 재 보는 것이 이 실습의 마지막 단계입니다.
단계
- 5초 창을 N 개 이어 받는 수집기
/root/prof/collect.sh를 만드세요. 저장 위치의 기본값은/root/prof/cont입니다. - pricing 을 새로 띄우고 수집기로 창 7개를 받는 동안, 쿠폰 없는 부하(
-coupon 0 -d 12s)와 쿠폰 부하(-coupon 0.3 -d 12s)를 이어서 주세요. main.couponPattern이 표본의 20% 를 처음 넘은 창과, 그 바로 앞 창의 비율을/root/prof/answers/onset.json에 적으세요.- 그 창부터 끝까지를 합친 프로파일을
/root/prof/profiles/cont-after-onset.pb.gz에 저장하세요. - 창마다 전체 표본 수와
coupon=yes표본 수를/root/prof/answers/windows.csv에 적으세요. - 창의 평균 크기로 「서비스 하나·CPU 프로파일 하나」의 하루 저장량을
/root/prof/answers/retention.json에 계산하세요. - 수집기를 끈 부하와 켠 부하를 같은 조건으로 돌려 처리량 차이를
/root/prof/answers/overhead.json에 적으세요.
참고
- 작업 자리는
/root/prof입니다.prof-workspace가 소스(src)를 복사하고 두 프로그램(bin/pricing·bin/loadgen)을 빌드합니다. 여러 번 불러도 이미 있는 것은 덮지 않습니다. - 서비스는
prof-svc up pricing·prof-svc up api로 띄우고prof-svc status로 봅니다.up은 떠 있던 것을 내리고 다시 띄우므로, 앞에 적은 환경 변수가 그때 반영됩니다. - 부하는
loadgen입니다.-c(동시성)·-d(시간)·-coupon(쿠폰 비율)·-big(큰 주문 비율)·-seed를 받고,-out파일에 조건과 결과를 함께 적습니다. - 이 파드는 네트워크가 막혀 있습니다. 필요한 것은 전부 이미지에 들어 있습니다.
go tool pprof -proto a.pb.gz b.pb.gz … > 합친.pb.gz는 여러 프로파일을 하나로 합칩니다. 지속 프로파일러가 「이 시간 범위」를 보여 줄 때 하는 일입니다.- 창의 시작 시각은 프로파일 안의 Time 에도 들어 있습니다(
go tool pprof -raw <파일> | head -3). - 7단계의 수집기는 다른 디렉터리(
collect.sh 3 /root/prof/cont-overhead)에 쓰세요./root/prof/cont에 창이 더해지면 3–5단계의 답이 바뀝니다.
수집기를 만든다
/debug/pprof/profile?seconds=5 를 창 개수(첫 인자)만큼 이어 받아 저장 디렉터리(둘째 인자, 기본 /root/prof/cont)에 시작 시각 이름으로 저장하는 /root/prof/collect.sh 를 만들고 실행 비트를 주세요.
curl 은 프로파일 창이 끝날 때까지 기다렸다 돌아옵니다. 그래서 반복문 하나면 창이 빈틈없이 이어집니다. 파일 이름을 시각으로 두면 이름순이 곧 시간순입니다.
시간 축 위에 창을 쌓는다
prof-svc up pricing 으로 새로 띄우고 /root/prof/cont 를 비운 뒤, collect.sh 7 을 백그라운드로 돌리는 동안 loadgen -c 4 -coupon 0 -d 12s 와 loadgen -c 4 -coupon 0.3 -d 12s 를 차례로 돌리세요. 끝나면 창이 7개 남습니다.
첫 부하는 쿠폰이 없는 「배포 전」, 두 번째는 쿠폰 기능이 켜진 「배포 뒤」를 흉내 냅니다. 수집기는 그 사이에도 쉬지 않고 받습니다.
언제부터 뜨거워졌나
창을 시간순으로 보면서 표본이 50개 이상이고 main.couponPattern 이 든 표본이 20% 이상인 첫 창의 파일 이름을 first_window, 바로 앞 창의 그 비율(0..1)을 share_before 로 /root/prof/answers/onset.json 에 적으세요.
창마다 비율을 계산해 세로로 늘어놓으면 시간에 따른 그래프가 됩니다. 지속 프로파일러 화면의 위쪽 시계열이 이것입니다.
시간 범위를 합친다
first_window 부터 마지막 창까지를 go tool pprof -proto 로 합쳐 /root/prof/profiles/cont-after-onset.pb.gz 에 저장하세요.
pprof 는 파일을 여러 개 받으면 표본을 합칩니다. 창을 고르는 것이 곧 시간 범위를 고르는 것입니다.
창별 시계열
첫 줄을 window,total_samples,coupon_yes_samples 로 두고, 창마다 파일 이름·전체 표본 수·coupon=yes 레이블 표본 수를 한 줄씩 /root/prof/answers/windows.csv 에 적으세요.
레이블은 표본에 붙어 있으니 창마다 그 레이블의 합을 세면 됩니다. 지속 프로파일러가 「레이블로 나눠 보기」를 할 때 하는 일입니다.
하루에 얼마나 쌓이나
창 개수(windows), 창 파일의 평균 크기(avg_bytes), 5초 창을 하루 내내 받을 때의 저장량(per_day_mb = 평균 크기 × 17280 ÷ 1000000)을 /root/prof/answers/retention.json 에 적으세요.
하루는 86400초이니 5초 창은 17280개입니다. 여기에 서비스 수·인스턴스 수·프로파일 종류 수를 곱하면 실제 규모가 나옵니다. 그래서 지속 프로파일러는 창을 합쳐 압축하고 오래된 것을 줄여 둡니다.
수집 부담을 잰다
loadgen -c 4 -d 10s -seed 9 -out /root/prof/runs/m6-off.json 을 수집기 없이 돌리고, collect.sh 3 /root/prof/cont-overhead 를 백그라운드로 돌리는 동안 같은 명령을 -out /root/prof/runs/m6-on.json 으로 돌린 뒤, 두 처리량과 감소율을 /root/prof/answers/overhead.json 에 적으세요.
부담은 「켰을 때 처리량이 얼마나 주나」로 잽니다. 같은 조건이 아니면 그 차이는 부담이 아니라 조건의 차이입니다. 값이 음수로 나오면 측정 잡음이 부담보다 크다는 뜻입니다.