Redis Stream을 적용한 선착순 이벤트 시스템 (2편)
·
프로젝트
Spring Boot + MySQL로 구현한 선착순 이벤트 시스템 (1편)“매일 오후 1시에 선착순 100명에게 도서를 증정하는 이벤트 시스템”을 개발하게 되었습니다. 처음엔 단순해 보였지만, 높은 동시성과 정확성이 요구되는 이 과제는 생각보다 많은 도전 과제hyodeng.tistory.com 1편에서는 Spring Boot와 MySQL만으로 선착순 이벤트 시스템을 구현하고 그 한계점을 분석했습니다. 이번 글에서는 Redis Stream을 활용하여 시스템을 어떻게 개선했는지 그리고 그 결과로 성능이 어떻게 향상 되었는지 공유하고자 합니다. Spring + MySQL 구조에서의 문제점단일 서버 환경의 Spring Boot + MySQL 구조로 시스템을 구현했을 때 심각한 병목 현상들이 발견되었습니다.DB ..
성장하는 서비스를 위한 DDD 기반 멀티 모듈 전환기
·
프로젝트
변화의 필요성댕글 서비스를 개발하면서 초기에는 빠른 기능 구현과 배포를 위해 일반적인 Spring Boot 기반의 모놀리식 아키텍처로 시작했습니다.com.daengle├── controller│ ├── UserController.java│ ├── GroomerController.java│ ├── VetController.java│ ├── PaymentController.java│ └── ...├── service│ ├── UserService.java│ ├── GroomerService.java│ └── ...├── repository│ ├── UserRepository.java│ └── ...├── entity│ ├── User.java│ ├── Groomer..
Spring MVC의 진입점을 파고들어 개선한 JWT 토큰 처리 시스템
·
프로젝트
시작은 불편함에서멀티 모듈로 구성된 댕글 서비스에서 Auth 모듈은 사용자 인증과 인가를 담당하는 핵심 모듈입니다.Spring Security + JWT + OAuth2.0을 기반으로 구축된 이 모듈은 처음에는 단순히 “동작하는 코드”를 만드는 데 초점을 맞췄습니다. 초기 구현에서는 로그인 성공 시 사용자 정보가 담긴 JWT 토큰을 생성하고, 보호된 엔드포인트에 접근할 때마다 이 토큰을 검증하는 방식이었습니다. 그러나 REST API를 개발하면서 사용자의 인증 상태나 권한을 확인해야 하는 엔드포인트가 늘어났고, 각 컨트롤러마다 토큰 처리 코드가 반복되었습니다. 초기 구현 방식@RestController@RequiredArgsConstructor@RequestMapping("/api/user")public..
Spring Boot + MySQL로 구현한 선착순 이벤트 시스템 (1편)
·
프로젝트
“매일 오후 1시에 선착순 100명에게 도서를 증정하는 이벤트 시스템”을 개발하게 되었습니다. 처음엔 단순해 보였지만, 높은 동시성과 정확성이 요구되는 이 과제는 생각보다 많은 도전 과제를 안겨주었습니다.이 글에서는 Spring Boot와 MySQL만으로 시작해 어떤 문제에 직면했고, 어떻게 이를 분석하고 개선해 나갔는지 경험을 공유하고자 합니다. 요구사항 분석프로젝트 시작 시 다음과 같은 요구사항을 확인했습니다.매일 오후 1시에 선착순 100명 한정 이벤트 진행1분에 10만 건의 요청을 10분간 처리 (초당 약 1,666건)중복 응모 방지정확히 100명까지만 선발다음날 오후 1시에 당첨자 발표가장 핵심적인 요구사항은 초당 1,666건의 요청 중에서 정확히 100명만 선발하고, 동일 사용자의 중복 응모를..
미용사 및 병원 검색 API의 N+1 문제 해결
·
트러블슈팅
댕글 서비스에서는 사용자가 미용사와 병원을 검색할 수 있는 API를 제공하고 있습니다. 이 API는 세 가지 주요 검색 조건을 지원합니다.주소 address 기반 검색미용사/병원 이름 name 기반 검색뱃지 badge (#대형견, #중형견, #노견 등) 기반 검색데이터베이스 구조문제를 이해하기 위해 먼저 관련 테이블의 구조를 살펴보겠습니다. 미용사 테이블 groomers 은 뱃지 테이블 grooming_badges 과 자격증 테이블 groomer_business_licenses 과 1:N 관계를 가지고 있습니다.@Entity@Table(name = "groomers")public class GroomerJpaEntity { // ... 기본 필드 생략 ... @ElementCollection ..