고친 뒤, 같은 조건으로 두 프로파일을 견준다
목표
지금까지 쫓아온 원인(요청마다 정규식을 컴파일하는 couponPattern)을 고치고, 고치기 전과 같은 조건으로 다시 재서 두 프로파일의 차이(diff)로 고쳐졌음을 확인합니다. 조건이 다른 비교가 왜 믿을 수 없는지도 직접 만들어 봅니다.
왜 중요한가
「고쳤더니 빨라졌다」는 말은 두 측정이 같은 조건이었을 때만 뜻이 있습니다. 동시성이 다르면 대기 시간이 달라지고, 쿠폰 비율이 다르면 하는 일 자체가 다르고, 프로파일 길이가 다르면 표본 수가 다릅니다. 그 차이를 고친 효과로 읽으면 다음 사람이 같은 실험을 되풀이할 수 없습니다.
go tool pprof -diff_base 는 같은 조건의 두 프로파일을 빼서 줄어든 곳을 음수로 보여 줍니다. 그리고 처리량이 늘면 같은 시간에 더 많은 일을 하므로 CPU 합계만 보면 오히려 그대로일 수 있습니다. 그래서 「요청 하나당 CPU」처럼 일의 양으로 나눈 값을 함께 봅니다.
단계
- 소스를 처음 상태로 되돌려 pricing 을 띄우고
-c 4 -d 20s -seed 7부하(/root/prof/runs/before.json)를 주는 동안 15초 프로파일을/root/prof/profiles/before.pb.gz에 받으세요. /root/prof/src/pricing/main.go에서 정규식을 한 번만 컴파일하도록 고치고 다시 빌드하세요.- 고친 pricing 으로 1단계와 같은 조건의 부하(
/root/prof/runs/after.json)와 프로파일(/root/prof/profiles/after.pb.gz)을 받으세요. -diff_base로 두 프로파일을 뺀 표를/root/prof/answers/diff-top.txt에 저장하세요.- 두 측정의 처리량과 요청 하나당 CPU(ms)를
/root/prof/answers/compare.json에 적으세요. - 두 측정의 p99 와 그 비율을
/root/prof/answers/result.json에 적으세요. - 조건을 바꾼 측정(
/root/prof/runs/after-wrong.json)을 하나 만들고, before 와 다른 조건 필드를/root/prof/answers/why-wrong.txt에 적으세요.
참고
- 작업 자리는
/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파일에 조건과 결과를 함께 적습니다. - 이 파드는 네트워크가 막혀 있습니다. 필요한 것은 전부 이미지에 들어 있습니다.
- 소스를 망가뜨렸으면
prof-workspace --reset pricing으로 되돌립니다. 고친 뒤prof-workspace를 다시 부르면 소스가 바이너리보다 새로우므로 다시 빌드합니다. - 새 바이너리를 빌드해도 떠 있는 프로세스는 옛 것입니다.
prof-svc up pricing으로 다시 띄워야 합니다. - 요청 하나당 CPU(ms) = 프로파일의 CPU 합(ms) ÷ (처리량 × 프로파일 길이(초)) 입니다.
- 조건 필드는 loadgen 결과의
concurrency·duration_s·coupon_ratio·big_ratio·seed입니다.
고치기 전을 잰다
prof-workspace --reset pricing 으로 처음 소스로 되돌려 빌드하고, prof-svc up pricing 뒤 loadgen -c 4 -d 20s -seed 7 -out /root/prof/runs/before.json 을 돌리는 동안 ?seconds=15 프로파일을 /root/prof/profiles/before.pb.gz 에 받으세요.
비교의 기준선입니다. 나중에 같은 명령을 그대로 다시 쓸 수 있게 명령을 적어 두세요.
원인을 고친다
/root/prof/src/pricing/main.go 의 couponPattern 이 정규식을 매번 컴파일하지 않도록 고치고(패키지 변수로 한 번만 컴파일) prof-workspace 로 다시 빌드하세요.
패턴은 요청마다 같습니다. 패키지 수준 var 로 한 번 컴파일해 두고 함수는 그것을 돌려주면 됩니다. 정말 고쳐졌는지는 이 단계가 아니라 다음 단계의 프로파일이 판정합니다.
같은 조건으로 다시 잰다
prof-svc up pricing 으로 새 바이너리를 띄우고 1단계와 같은 loadgen 명령을 -out /root/prof/runs/after.json 으로 돌리는 동안 같은 길이의 프로파일을 /root/prof/profiles/after.pb.gz 에 받으세요.
채점기는 두 결과 파일의 조건 필드와 두 프로파일의 길이를 견줍니다. 하나라도 다르면 이 비교는 받지 않습니다.
두 프로파일을 뺀다
go tool pprof -top -cum -nodecount=40 -diff_base /root/prof/profiles/before.pb.gz /root/prof/profiles/after.pb.gz 의 출력을 /root/prof/answers/diff-top.txt 에 저장하세요. main.couponPattern 줄이 음수여야 합니다.
-diff_base 는 뒤의 프로파일에서 기준을 뺍니다. 줄어든 곳이 음수, 늘어난 곳이 양수입니다. couponPattern 은 자기 시간(flat)이 거의 없으니 -cum 으로 정렬해야 위에 보입니다. 고친 곳 말고 늘어난 곳도 보세요. 처리량이 늘면 다른 함수가 더 바빠집니다.
일의 양으로 나눈다
before_rps·after_rps(loadgen 결과의 rps)와 before_cpu_ms_per_req·after_cpu_ms_per_req(프로파일의 CPU 합(ms) ÷ (rps × 프로파일 길이(초)))를 /root/prof/answers/compare.json 에 적으세요.
CPU 합만 보면 두 코어를 다 쓰는 것은 고친 뒤에도 같을 수 있습니다. 같은 CPU 로 일을 몇 배 했는지가 고친 효과입니다.
사용자가 느끼는 차이
runs/before.json·runs/after.json 의 p99 를 p99_before·p99_after 로, 그 비율(before ÷ after)을 speedup 으로 /root/prof/answers/result.json 에 적으세요.
프로파일은 서버가 어디에 시간을 썼는지, p99 는 사용자가 얼마나 기다렸는지를 말합니다. 둘 다 좋아져야 「고쳤다」고 말할 수 있습니다.
믿을 수 없는 비교를 알아본다
조건을 바꿔(loadgen -c 1 -d 5s -out /root/prof/runs/after-wrong.json) 한 번 더 재고, runs/before.json 과 값이 다른 조건 필드 이름을 한 줄에 하나씩 /root/prof/answers/why-wrong.txt 에 적으세요.
조건 필드는 concurrency·duration_s·coupon_ratio·big_ratio·seed 입니다. 명령에 적지 않은 옵션은 기본값으로 돌아간다는 점을 잊지 마세요.