
프로젝트 소개
우아한테크코스 4기에서 진행한 팀 프로젝트로, 키보드, 마우스 등의 하드웨어부터 IDE 등 소프트웨어까지, 개발자들이 사용하는 장비에 대해 리뷰를 남기고 프로필에 등록하여 다른 개발자들의 장비를 구경할 수 있는 서비스입니다.
프로젝트 기간
2022.06. ~
프로젝트 주소
https://f12.app
참여 인력
FE 2명 / BE 5명
사용 기술
- Java 11
- Spring Boot, Spring MVC, Spring REST Docs
- Spring Data JPA, QueryDSL
- MySQL, H2
- OAuth 2.0, JWT
- nginx, AWS EC2
- GitHub Actions, Jenkins
프로젝트 진행 내용
1. 대량의 데이터의 페이징 쿼리 성능 개선
문제 상황
- Review - Product, Following - Member 사이의 연관관계가 존재하는 상황에서 Product와 Member는 각각 Review와 Following에 의존한 정렬을 서브쿼리를 통해 진행
- 데이터의 개수 20만 개 기준 서브쿼리를 사용하는 테이블에 인덱스를 사용해도 1초가 걸릴 정도로 저하
문제 해결
- 테이블에 집계 컬럼을 두어 서브쿼리를 사용하지 않도록 함
- 1초가 걸리던 쿼리 실행 시간을 0.25초로 단축
- 커버링 인덱스를 사용하여 대부분의 row를 인덱스 풀 스캔으로 대체하고, 실제 조회할 row만 테이블 풀 스캔을 하도록 개선
상세 내용 링크
블로그 - 쿼리 개선기 1편
블로그 - 쿼리 개선기 2편
2. JPA 페이지네이션과 N+1 문제 해결
문제 상황
- Member - InventoryProduct는 일대다 양방향 관계, InventoryProduct - Product는 다대일 단방향 관계
- DTO로 변환 과정에서 N+1 문제가 발생했으나 페이지네이션으로 인해 fetch join을 사용할 수 없는 문제 발생
@BatchSize
로는 1 depth의 연관관계만 조회할 수 있는 한계 존재
문제 해결
@BatchSize
방식을 직접 구현하고 fetch join을 함께 활용하기로 결정
- Member만 조회 뒤 조회된 Member들의 id를 where ~ in fetch join으로 InventoryProduct - Product를 조회
- in 절로 조회해 온 InventoryProduct들을 애플리케이션 레벨에서 연관된 Member에 맞게 조립하는 로직 작성
- 총 두 개의 쿼리로 N+1 문제 해결
상세 내용 링크
블로그 - 쿼리 개선기 2편
3. 동시성 문제로 인해 데이터베이스 정합성이 맞지 않는 문제 해결
문제 상황
- 집계 컬럼을 JPA의 변경 감지 기능을 이용해 업데이트하는 과정에서 한 레코드에 대해 여러 트랜잭션이 동시에 접근할 경우 컬럼 값과 실제 집계 값이 일치하지 않는 정합성 문제 발생
- 문제 상황 모식도

문제 해결
- 배타락을 사용하는 비관적 락
- 정합성 문제는 해결되나 트랜잭션 시작 시점부터 배타락이 걸리게 되기 때문에 다른 트랜잭션들의 지연 시간이 길어지는 문제 발생
- 낙관적 락
- 낙관적 락으로 인해 집계 컬럼을 업데이트 하는데 실패하면 주 비즈니스 로직도 롤백되는 문제 발생
- 집계 컬럼 값을 활용하여 계산하는 쿼리를 직접 실행 → 채택
- JPA 변경 감지를 사용하지 않아 도메인이 빈약해지고 객체 지향적인 코드를 다소 포기하게 됨
- 정합성 문제를 확실히 해결할 수 있고, 업데이트 쿼리를 실행하는 시점에 비로소 락을 얻게 되기 때문에 트랜잭션들의 지연 시간을 최소화 할 수 있음

상세 내용 링크
블로그 - 동시성 그리고 정합성, 문제 해결기
4. 인수 테스트 가독성 개선
문제 상황
- 인수 테스트에서 사용하는 픽스처와 단위 테스트에서 사용하는 픽스처가 같아 여러 로직이 혼재되어 있는 상태
문제 해결
- 시나리오의 주체(사용자)를 인수 테스트용 픽스처로 만들어서 기존 테스트 픽스처와 분리
- 기존 테스트용 픽스처를 필드로 가지고 있고, 해당 데이터와
RestAssured
를 사용해서 API 요청을 보낼 수 있는 메서드를 보유한 객체를 구현
- 시나리오 상의 진행 상태를 픽스처로 만들어 문장형 테스트 구현
- 오찌.로그인한_상태로().리뷰를_작성한다(); 와 같이 메서드 체이닝을 통해 문장으로 읽히는 테스트 구현
상세 내용 링크
GitHub Pull Request
5. Spring REST Docs가 운영 서버에 배포되지 않는 문제 해결
문제 상황
- 애플리케이션 배포 과정에 Spring REST Docs를 랜딩 페이지로 배포하는 과정이 포함되어 있었으나, 실제 운영 서버에 배포 후 확인해 보니 REST Docs가 배포되지 않는 문제 발생
- 기존에는 문제가 없는 것으로 알았으나 Jenkins 저장 공간의 문제로 배포 완료한 작업 공간을 지우는 설정을 한 이후로 문제 인식
문제 해결
- Jenkins를 수정하기 전 문제가 없어 보이는 과정에서도 실제로는 제대로 REST Docs 배포가 되고 있지 않았음을 확인
- Gradle 빌드 시 출력되는 로그를 분석한 결과, resources 디렉토리의 리소스 파일들을 Jar 빌드 대상 디렉토리로 이동하는
processResources
작업이 테스트 작업 이전이 진행되어 테스트 작업 이후 생성되는 문서는 Jar 파일로 묶이지 않아서 생기는 현상임을 확인
static/docs
로 html 파일을 복사하여 jar에 직접 패키징하는 공식 문서의 배포 과정과는 다르게 src/.../resources
디렉토리로 복사하여서 생기는 문제였음
- 공식 문서의 방법대로 배포할 경우
/docs/index.html
주소로 접속해야 문서를 확인 가능
- 랜딩 페이지로 REST Docs가 열리게 하고 싶었기 때문에 문서 복사를
build/resources/main/static
디렉토리로 하여 Jar 빌드 대상에 포함되도록 하여 문제 해결