전체 글
-
선명하게 생각하는 법을 배운 지난 10주카테고리 없음 2026. 4. 14. 12:00
TLDR; 헤맨 만큼 내 땅이다1. 전체 여정1.1. 1~3주차 - TDD, 소프트웨어 설계, 도메인 모델링 설계의 기초 체력을 만드는 시간이었다. 1주차에는 TDD로 회원가입, 조회, 비밀번호 수정을 구현하면서 '테스트를 반드시 먼저 작성해야 하는가'에 대해서는 완전히 공감하지 못했지만, 테스터블한 코드를 만드는 사고방식이 자연스럽게 책임 분리와 레이어 경계를 강제한다는 걸 체감했다. 이 사고방식을 바탕으로 2주차에서는 코드 작성 전에 요구사항 명세서, 시퀀스 다이어그램, ERD를 먼저 작성하고 계약에 의한 설계를 적용해서 사전조건, 불변식, 사후조건을 정의했다. 또, 좋아요 중복 처리, 삭제 전략, 재고 제어, 주문 총액 관리 등 8개의 트레이드오프 판단을 내리면서 당장 결정할 수 있는 것과 미룰..
-
랭킹을 구현하며 해본 3가지 고민카테고리 없음 2026. 4. 10. 17:18
상품 랭킹을 Redis ZSET으로 구현했다. ZINCRBY 한 줄이면 score가 올라가고, ZREVRANGE 한 줄이면 Top N이 나온다. 첫 번째 문제를 만나기 전까지는 간단했다. 누적 ZSET의 롱테일을 해결하려 키를 일별로 분리하자 콜드스타트가 문제가 보였고, 콜드스타트를 해결하자 TTL 타이밍 이슈가 보였다. 이 글에서는 각 문제가 왜 발생하는지, 해결책을 왜 그렇게 선택했는지, 그리고 선택하지 않은 대안은 왜 안 되는지를 구체적인 코드와 수치로 풀어간 과정을 정리한다.1. 누적 ZSET의 롱테일1.1. 문제 상황단일 ZSET에 모든 점수를 누적하는 구조를 생각해보자.ZINCRBY ranking 0.7 product:101 // 주문 발생ZINCRBY ranking 0.2 produc..
-
대기열, 점진적 Polling, Rate Limiter로 주문 API 보호하기카테고리 없음 2026. 4. 3. 13:55
대기열을 만들면 주문 API는 안전할 줄 알았다. 그런데 대기열을 구현하고 보니, 진입 시점을 늦추는 것 만으로는 부족한 문제들이 보이기 시작했다.사용자에게 "지금 몇 번째인지, 얼마나 기다려야 하는지"를 어떻게 알려줄 것인가?10,000명이 동시에 순번을 조회하면 서버가 버틸 수 있는가?토큰을 받은 사용자가 한꺼번에 몰리면 주문 API는 안전한가? 이 글에서는 대기열의 사용자 경험과 시스템 보호 관점을 함께 다룬다. 또, 설계 과정에서 발견한 시스템이 다운될 수 있는 시나리오를 분석하고 방어선을 추가한 기록이다.1. 사용자에게 무엇을 보여줄 것인가 쿠폰 발급은 "신청 완료, 결과는 나중에 확인하세요"로 끝난다. 하지만 주문 대기열에서 사용자는 실시간으로 기다린다. 이 기다리는 동안 아무 정보도 주지 ..
-
이벤트가 조용히 사라지지 않게 하려면카테고리 없음 2026. 3. 27. 15:42
부제: Outbox부터 DLQ까지, 이벤트 신뢰성을 확보하는 3가지 안전망 DB 커밋 직후, 메시지 브로커에 이벤트를 보내는 사이에 서버가 재시작되었거나 네트워크 장애가 발생하면 코드상으로는 문제가 없어 보이지만 이벤트가 사라질 수 있다. 이 글에서는 이 문제의 구조적 원인인 Dual Write를 분석하고, Transactional Outbox 패턴으로 해결하는 과정을 다룬다. 또한 스터디에서 Kafka에게 이벤트를 발행하는 Relay를 직접 구현했던 경험과, 실무에서 AWS 기반으로 운영했던 사례를 함께 비교해보면서 이벤트 신뢰성을 어떻게 확보했는지 정리해본다. 결론부터 말하면 이벤트 신뢰성을 확보하기 위해 다음과 같은 3가지 안전장치를 구성했다.1차: Outbox → 이벤트가 반드시 발행된다2..
-
안전하게 결제하기카테고리 없음 2026. 3. 20. 17:06
결제는 다른 도메인과 결이 다르다. 브랜드, 상품 관리 등은 하나의 시스템 내부에서 모든 것이 완결되지만, 결제는 외부 PG 서버에 HTTP 요청을 보내고 비동기 콜백으로 상태가 확정되는 구조다. PG에 장애가 나면? 응답이 5초 넘게 지연되면? 콜백이 2번 오면? 이런 상황에 대비하지 않으면 사용자는 "결제했는데 실패 화면"을 보거나, 더 심각하게는 "이중 결제"를 경험하게 된다. 결제 도메인에서 내결함성 패턴이 필수인 이유다. 이 글에서는 Resilience4j의 서킷 브레이커 + 재시도 + 타임아웃을 결제 비즈니스 로직에 맞게 설계한 과정을 다룬다. 단순히 라이브러리 사용법이 아니라, "결제라는 맥락에서 왜 이렇게 설계했는가"에 초점을 맞췄다.1. 결제 흐름과 장애 지점결제의 일반적인 흐름을 먼저..
-
캐싱을 했는데 왜 조회는 더 느려졌을까카테고리 없음 2026. 3. 13. 16:38
상품 조회 API의 성능을 개선하기 위해 상품 테이블에 복합 인덱스를 추가하고, Caffeine + Redis 레이어드 캐시를 구현하고, k6로 부하 테스트를 진행했다. 조회 최적화 결과는 예상과 달랐다. 캐시를 적용했더니 오히려 DB 직접 조회보다 느려졌다. 심지어 히트율별 실험에서는 "히트율이 높을수록 조회 속도가 느리다"는 말도 안 되는 결과가 나왔다. 원인을 추적한 결과, MySQL의 InnoDB Buffer Pool이라는 DB 내부의 캐시를 발견했다.⚙️ 테스트 환경 모든 서비스가 단일 머신에서 실행되므로 Redis 통신은 loopback 수준이다. 또한 10만 건 상품 데이터는 128MB Buffer Pool에 충분히 적재될 수 있는 규모다. 이 두 가지 조건이 이후 실험 결과를 해석하는 핵심..
-
[WIL] 루퍼스 4주차 - 동시성Extracurricular Activites/루퍼스 2026. 3. 8. 22:23
1. 이번 주에 새로 배운 것1) id 참조 vs 객체 참조를 나누는 기준 사실 이건 도메인 설계 시에 Aggregate 경계에 따라 정해져야하는 게 맞다. 하지만 이번 주차에 와서야 깊게 생각해봤기 때문에 같은 Aggregate로 묶여서 동기적으로 동작해야 한다면 객체 참조, 밀접한 관계를 가지고 있지만 별개의 Aggregate라면 최종적 일관성만 맞추면 되기 때문에 id 참조라는 기준을 세우게 되었다. 별개의 Aggregate인데 불필요하게 객체 참조를 걸면 DB의 purge 스레드가 길어지기 때문이다. 2) 비용에 따른 동시성 처리 방법 '아토믹 업데이트'는 잘 사용해보지 않았고 사용해야 하는 상황에 대해서도 제대로 고민해본적이 없었다. 아토믹 업데이트는 어플리케이션에서 읽고 제어할 필요가 있는 '..
-
@Transactional은 동시성 문제를 해결해주지 않는다카테고리 없음 2026. 3. 6. 03:25
TL;DR동시성은 MVCC와 Lock이 관리한다. 중요한 것은 트랜잭션의 범위 설정이며, 그 경계는 @Transactional이 아니라 도메인 모델이 결정한다. 목차1. @Transactional에 대한 오해와 진실2. 트랜잭션 범위를 넓히는 요소3. 도메인 경계와 트랜잭션 경계4. 동시성 성능을 고려한 설계 실습5. 트랜잭션은 설계의 결과다 본 포스팅에서는 DB 기술에 대한 깊은 이야기는 다루지 않습니다. 트랜잭션 범위 설계를 위한 원리 이해 용도로 언급하니 참고 부탁드립니다.1. @Transactional에 대한 오해와 진실1.1. @Transactional의 역할 처음 Spring을 사용했을 땐 @Transactional을 마치 동시성 문제를 해결해주는 마법의 도구처럼 인식했었다. 하지만 @Tran..