0. 들어가며
- “모놀리식에서 잘 되던 Fetch Join이 MSA에서 왜 갑자기 힘들어지는지”
- 이번 글에서 다룰 것 : MSA 개념 → Join 문제 → N+1 → Bulk Fetch 조회 해결
1. MSA란?
하나의 큰 애플리케이션을 독립적인 작은 서비스들로 나누어, 각 서비스가 독립적으로 개발, 배포, 확장될 수 있도록 하는 아키텍처
2. MSA vs 모놀리식

|
|
MSA
|
모놀리식
|
|
배포
|
해당 서비스만
|
전체
|
|
영향
|
해당 서비스만
|
전체
|
|
배포 시간
|
5분
|
30분
|
|
위험도
|
낮음
|
높음
|
하지만, 데이터 접근 방식이 달라지면서 새로운 문제가 생긴다.
3. 모놀리식에서는 ‘Fetch Join’ 으로 끝났던 이유
@Query("Select p from posts p join fetch p.user")
- 같은 DB / 같은 트랜잭션 범위
- post + user 를 한방 쿼리로 조회가 가능했다
모놀리식은 DB Join으로 관계를 해결하지만, MSA 서비스 경계 때문에 Join을 사용할 수가 없다.
4. MSA에서는 Join이 왜 어려운가?
- 데이터가 서비스마다 분리가 되어있음
- A 서비스가 B 서비스의 데이터를 원하면 조인이 아닌 API 호출을 해야함
@FeignClient(name = "user-service")
public interface UserClient {
@GetMapping("/api/users")
List<UserDto> getAll();
@GetMapping("/api/users/{id}")
UserDto getUser(@PathVariable Long id);
}
5. 문제 발생: API Join 에서 N+1 터짐
1) 모든 게시글 조회하는 API 호출 시
public List<PostResponseDto> getAllPosts() {
return postRepository.findAll().stream()
.map(p -> PostResponseDto.from(p, userClientWrapper.getUser(p.getUserId())))
.toList();
}

2) Post서비스와 User서비스가 나누어져 있어서 User 를 불러오기 위해 N+1 문제가 발생한다.
.map(p -> PostResponseDto.from(p, userClientWrapper.getUser(p.getUserId())))

ex)
- 게시글 목록 20개 조회 (post-service)
- 각 게시글 작성자 정보 조회하려고 user-service를 20번 호출 → 총 21번 호출 N+1
6. 해결: ID 리스트로 한 번에 조회(Bulk Fetch)로 한 번에 가져와서 매핑
6-1) 해결 방법
- 1) 게시글 목록에서 userId만 모아서 중복 제거
List<Long> ids = postRepository.findAll().stream()
.map(r -> r.getUserId())
.distinct()
.toList();
- 2) user-service에서 배치 API 로 한 번 호출하기
@GetMapping("/api/users/batch")
List<UserDto> getUsers(@RequestParam List<Long> ids);
- 3) 결과를 Map<Long, UserDto> 으로 매핑하기
Map<Long, UserDto> userMap = users.stream()
.collect(Collectors.toMap(UserDto -> UserDto.getId(), m -> m));
- 4) List<PostResponseDto> 로 매핑 후 반환하기
return posts.stream()
.map( p -> PostResponseDto.from(p, userMap.get(p.getUserId())))
.toList();
6-2) 결과
- 호출 수 : N + 1 → 1 + 1
- 응답 시간 / 서버 부하 감소

7. 배운 점
지금 배우는 입장에서 작은 프로젝트에 MSA를 그대로 적용하는 건 오버엔지니어링이라고 느꼈다.
다만, 이번 경험을 통해 모놀리식에서는 당연했던 Join이 서비스 분리 순간 ‘API 조합’ 문제로 바뀌고, 그 과정에서 API N+1 → Bulk Fetch 를 통해 해결하는 방법을 배웠다. 결론적으로 MSA가 좋다 / 나쁘다가 아닌, 팀 규모, 배포 단위 등 요구가 생길 때 선택해야하는 아키텍처라는 기준도 배우게 되었다.
'Tech' 카테고리의 다른 글
| [Server Migration] 구형 미니PC 서버 장애 및 신규 미니 PC 구축기 (0) | 2026.04.21 |
|---|