API Eager Loading (요청 최소화, 데이터 과잉, 설계 기준)
- 공유 링크 만들기
- X
- 이메일
- 기타 앱
API Eager Loading 전략은 요청 시점에 필요한 모든 연관 데이터를 한 번에 조회하여 반환하는 방식입니다. 이 전략은 추가적인 API 호출을 줄이고, 데이터 접근을 단순화하는 데 효과적입니다.
API 호출을 줄이면 무조건 빠를까요? 실제 프로젝트에서 Eager Loading을 적용하고 나서 오히려 응답 속도가 느려진 경험을 한 뒤로, 이 전략이 단순한 최적화 기법이 아니라는 걸 체감했습니다. 요청 수를 줄이는 것과 성능을 높이는 것은 전혀 다른 이야기일 수 있습니다.
요청 최소화, 이게 정말 이점일까
Eager Loading의 핵심은 연관된 데이터를 요청 시점에 한 번에 모두 가져오는 방식입니다. 반대 개념인 Lazy Loading은 데이터가 실제로 필요한 순간에만 추가 요청을 보냅니다. 언뜻 보면 Eager Loading이 압도적으로 유리해 보입니다. 요청 한 번이면 끝나니까요.
그런데 Lazy Loading 방식에서 자주 언급되는 문제가 N+1 문제입니다. 예를 들어 사용자 목록 100명을 조회한 뒤, 각 사용자의 주문 내역을 가져오기 위해 추가로 100번 요청이 발생하는 구조입니다. N개의 항목을 조회하는 데 1(최초 요청) + N(각 항목에 대한 요청)번이 발생한다고 해서 N+1 문제라고 부릅니다. 네트워크 레이턴시(데이터가 출발지에서 목적지까지 이동하는 데 걸리는 시간)가 누적될수록 전체 응답 시간은 기하급수적으로 늘어납니다.
이 지점에서 Eager Loading이 강점을 발휘합니다. JOIN 쿼리(두 개 이상의 테이블을 연결해 한 번에 조회하는 SQL 구문)를 활용하면 데이터베이스 왕복 횟수를 확 줄일 수 있고, 특히 DB 접근 비용이 높은 환경에서는 이 차이가 꽤 명확하게 수치로 나타납니다. 제가 직접 써봤는데, 연관 엔티티가 3~4개 이상 중첩된 구조에서는 Lazy 방식 대비 응답 시간이 30~40% 단축되는 경우도 있었습니다.
하지만 이 장점이 항상 유효하지는 않습니다. 데이터 간 관계가 단순하고, 실제로 조회 빈도가 높은 연관 데이터가 명확히 특정될 때만 이 이점이 살아납니다. 조건이 어긋나는 순간, 이야기는 완전히 달라집니다.
데이터 과잉 반환이 만드는 실제 부담
Eager Loading을 처음 적용했을 때, API 응답 페이로드(서버가 클라이언트에 돌려주는 실제 데이터 묶음) 크기가 이전보다 4배 가까이 커진 경우가 있었습니다. 목록 화면에서는 유저 이름과 이메일만 필요했는데, 응답에는 주문 이력 전체와 배송지 정보까지 딸려 나왔습니다.
이 문제는 모바일 환경에서 더 두드러집니다. LTE 또는 5G 환경이라도 데이터 요금이나 네트워크 상태에 따라 대용량 페이로드는 체감 속도를 떨어뜨립니다. 클라이언트 입장에서도 실제로 사용하지 않는 데이터를 파싱하고 메모리에 올리는 과정이 불필요하게 추가됩니다. 이는 저사양 기기에서 렌더링 지연으로 이어질 수 있습니다.
서버 측도 마찬가지입니다. 복잡한 JOIN 쿼리는 DB의 CPU와 메모리 사용량을 끌어올립니다. 트래픽이 몰리는 상황에서 이런 쿼리가 동시에 다수 실행되면, 처리 대기열이 쌓이면서 병목 현상(특정 지점의 처리 속도가 전체 시스템의 한계를 결정하는 현상)이 발생합니다. 제 경험상 이건 로컬 테스트 환경에서는 잘 드러나지 않고, 실제 트래픽 상황에서 갑자기 나타나는 유형의 문제입니다.
오버페칭(Over-fetching)이라는 개념이 바로 여기서 나옵니다. 필요한 것보다 더 많은 데이터를 가져오는 상황을 뜻하는데, GraphQL이 REST API의 이 문제를 해결하기 위한 대안으로 등장한 배경이기도 합니다. Eager Loading을 무분별하게 적용하면 REST API가 오버페칭의 온상이 될 수 있습니다.
설계 기준 없이 쓰면 독
그럼 Eager Loading은 언제 써야 할까요? 경험상 이건 사용 맥락을 먼저 정의하지 않으면 독이 됩니다. 아래 기준을 실제로 적용하면서 효과를 봤습니다.
- 데이터 사용 패턴 분석: 해당 API를 호출하는 화면에서 어떤 필드를 실제로 렌더링하는지 먼저 파악합니다. 로그 분석이나 프론트엔드 팀과의 협의가 필수입니다.
- API 목적별 분리: 목록용 API와 상세용 API를 분리하는 방식이 효과적입니다. 목록에서는 핵심 필드만, 상세에서는 전체 연관 데이터를 포함하도록 설계하면 오버페칭을 구조적으로 차단할 수 있습니다.
- 반환 범위 제한: 연관 데이터를 전부 포함하는 게 아니라, 실제 호출 빈도가 높은 연관 엔티티만 선택적으로 포함합니다. 나머지는 별도 요청으로 처리하는 하이브리드 구조가 현실적입니다.
- 성능 모니터링 주기 설정: 응답 크기, 쿼리 실행 시간, DB 커넥션 점유율을 주기적으로 측정합니다. 배포 후 트래픽 변화에 따라 Eager 범위를 조정해야 할 시점이 반드시 옵니다.
일반적으로 Eager Loading을 기본 전략으로 깔고 가는 게 좋다는 의견도 있는데, 저는 조금 다르게 봅니다. 기본값은 Lazy로 두고, 성능 측정을 통해 N+1 문제가 실제로 확인된 지점에서만 Eager로 전환하는 접근이 더 안전합니다. 처음부터 Eager로 도배하면 나중에 응답 크기 문제를 추적하는 비용이 훨씬 커집니다.
실제로 출처: Martin Fowler의 엔터프라이즈 애플리케이션 아키텍처 패턴에서도 데이터 로딩 전략은 쿼리 빈도와 데이터 볼륨을 함께 고려해야 한다고 명시하고 있습니다. 단순히 요청 수를 줄이는 것이 목표가 아니라, 전체 시스템 비용을 낮추는 것이 목표임을 상기시켜 주는 대목입니다.
결국 Eager Loading은 도구입니다. 제가 내린 결론은 이렇습니다. 이 전략이 힘을 발휘하는 상황은 분명히 있고, 그 상황을 정확히 파악했을 때만 써야 합니다. 데이터 접근 패턴을 먼저 분석하고, API를 목적별로 쪼개고, 성능 지표를 지속적으로 추적하는 루틴 없이 Eager Loading을 적용하는 건 최적화가 아니라 기술 부채를 쌓는 일입니다. 다음에 API 설계를 고민 중이라면, Lazy Loading 전략과 함께 비교해보시면 더 명확한 판단이 가능할 것입니다.
관련 글
- 공유 링크 만들기
- X
- 이메일
- 기타 앱
댓글
댓글 쓰기