CQRS 활용 경매 시스템 성능 최적화(feat. 데이터 누락 이슈)

정석·2024년 10월 13일
2

해결한 방법이 제일 완벽한 수단이 아닐 수 있습니다. 다만, 기술적 경험을 얻을 수 있었고 서버의 트래픽을 예상해볼 수 있던 에피소드였습니다.

🏗 배경 : 성능 문제에 직면

‘실시간 중고 경매 서비스’의 백엔드를 설계하며, 경매 로직에서 발생하는 트래픽을 감당할 수 있을지에 대한 고민이 있었습니다. 이를 검증하기 위해 부하 테스트를 진행했는데, 예상보다 심각한 성능 문제가 드러났습니다.

특정 경매에 1000명의 사용자가 동시에 입찰을 시도했을 때, 8초 이상의 지연이 발생하는 것을 확인했습니다. 경매 시스템에서 속도는 곧 사용자 경험과 직결되기 때문에, 최적화가 시급한 상황이었습니다.

  • 1000명의 트래픽 테스트 결과


🔍 문제 분석 : 병목의 원인

성능 저하의 주요 원인은 하나의 API 요청에서 발생하는 다량의 DB 쿼리였습니다.
이 로직을 자세히 분석한 결과,

  • 경매 입찰 시 여러 테이블을 조회하고 갱신하는 JOIN 쿼리가 많았음
  • 트랜잭션이 길어지면서 DB 부하가 증가
  • 단순히 DB 서버를 Scale Up하는 것으로 해결하기에는 비용과 확장성의 한계

우선, API 를 통해 데이터를 가져올 때 필요한 데이터만 가져오도록 쿼리문을 변경하였습니다.

이후 속도 측면 문제를 해결하기 위해 CQRS 패턴과 캐싱 도입을 고려했습니다.



🚀 CQRS 패턴 도입 : 성능 최적화

CQRS읽기(조회)와 쓰기(갱신) 작업을 분리하는 아키텍처 패턴입니다.

이를 적용하면,

  • 쓰기 로직은 기존 DB에서 수행하여 데이터 정합성을 유지
  • 읽기 로직별도의 조회 전용 DB 또는 캐시에서 가져와 성능을 개선

💡 도입 결정의 이유:

  • 트래픽 분산: 경매에서 가장 많은 요청이 발생하는 부분은 조회(읽기) 작업 → 읽기 부하를 줄여 전체적인 성능 개선
  • 비용 효율성: 단순히 DB 서버를 확장하는 것보다 유지보수가 용이
  • 빠른 데이터 응답: 캐시와 결합하여 조회 성능을 극대화

하지만, CQRS는 단점도 있었습니다.

  • 설계 복잡도 증가: 기존 로직을 읽기/쓰기 분리 구조로 변경해야 함
  • 데이터 일관성 문제: 읽기와 쓰기 데이터 동기화를 위한 캐시 관리 필요

🌟 최신 데이터 누락 이슈
CQRS 를 도입하며, 최신 데이터가 Slave DB로 복제될 때 누락이 되는 현상이 있었습니다.
간헐적으로 복제가 네트워크 환경에 따라 데이터 복제 시간이 딜레이되는 것으로 판단했고,

Redis 캐싱을 도입하여 Mster DB 에 데이터가 저장될 때, Redis 에 최신 데이터 또한 캐싱하여 동기화를 유지하도록 했습니다.
따라서 데이터 변경 또는 삽입될 때 DB 와 Redis 캐시를 동시에 갱신하여 데이터 일관성을 보장하도록 했습니다.



결과 : 약간의 개선

CQRS 패턴을 도입한 후, 실제 부하 테스트를 진행한 결과 약 46%의 성능 개선을 확인했습니다.

테스트 환경평균 응답 속도
적용 전8.5초
적용 후4.9초
  • CQRS 적용 후 1000명의 트래픽 테스트 결과

8.5초 > 4.9 초로 개선되긴 했지만, 서비스 목적이라면 보다 좋은 성능을 보여야 할 거라 생각했습니다.
이후 방안을 팀원들과 상의해 보았고 이 상태에선 DB 서버 Scale up 에 대해 의논하고 있습니다.



🎯 배운 점과 향후 과제

이번 경험을 통해 트래픽 최적화는 단순한 DB 확장 또는 CQRS 만으로 해결되지 않는다는 것을 배웠습니다.

  1. 대량 트래픽을 고려한 설계가 중요하다.
  2. 성능 최적화는 다양한 접근 방식이 있다.
    JOIN 최적화, 인덱싱, CQRS, 캐싱, 비동기 처리 등 상황에 따라 적절한 선택이 필요하다.
  3. 데이터 일관성과 성능 최적화는 트레이드오프가 존재한다.

다음 목표는 더 안정적인 캐싱 전략을 적용하고, CQRS 구조를 점진적으로 개선하는 것입니다.
이번 프로젝트를 통해 트래픽을 고려한 백엔드 설계의 중요성을 다시 한번 깨닫는 좋은 기회가 되었습니다.

0개의 댓글