콘서트 티켓팅 서비스
📌 3~5주차 서버 구축
3주차
주어진 요구사항을 분석하고 마일스톤, 시퀀스 다이어그램, ERD 다이어그램, API 명세서 등 설계와 개발 계획 수립에 있어 주요 문서들을 작성했다.
취업 전에 한창 회사를 알아볼 때, "개발자인데 문서 작업을 더 많이 해요," 라고 불만있어 하는 글을 많이 봤었다.
직접 작성해보기 전까지는 나도 개발자가 문서 작업을 왜 해야하는 지 이해하지 못했었다.
하지만 마일스톤을 작성하면서 얼추 언제 얼마만큼의 개발을 해야겠다는 계획이 러프하게 세워졌고,
분석한 요구사항을 바탕으로 시퀀스 다이어그램을 그려보며 개발 방향이 명확해졌으며,
ERD 다이어그램, API 명세서를 작성하면서 각각 DB와 API의 윤곽을 잡을 수 있었다.
또한 피어리뷰 시간에 느낀 건데, 작성해둔 문서를 보고 설명하는 것이 코드를 바탕으로 설명하는 것보다 훨씬 쉬웠다.
4주차
Swagger 문서 작성 및 TDD 기반으로 주요 API의 Business/Infrastructure 로직을 완성했다.
프론트엔드 개발을 하면서 백엔드 개발자 분과 협업을 할 때, 간혹 API 쪽에서 넘어오는 에러를 어떻게 처리해주어야 할 지 알 수 없을 때가 있다.
어떻게 처리해야 하는 지 요청해도 답변이 바로 오는 것이 아니니, 빠르게 개발해야 하는 입장에선 답답할 때도 부지기수.
그래서 API를 개발하면서 발생할 수 있는 에러들을 최대한 처리하고 그것을 명시하는 Swqgger 문서를 작성했다.
이 과정에서 에러가 이렇게나 다양하다는 것을 새삼 깨달았다. (최대한 옳다고 생각하는 에러를 지정했는데 인텔리제이가 계속 다른 걸 추천해주었다...)
다음에 예외처리 할 때는 커스텀 Exception으로 처리를 해봐야겠다.
5주차
미흡한 점을 리팩토링하고, 필요한 Filter와 Intercepter, 예외처리, 로깅 등의 기능 구현을 넣어 서버 구축을 마무리했다.
클린아키텍처를 추구한다는 큰 틀은 있지만, 코치님들 사이에서도 저마다 방법이 조금씩은 다르셨다.
같이 수업 듣는 동기들 깃헙을 뒤져봐도 저마다 조금씩 달라서 클린아키텍처를 처음 배운 2주차에는 멘붕도 그런 멘붕이 없었다.
그래서 서버 구축을 마무리하며 5주차의 목표는 "클린아키텍처 하나는 확실히 구현하자," 에 더해 "각 로직이 어떤 책임을 가져가야 할 지 고민하며 개발하기," 였다.
리팩토링 할 코드가 아주 많았다.
예를 들어 예약 도메인은 비즈니스 로직인데 유저도 부르고 좌석도 부르고 좌석 상태 변경하고 예약 만들고 아주 바쁜 녀석이었다.
그래서 이런 복잡한 조립의 역할은 파사드에 맡기고 도메인에는 saveReservation 이름에 어울리는 예약 저장하는 책임만 주었다.
예약 상태를 변경하고 예약을 만드는 역할은 엔티티에 맡김으로써 응집도를 높이고 보다 객체지향적인 코드를 지향할 수 있게 되었다.
이런 노력이 보람되게도 그 주에 명예의 전당에 올랐다
📌 6~9주차 대용량 트래픽 & 데이터 처리
6주차
내 시나리오에서 동시성 문제가 발생할 수 있는 부분을 파악하고 동시성 제어 방법을 도입해보았다.
DB에 락을 걸어 동시성 이슈를 제어할 때 어떤 방법을 쓸 지는, 시각에 따라 다양하게 나왔다.
예를 들어 좌석을 예약할 때 동시성 이슈가 많이 발생한다는 점에 초점을 두면 비관적 락이 고려되었고,
누군가 락을 획득하면 다른 사람들은 예매를 할 수 없으므로 빠르게 다른 좌석을 예매할 수 있도록 하는 사용자 경험에 초점을 두면 낙관적 락이 고려되었다.
또 비관적 락을 걸면서도 사람들이 오래 기다리지 않도록 부러 예외를 발생시키거나 다른 방법을 사용할 수도 있다고 한다.
6주차 과제를 하면서 어떤 락이 어울릴 지 조원들과 많은 얘기를 나눠서 결정했었는데,
현업에서는 어떤 경우에 어떤 식으로 사용하는 지가 너무 궁금해지면서 6주차를 마무리했다.
7주차
자주 사용되지만 빈번하게 바뀌지 않는 데이터에 대해 캐싱 전략을 적용하여 성능을 향상시켜 보았다.
기존에 DB로 구현했던 대기열을 레디스 대기열로 바꿔보았다.
한 번 등록되면 빈번하게 바뀌지 않을 콘서트 목록과 콘서트 옵션을 CacheAside 전략으로 캐싱하고,
Expiration로 만료시간을 설정하는 대신 CacheEvict로 원하는 시점에 캐싱된 데이터를 지울 수 있도록 하였다.
캐싱 전후의 차이는 10배나 났다.
조회에서 예약까지 하나의 유저플로우에서 소요되는 시간과 1분동안 처리 가능한 사용자 수를 계산하여,
1분에 한 번씩 계산된 수만큼 waiting 토큰을 active 토큰으로 바꿔주는 로직을 구현하였다.
(10주 간의 일정 중에서 캐싱으로 성능을 향상시키고 레디스 대기열을 구현해서 유량 제어를 하는 7주가 가장 재밌었기 때문에, 대기열을 다루는 서비스가 있는 현업으로 이직하고 싶다.)
8주차
인덱싱을 추가하여 쿼리의 성능개선을 도모했다.
콘서트 티켓팅 서비스를 마이크로서비스 아키텍처(MSA)로 전환 시 그에 따른 트랜잭션 문제점을 분석하고 해결방안에 대해 보고서를 작성해보았다.
기존에 slow 쿼리로 의심되는 쿼리들에 Explain Analyze를 실행하여 분석하고 인덱스 생성 전략에 따라 적절한 인덱스를 추가했다.
하지만 인덱싱 적용 전후를 비교했을 때 예상 시간이 오히려 증가해서 당황스러웠다.
원인을 추측만하다가 Explain Analyze를 사용하지 않고 쿼리 실행 시간 자체를 비교했다.
Explain Analyze로 분석했던 결과와 달리 실제 실행 시간은 인덱싱 적용 후가 더 빨랐다.
좀 더 알아보니 Explain Analyze는 단순히 쿼리를 실행하는 것과 달리 실행 계획과 실제 성능 데이터를 수집하고 이를 출력하기 위한 작업을 수행한다고 한다.
인덱싱을 적용하면서 이 작업이 더 복잡해졌고, 때문에 예상 시간이 더 증가한 결과가 나온 것으로 보인다.
콘서트 티켓팅 시스템 MSA 전환에 따른 트랜잭션 문제점 분석.md
내 시나리오 상의 유즈케이스 별로 서비스 간의 상호작용을 분석했다.
이어 서로 상호작용하는 서비스들을 분리했을 때 발생할 수 있는 문제점과 해결 방안을 보고서로 작성했다.
또한 서비스 분리 상황을 가정하고 이벤트 메시지 발행 기능을 추가했다.
9주차
Docker를 이용해 Kafka를 설치 및 실행하고, 기존의 이벤트 메시지 발행 기능을 카프카로 대체했다.
사실 카프카는 아직 어렴풋하게만 이해를 했다...
📌 10주차 장애 대응
10주차
부하 테스트 대상을 선정하여 시나리오를 세우고 이를 테스트하여 보고서로 작성했다.
또한 위 테스트를 바탕으로 가상 장애 대응 문서를 작성했다.