본문 바로가기

Spring36

펀딩 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. 3.
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.
Redis를 활용한 데이터베이스 캐싱 전략 개요이 문서는 Redis를 사용한 데이터베이스 캐싱 전략에 대한 AWS 백서를 정리한 내용입니다. 인메모리 데이터 캐싱은 애플리케이션 성능을 향상시키고 데이터베이스 비용을 절감하는 가장 효과적인 전략 중 하나입니다.1. 데이터베이스의 주요 과제분산 애플리케이션을 구축할 때 디스크 기반 데이터베이스는 여러 문제점을 가지고 있습니다.1.1 느린 쿼리 처리디스크에서 데이터를 검색하는 물리적 시간과 쿼리 처리 시간으로 인해 응답 시간이 밀리초 단위로 증가최적화된 상태에서도 최소 수십 밀리초의 응답 시간 소요1.2 확장 비용NoSQL이든 관계형 데이터베이스든 높은 읽기 성능을 위한 확장 비용이 높음단일 인메모리 캐시 노드가 제공하는 초당 요청 수를 맞추려면 여러 개의 데이터베이스 읽기 복제본이 필요1.3 데이터 .. 2025. 10. 23.
Spring Boot 환경에서의 직렬화(Serialization) 이해하기 직렬화란 무엇인가?직렬화(Serialization)는 프로그램 메모리에 존재하는 데이터를 저장하거나 전송 가능한 형태로 변환하는 과정입니다.프로그램이 실행되는 동안 JVM 메모리에는 다양한 객체들이 생성되고 소멸됩니다. 이러한 객체들은 프로그램이 실행 중일 때만 존재하며, 프로그램이 종료되면 함께 사라집니다. 만약 이 데이터를 파일에 저장하거나, 네트워크를 통해 전송하거나, 다른 프로세스와 공유하려면 메모리 상의 객체를 특정 형식으로 변환해야 합니다.반대로, 저장되거나 전송된 데이터를 다시 메모리의 객체로 복원하는 과정을 **역직렬화(Deserialization)**라고 합니다.왜 직렬화가 필요한가?메모리와 저장소는 서로 다른 언어를 사용한다다음과 같은 자바 객체가 있다고 가정해봅시다.public cla.. 2025. 10. 22.
Entity 식별자 전략: UUID vs Auto Increment vs Snowflake 목차들어가며1. Auto Increment (순차적 증가)개념장점단점적합한 사용 사례2. UUID (Universally Unique Identifier)개념장점단점최적화 방법적합한 사용 사례3. Snowflake ID개념구조장점단점구현 예제적합한 사용 사례4. 전략 비교표5. 실무 적용 가이드마치며 들어가며Spring JPA에서 Entity의 식별자(ID)를 어떻게 설계할지는 시스템 아키텍처에서 중요한 결정사항입니다. 이 글에서는 세 가지 주요 식별자 전략(Auto Increment, UUID, Snowflake)의 특징과 장단점을 비교하고, 각 상황에 맞는 최적의 선택 방법을 알아보겠습니다. 1. Auto Increment (순차적 증가)Auto Increment 개념데이터베이스가 자동으로 1씩 증가.. 2025. 10. 1.
Java 21 Virtual Thread가 만드는 새로운 조합: MSA 서비스 간 통신의 4가지 선택지 들어가며Java 21의 Virtual Thread 등장으로 마이크로서비스 아키텍처에서 서비스 간 통신에 대한 선택지가 크게 확장되었습니다. 기존에는 HTTP 클라이언트 선택과 스레드 모델이 거의 고정적으로 결합되어 있었지만, 이제는 더 다양한 조합이 가능해졌습니다.- HTTP 클라이언트: OpenFeign vs WebClient- 스레드 모델: Platform Thread vs Virtual Thread이 두 축의 조합으로 총 4가지 접근 방식이 가능해진 것입니다. 각각의 조합이 어떤 특성을 가지며, 언제 어떤 선택을 해야 하는지 분석해보겠습니다.4가지 조합의 전체 그림1. OpenFeign + Platform Thread (전통적 방식)특징: 간단한 API, 제한된 동시성적합한 상황: 단순한 서비스, .. 2025. 9. 18.
MSA에서 WebClient와 Reactive Resilience4j 선택의 기술적 이점 들어가며마이크로서비스 아키텍처(MSA)에서 가장 흥미로운 점 중 하나는 각 서비스가 독립적으로 기술 스택을 선택할 수 있다는 것입니다. 서비스 간 통신에서도 마찬가지로, 어떤 팀은 OpenFeign의 선언적 접근 방식을 선호할 수 있고, 다른 팀은 WebClient의 리액티브 스트림을 활용할 수 있습니다.이번 글에서는 WebClient와 Reactive Resilience4j를 선택했을 때의 기술적 이점과 OpenFeign 대비 어떤 차별화된 가치를 제공하는지 살펴보겠습니다.MSA에서 기술 선택의 자유로움MSA의 핵심 철학 중 하나는 "적합한 도구를 적합한 상황에 사용하는 것"입니다. 같은 조직 내에서도 서비스별로 다음과 같은 다양한 선택이 가능합니다:팀별 다른 접근법팀 A: OpenFeign + 동기식.. 2025. 9. 18.
Spring Boot 검증 처리 아키텍처 전략: 컨트롤러에서 BindingResult를 직접 처리하지 말아야 하는 이유 들어가며Spring Boot 환경에서 REST API 개발 시, @Valid 검증 오류를 어떻게 처리할지는 중요한 아키텍처 결정 사항입니다. 많은 개발팀에서 컨트롤러에서 BindingResult를 직접 처리하는 패턴을 사용하고 있지만, 이는 관심사 분리 원칙을 위반하고 코드 품질을 저하시키는 안티패턴입니다.본 아티클에서는 왜 컨트롤러에서 BindingResult를 직접 처리하면 안 되는지, 그리고 GlobalExceptionHandler를 활용한 중앙화된 예외 처리 전략이 더 나은 선택인지 기술적으로 분석해보겠습니다.Spring MVC 검증 처리 메커니즘의 이해HandlerAdapter의 검증 처리 전략Spring MVC의 HandlerAdapter는 BindingResult 매개변수의 존재 여부에 따라.. 2025. 9. 16.
데이터베이스 커넥션 풀 최적화 - 성능과 안정성 향상 들어가며데이터베이스 커넥션은 애플리케이션에서 가장 중요하면서도 제한적인 자원 중 하나입니다. 커넥션을 효율적으로 관리하지 못하면 성능 저하, 응답 지연, 심지어 서비스 장애까지 발생할 수 있습니다. 이번 포스트에서는 커넥션 풀의 개념부터 실제 최적화 방법까지 상세히 알아보겠습니다. 커넥션 풀의 이해커넥션 풀이란커넥션 풀은 데이터베이스 연결을 미리 생성해서 풀에 저장해두고, 필요할 때마다 재사용하는 메커니즘입니다. 매번 새로운 커넥션을 생성하고 종료하는 비용을 절약할 수 있습니다. 커넥션 풀 없이 사용할 때의 문제점// 문제가 되는 코드 - 매번 새로운 커넥션 생성public List getUsers() { Connection conn = null; try { // 1. 커넥션 생성.. 2025. 7. 14.
파일 저장소 분리와 CDN 활용 - 대용량 파일 처리 최적화 들어가며현대의 웹 애플리케이션에서는 이미지, 동영상, 문서 등 다양한 형태의 파일을 처리해야 합니다. 이러한 파일들을 애플리케이션 서버나 데이터베이스에 직접 저장하면 성능 저하와 확장성 문제가 발생할 수 있습니다. 이번 포스트에서는 파일 저장소를 분리하고 CDN을 활용하여 효율적으로 파일을 관리하는 방법을 알아보겠습니다. 파일 저장소 분리의 필요성기존 방식의 문제점1. 데이터베이스에 파일 저장-- 문제가 되는 구조CREATE TABLE posts ( id BIGINT PRIMARY KEY, title VARCHAR(255), content TEXT, image_data LONGBLOB -- 이미지를 직접 저장); 문제점:데이터베이스 크기 급속 증가백업 및 복원 시간 증가메모리 사용.. 2025. 7. 14.