-
펀딩 API 성능 개선기: TPS 61에서 100으로
들어가며음악 크라우드펀딩 플랫폼을 개발하면서 가장 중요한 기능은 단연 '후원하기'였습니다. 사용자가 프로젝트에 후원하는 이 핵심 기능의 성능 테스트를 진행했을 때, 결과는 예상보다 좋지 않았습니다. TPS 61.6, 평균 응답 시간 3850ms. 이 글에서는 이를 TPS 100, 평균 응답 46ms까지 개선한 과정을 공유하려 합니다. 초기 성능, 그리고 문제의 시작처음 부하 테스트를 돌렸을 때의 결과입니다.요청 수: 1000건TPS: 61.6/sec평균 응답 시간: 3850ms최소: 167ms최대: 9462ms표준편차: 1705ms평균 응답 시간이 거의 4초에 가깝습니다. 더 심각한 것은 최대 응답 시간이 9초를 넘어간다는 점이었습니다. 저희는 AWS ECS에 배포할 계획이었고, 제한된 예산 내에서 인프..
2025.12.10
-
Spring Boot에서 Redisson을 활용한 분산 락 구현하기
들어가며MSA(Microservices Architecture) 환경에서 개발을 하다 보면 한 가지 자주 마주하게 되는 문제가 있습니다.바로 여러 서버 인스턴스가 동시에 동일한 스케줄러를 실행하는 상황입니다.제가 개발 중인 음악 크라우드펀딩 플랫폼에서도 같은 문제가 발생했습니다.“프로젝트 시작 스케줄러”, “프로젝트 종료 스케줄러”, “Outbox 이벤트 재시도 스케줄러”가 서버 2대 이상에서 동시에 실행되면서, 동일한 프로젝트가 중복 처리되는 상황이 생긴 것입니다. 이런 경우 데이터 정합성이 깨지고, 불필요한 중복 작업으로 인해 시스템 부하가 증가할 수 있습니다.이 문제를 해결하기 위해 다양한 방식을 검토한 끝에, Redis 기반의 Redisson 분산 락을 도입하게 되었습니다. 아래에서는 이를 AOP..
2025.12.03
-
분산 트랜잭션에서 Outbox 패턴 사용하기
어떤 문제가 있었냐면...크라우드펀딩 플랫폼을 만들고 있는데요, Funding 서비스가 다른 서비스들(Reward, Payment)이랑 통신해야 하는 상황이었습니다.비즈니스 플로우는 이렇습니다1. 사용자가 후원 버튼 클릭2. Reward 서비스한테 티켓 재고 감소 요청3. Payment 서비스한테 결제 요청4. Funding DB에 저장5. 통계 업데이트간단해 보이죠? 근데 여기서 문제가 생겼는데요, 실제로 겪은 문제들 케이스 1: 티켓은 예약됐는데 결제가 실패함✅ Reward 서비스: 재고 감소됨 (이미 커밋됨)❌ Payment 서비스: 결제 실패❌ Funding DB: 저장 안 됨 (롤백됨)결과: 티켓 재고만 줄어들고 실제 후원은 안 된 상태 💥사용자 입장에선 결제 실패했다고 나오는데, 티켓은 이미..
2025.12.02
-
AWS ECS 기반 MSA 구축 시 서비스 디스커버리 방식 비교
안녕하세요. 이번 포스팅에서는 AWS ECS Fargate 환경에서 마이크로서비스 아키텍처(MSA)를 구축할 때 고민했던 서비스 디스커버리 방식에 대해 공유하고자 합니다.프로젝트 배경저희 팀은 음악 크라우드펀딩 플랫폼을 MSA로 구축하고 있으며, 다음과 같은 환경에서 개발하고 있습니다.기술 스택: Spring Boot (Java 21), AWS ECS Fargate서비스 구성: 5개의 마이크로서비스 (Funding, Payment, Reward 등)예상 트래픽: DAU 50,000 ~ 100,000명, 피크 타임 TPS 5,000 ~ 10,000프로젝트 기간: 1개월팀 구성: 4명이러한 환경에서 서비스 간 통신을 어떻게 구성할지 고민하게 되었고, 3가지 방식을 비교 분석했습니다.제가 생각한 우리 서비스가..
2025.11.26
-
DDD에서 AbstractAggregateRoot 이해하기
AbstractAggregateRoot1. AbstractAggregateRoot란?Spring Data에서 제공하는 도메인 이벤트 발행을 위한 추상 클래스입니다. 애그리거트 루트가 이를 상속받으면 도메인 이벤트를 쉽게 등록하고 자동으로 발행할 수 있습니다.import org.springframework.data.domain.AbstractAggregateRoot;public class Order extends AbstractAggregateRoot { public void pay() { this.status = PAID; registerEvent(new OrderPaidEvent(this.id)); }}2. 핵심 역할2.1 도메인 이벤트 저장소public abstra..
2025.10.30