성능
성능은 기능입니다. 평균이 아닌 P99를 위해 설계하세요. 측정 없이 최적화하지 마세요 — 직관은 시간이 어디에 소비되는지에 대해 거의 항상 틀립니다.
규칙
- 최적화 전에 프로파일링하세요. 핫 경로를 추측하면 시간을 낭비합니다. 먼저 플레임 그래프, APM 트레이스, 또는
EXPLAIN ANALYZE를 사용하세요. - N+1 쿼리를 제거하세요. 서비스 코드에서 가장 큰 지연 원인입니다. 행별 조회보다 조인, 배치 페치, 또는
IN (...)을 선호하세요. - 모든 목록 엔드포인트를 페이지네이션하세요. 제한 없는 결과 집합은 결국 파드를 OOM시키거나 데이터베이스를 포화시킵니다. 큰 테이블에는 기본적으로 커서 기반 페이지네이션을 사용하세요.
- 모든 컬럼이 아닌 쿼리 조건에 인덱스를 생성하세요. 각 추가 인덱스는 쓰기를 느리게 하고 저장 공간을 늘립니다. 알려진 쿼리에 필요한 경우에만 인덱스를 추가하세요.
- 필요한 컬럼만 프로젝션하세요.
SELECT *로 넓은 DTO를 가져오면 네트워크, 메모리, GC를 낭비합니다. 목록 API에는 좁은 프로젝션을 반환하세요. - 읽기 부하가 높고 멱등성 있는 데이터를 캐싱하세요. 하지만 캐시를 추가하기 전에 무효화 전략을 결정하세요 — 제거 계획이 없는 캐시는 버그 공장입니다.
- 커넥션 풀과 스레드 풀 크기를 명시적으로 설정하세요. 기본값은 워크로드에 적합한 경우가 드뭅니다. 다운스트림 용량에 맞춰 크기를 조정하고, 그 이상으로 크게 설정하지 마세요.
- 아웃바운드 호출을 배치 처리하세요. 한 번에 100개 항목을 요청하는 것이 100번 각각 요청하는 것보다 모든 측면(지연 시간, CPU, DB 커넥션)에서 낫습니다.
- 원격 호출의 동기식 체인을 피하세요. 지연 시간이 누적됩니다. 병렬로 팬아웃하거나 작업을 비동기로 옮기세요.
- 페이로드를 작게 유지하세요. 응답을 압축하고, 사용하지 않는 필드를 제거하며, 중요한 경우 이진 프로토콜(gRPC, Protobuf)을 사용하세요.
위험 신호
- 데이터베이스를 쿼리하는 루프.
- "모든 레코드"를 반환하는 API.
- TTL과 무효화 정책이 없는 캐시.
- 프로덕션에서 프레임워크 기본값으로 설정된 스레드 풀 / 커넥션 풀.
- 평균만 표시하는 지연 시간 대시보드(P95/P99 없음).