Redis Stream을 적용한 선착순 이벤트 시스템 (2편)
·
프로젝트
Spring Boot + MySQL로 구현한 선착순 이벤트 시스템 (1편)“매일 오후 1시에 선착순 100명에게 도서를 증정하는 이벤트 시스템”을 개발하게 되었습니다. 처음엔 단순해 보였지만, 높은 동시성과 정확성이 요구되는 이 과제는 생각보다 많은 도전 과제hyodeng.tistory.com 1편에서는 Spring Boot와 MySQL만으로 선착순 이벤트 시스템을 구현하고 그 한계점을 분석했습니다. 이번 글에서는 Redis Stream을 활용하여 시스템을 어떻게 개선했는지 그리고 그 결과로 성능이 어떻게 향상 되었는지 공유하고자 합니다. Spring + MySQL 구조에서의 문제점단일 서버 환경의 Spring Boot + MySQL 구조로 시스템을 구현했을 때 심각한 병목 현상들이 발견되었습니다.DB ..
SQL 튜닝을 통한 API 성능 최적화 (2편)
·
프로젝트
SQL 튜닝을 통한 API 성능 최적화 (1편)현재 댕글 데이터베이스에는 데이터가 약 1,000개 이하로 적은 양이기 때문에 비효율적으로 작성된 쿼리로도 원하는 데이터를 빠른 속도로 가져올 수 있습니다. 하지만 서비스가 성장하면서 데hyodeng.tistory.com 대기 진료 견적서 상세 조회 (GET)테스트 환경 : Local MySQL 8.0 / Local 애플리케이션 서버 / 100만 개 데이터 기준문제 상황사용자가 진료 견적서에 대한 상세 데이터를 조회하기 위해서는 care_estimates 테이블에 들어있는 vet_id, pet_id 등의 id 를 통해 각 vets, pets 에 해당하는 다른 테이블의 정보를 가져와야 했습니다. 기존 구현에서는 세 개의 개별 쿼리를 순차적으로 실행하여 데이터를..
성장하는 서비스를 위한 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..
주소창에 검색어를 입력했을 때 일어나는 과정
·
네트워크
백엔드 개발자로서, 매일 사용하는 웹 브라우저가 어떻게 동작하는지 이해하는 것은 매우 중요하다고 생각합니다. 단순해 보이는 URL 입력 한 번에도 여러 복잡한 과정이 숨어있는데, 이 과정을 자세하게 살펴보려고 합니다.1. URL 입력과 처리브라우저는 사용자가 입력한 URL을 파싱하여 각 구성요소를 분석합니다.https://www.google.com:443/search?q=오늘의+날씨프로토콜 (https://)도메인 (www.google.com) : 웹 서버의 주소로 실제 IP 주소 대신 사람이 기억하기 쉬운 이름을 사용합니다.포트 번호 (443)경로 (/search)쿼리 파라미터 (?q=오늘의+날씨)2. 웹사이트 주소를 실제 컴퓨터 주소로 변환 (DNS 조회)인터넷의 모든 컴퓨터는 IP 주소라는 고유한 ..
Spring Boot + MySQL로 구현한 선착순 이벤트 시스템 (1편)
·
프로젝트
“매일 오후 1시에 선착순 100명에게 도서를 증정하는 이벤트 시스템”을 개발하게 되었습니다. 처음엔 단순해 보였지만, 높은 동시성과 정확성이 요구되는 이 과제는 생각보다 많은 도전 과제를 안겨주었습니다.이 글에서는 Spring Boot와 MySQL만으로 시작해 어떤 문제에 직면했고, 어떻게 이를 분석하고 개선해 나갔는지 경험을 공유하고자 합니다. 요구사항 분석프로젝트 시작 시 다음과 같은 요구사항을 확인했습니다.매일 오후 1시에 선착순 100명 한정 이벤트 진행1분에 10만 건의 요청을 10분간 처리 (초당 약 1,666건)중복 응모 방지정확히 100명까지만 선발다음날 오후 1시에 당첨자 발표가장 핵심적인 요구사항은 초당 1,666건의 요청 중에서 정확히 100명만 선발하고, 동일 사용자의 중복 응모를..
JPA와 MySQL로 구현한 동시성
·
프로젝트
현재 꾸미 서비스에는 좋아요/싫어요 기능의 동시성 제어를 위해 Redis를 사용하고 있었습니다.그러나 기능 분석 결과, Redis 사용이 오버 엔지니어링이라고 판단했습니다.Redis를 사용하지 않으려는 이유좋아요/싫어요 기능은 SNS 서비스와 달리 실시간성이 매우 중요한 기능이 아닙니다. 사용자들이 동시에 좋아요 버튼을 누르는 상황이 자주 발생하지 않으며, 초당 처리해야 할 트랜잭션 수가 많지 않습니다. 즉, 수 밀리초 단위의 즉각적인 반영보다는 좋아요 수의 정확성이 더 중요합니다. 추가적으로, Redis 사용으로 인한 여러 단점들이 존재했는데,추가 인프라 관리 오버헤드 발생Redis와 MySQL 간 데이터 동기화 로직 필요장애 상황에서 데이터 정합성 보장의 어려움시스템 복잡도 증가이번 기회에 JPA와 ..
미용사 및 병원 검색 API의 N+1 문제 해결
·
트러블슈팅
댕글 서비스에서는 사용자가 미용사와 병원을 검색할 수 있는 API를 제공하고 있습니다. 이 API는 세 가지 주요 검색 조건을 지원합니다.주소 address 기반 검색미용사/병원 이름 name 기반 검색뱃지 badge (#대형견, #중형견, #노견 등) 기반 검색데이터베이스 구조문제를 이해하기 위해 먼저 관련 테이블의 구조를 살펴보겠습니다. 미용사 테이블 groomers 은 뱃지 테이블 grooming_badges 과 자격증 테이블 groomer_business_licenses 과 1:N 관계를 가지고 있습니다.@Entity@Table(name = "groomers")public class GroomerJpaEntity { // ... 기본 필드 생략 ... @ElementCollection ..
SQL 튜닝을 통한 API 성능 최적화 (1편)
·
프로젝트
현재 댕글 데이터베이스에는 데이터가 약 1,000개 이하로 적은 양이기 때문에 비효율적으로 작성된 쿼리로도 원하는 데이터를 빠른 속도로 가져올 수 있습니다. 하지만 서비스가 성장하면서 데이터 양이 100만 개 혹은 그 이상으로 늘어난다면, 초기에 예상했던 것보다 현저히 느린 조회 속도로 사용자 경험을 저하시키게 되고, 이는 사용자 이탈까지 이어질 수 있습니다. 이러한 문제를 미연에 방지하기 위해, 인프라 확장이나 캐싱 시스템 도입과 같은 복잡한 해결책을 적용하기 전에, 가장 기본적이면서도 효과적인 방법인 SQL 튜닝을 시도해보았습니다. 성능 개선 효과를 검증하기 위해 100만 개의 더미 데이터를 데이터베이스에 삽입한 후, 서비스의 주요 기능 중 하나인 “일반 진료 대기 견적서 반려동물 정보 반환 API”..
정규화 (Normalization)
·
데이터베이스
데이터베이스 내의 데이터 구조를 조직화하고 최적화하는 과정으로 정규화를 하는 목적은 데이터 중복을 제거하고, 효율성을 향상시키며, 데이터 무결성을 보장하기 위함이다.즉, 테이블 간에 중복된 데이터를 허용하지 않게 함으로써 무결성(Integrity)을 유지할 수 있으며, 데이터베이스의 저장 용량 역시 줄일 수 있다.정규화 목적데이터의 중복을 없애면서 불필요한 데이터를 최소화시킨다.무결성을 지키고, 이상 현상을 방지한다.테이블 구성을 논리적이고 직관적으로 할 수 있다.데이터베이스 구조 확장에 용이해진다.정규화 장점데이터베이스 변경 시 이상 현상(Anomaly)을 제거할 수 있다.정규화된 데이터베이스 구조에서는 새로운 데이터 형의 추가로 인한 확장 시, 그 구조를 변경하지 않아도되거나 일부만 변경해도 된다.데..