3주 전 금요일, 넘블 타임딜 서버 구축하기 챌린지를 시작했다. 챌린지 마감인 오늘까지도 모든 요구가 구현된 상태가 아니라 조금 부끄럽다. 그래도 마감일이 다가왔으니 회고를 작성하고, 이후에 프로젝트를 더 보충해나가는 것으로 해본다.
나는 이 챌린지에 4가지 목표가 있다고 생각한다. 그 목표는 다음과 같다.
Java+Spring을 통한 쇼핑몰 API 구현, 상품 수량 동시성 문제 해결, CI/CD 구축, 성능 테스트 및 모니터링을 통한 성능 개선
이 목표들을 달성하기 위해 마일스톤을 통해 3주의 시간을 관리했다.

1주차: 설계 및 환경 구축
API 설계, ERD 설계, 와이어프레임 설계, 프로젝트 생성, CI/CD 구축 등 프로젝트를 진행하기 위한 기반을 마련했다.
첫째로, 와이어프레임을 그리면서 동시에 API와 ERD를 설계했다. 하다보니 설계에 잦은 변경이 일어난다는 것을 깨달아서 어느정도 마무리하고 다음 작업에 들어갔다.
둘째로, 프로젝트를 생성하고 CI/CD를 구축했다. 스프링 부트를 사용했기 때문에 프로젝트 생성은 쉽게 했다. CI/CD는 네이버 클라우드 플랫폼(NCP)과 Jenkins를 활용했는데, 둘 다 처음 접해본 거라 구축에 오랜 시간이 걸렸다. NCP에서 제공하는 Jenkins 이미지를 활용하면 조금 낫다. 하지만 최신 버전의 Jenkins를 사용하기 위해서는 서버에 접속해서 Jenkins를 제거하고 최신 버전으로 재설치하는 과정이 요구된다.
셋째로, Application Server와 Database Server를 구축했다. Application Server는 회원가입 후 1년간 무료로 제공되는 micro server를 활용했다. Database Server는 넘블과 NCP에서 제공하는 크레딧이 있어 과감하게 Cloud DB for MySQL을 활용했다. 내 경험에 비추어보자면, NCP의 Cloud DB는 AWS의 RDS와 비슷하다.
NCP의 장단점에 대해 이야기해보자.
장점으로는, 공식 한국어 튜토리얼이 매우 친절해서, 그대로 따라하기만 해도 환경을 구축할 수 있다. 한국어가 특유의 번역체 느낌이 없이 매우 자연스러워서 이질감이 없는 게 큰 장점이다.
단점으로는, 인터넷에서 얻을 수 있는 정보가 한정적이다. 외국의 대규모 클라우드 서비스의 경우, 영어로 검색하면 온갖 사이트에서 문제 해결 방법이나 튜토리얼을 손쉽게 찾아볼 수 있다. 하지만 NCP는 한국 유저들의 글이 대부분이고, 자료의 양 자체도 적다.
2주차~3주차: API 개발
Github Flow에 따라 API를 개발했다.
User, Order, Product 도메인으로 나누어 개발했다. 각 서비스 메서드를 시뮬레이션해보면서 세 도메인의 연관관계를 어떻게 설정할지 생각을 많이 했다. 결과적으로는 다음과 같은 ERD가 나왔다.
테이블 조회 쿼리를 짤 때 힘들었다. 간단한 조회는 JpaRepository를 활용하면 됐는데, 조건이 복잡해지면 메서드가 너무 길어져서 가독성이 떨어졌다. JpaRepository로 이 정도 비즈니스 로직을 건드려본 적이 없어서 그런가? 그래도 테이블 하나 건드는 쿼리는 짤만했다. 진짜 문제는 따로 있었는데... 바로 테이블 3개를 모두 조인해야 하는 product_id로 해당 Product를 구입한 모든 User를 중복없이 조회하여 페이징된 결과를 내보내는 쿼리였다. 결국 인터넷을 통해 해결하긴 했으나, 내가 쿼리 작성에 약하다는 걸 느꼈다.
상품 수량 동시성 문제는 타임딜처럼 동시에 요청이 많이 들어오는 서비스에서 자주 발생하는 문제이다. 이전에도 몇 번 접해본 이야기였지만 실제 활용해보는 것은 처음이라 기대가 컸다.
이 문제를 해결하는 가장 단순한 방법은 Java의 synchronized 키워드를 활용하는 것인데, 이는 서버가 여러 대일 경우 동시성 문제를 해결할 수 없어 미래에 서버가 수평적 확장될 것을 생각하여 다른 방법을 찾았다. 다음으로 생각한 방법은 락을 거는 것이었는데, 이는 낙관적 락과 비관적 락으로 나뉜다. 낙관적 락은 트랜잭션이 충돌하지 않는다고 가정하는 것이다. 비관적 락은 트랜잭션이 충돌한다고 가정하고 데이터베이스 테이블 자체에 락을 거는 것으로, 동시간에 많은 구매하기 요청이 몰리는 타임딜 서버에 적합하다고 느꼈다.
이미지 CRUD, 성능 테스트 및 모니터링과 조회 성능 개선을 해보지 못하고 기간이 끝나서 아쉽다. 그래도 CI/CD, 동시성 문제 해결, 복잡한 쿼리 작성을 경험해볼 수 있어 좋았다. 비록 프로젝트는 끝났지만, 이후에 Object Storage를 통한 이미지 CRUD, 성능 테스트 및 모니터링을 통한 조회 성능 개선, JpaRepository로 작성된 쿼리를 QueryDSL로 변경하는 등의 기능 개발과 리팩터링을 진행할 것이다.
'Project > 타임딜 서버' 카테고리의 다른 글
| 인덱스를 통한 목록 조회 성능 개선 (0) | 2023.03.22 |
|---|---|
| deleteUser(회원 탈퇴)를 어떻게 구현할 것인가 (0) | 2023.03.12 |