Q.서비스 성능 병목을 어떤 순서로 찾나요?
위에서 아래로 좁힙니다. 추측으로 코드를 보기 전에 어느 구간에서 시간을 쓰는지 먼저 나눕니다.
| 순서 | 확인 | 도구 |
|---|
| 1 | 어떤 요청이 느린가 | 요청별 지연 분포, p99 |
| 2 | 그 요청의 어느 구간인가 | 분산 트레이싱, 구간 타이머 |
| 3 | 자원 중 무엇이 포화인가 | CPU, 메모리, 디스크, 네트워크, 커넥션 풀 |
| 4 | 외부 의존인가 자기 코드인가 | DB 쿼리 시간, 외부 호출 시간 |
| 5 | 코드의 어느 함수인가 | 프로파일러 |
2번을 건너뛰면 대개 헛수고가 됩니다. 느린 API 의 시간이 DB 대기인지, 외부 호출인지, 직렬화인지에 따라 손댈 곳이 완전히 다릅니다.
3번에서 자주 놓치는 것이 커넥션 풀입니다. CPU 와 메모리가 한가한데도 느리면 풀 대기를 봐야 합니다.
흔한 실수: 평균만 보고 판단하는 것. 평균이 정상이어도 p99 가 나쁘면 일부 요청이 크게 느린 것이고, 원인이 평균과 다릅니다.
Q.프로파일러 결과에서 self time과 total time을 어떻게 구분해 읽나요?
| 지표 | 의미 |
|---|
| total time | 그 함수가 시작해서 끝날 때까지의 시간. 호출한 함수들의 시간을 포함한다 |
| self time | 그 함수 자체가 쓴 시간. 하위 호출을 뺀 값 |
읽는 방법이 다릅니다.
| 상황 | 해석 |
|---|
| total 이 크고 self 는 작다 | 이 함수는 통로다. 아래를 봐야 한다 |
| total 과 self 가 모두 크다 | 이 함수 자체가 무겁다. 여기를 고친다 |
| self 가 큰 함수가 여럿 흩어져 있다 | 특정 병목이 없다. 구조를 봐야 한다 |
최상위 진입점은 항상 total 이 가장 큽니다. 그것을 병목이라고 읽으면 아무것도 못 합니다. 고칠 대상은 self 가 큰 함수입니다.
I/O 대기가 섞이면 해석이 또 달라집니다. self 가 큰데 실제로는 소켓 대기인 경우가 있어서, CPU 프로파일과 벽시계 기준 프로파일을 구분해서 봐야 합니다.
흔한 실수: 호출 횟수를 함께 보지 않는 것. 한 번에 100밀리초 걸리는 함수와 1밀리초씩 100번 불리는 함수는 self 가 같아도 대응이 다릅니다. 후자는 호출을 줄이는 쪽입니다.
Q.APM 도구로는 무엇을 보고 병목을 판단하나요?
| 보는 것 | 판단하는 것 |
|---|
| 요청별 지연 분포 | 어떤 엔드포인트가 느린가 |
| 트레이스의 구간 분해 | 그 안에서 어디에 시간을 쓰는가 |
| 느린 쿼리 목록 | DB 가 원인인가 |
| 외부 호출 시간 | 남의 서비스 때문인가 |
| 오류율과 예외 | 느린 것과 실패가 같은 원인인가 |
| 처리량과 지연의 관계 | 부하가 원인인가 |
가장 먼저 보는 것은 어떤 엔드포인트가 전체 시간을 많이 쓰는지입니다. 요청당 200밀리초짜리가 초당 1,000회면, 요청당 2초짜리가 초당 1회인 것보다 훨씬 큰 문제입니다. 지연만 보면 순서가 뒤바뀝니다.
마지막 항목이 판단을 크게 바꿉니다. 처리량이 늘면서 지연이 나빠졌다면 용량 문제이고, 처리량이 그대로인데 나빠졌다면 코드나 데이터가 바뀐 것입니다.
흔한 실수: 느린 엔드포인트 하나만 잡고 최적화하는 것. 호출량을 곱해 전체에 기여하는 시간으로 순위를 매겨야 개선 효과가 큰 곳부터 손댑니다.
먼저 스스로 답해보고 아래 답변과 견줘보세요. 막히는 부분은 문제로 확인할 수 있어요.
읽었으면 문제로 확인해보세요
성능 최적화 문제를 풀면 틀린 문제가 자동으로 노트에 쌓입니다. 가입 없이 5문제를 먼저 풀어볼 수도 있어요.