본문 바로가기

Project10

[whatda] ArgumentResolver로 토큰 인증하기 Spring Security 대신 HanlderArgumentResolver를 사용한 이유이번 프로젝트에서는 복잡한 인증/인가 시나리오가 아닌, 단순한 JWT 기반의 사용자 인증만을 필요로 했습니다. Spring Security는 강력한 보안 기능을 제공하지만, 기본 설정만으로도 상당한 구조적 복잡성이 뒤따르며, 테스트 환경 구성 역시 까다로워지는 경향이 있습니다.따라서 보다 직관적이고 유연한 구현을 위해 Spring MVC의 HandlerMethodArgumentResolver를 직접 활용했습니다. 요청마다 토큰을 파싱하고 사용자 정보를 주입하는 과정을 Resolver에서 처리하도록 하여, 인증 로직을 명확히 분리하면서도 컨트롤러는 순수한 비즈니스 로직에만 집중할 수 있도록 구성했습니다. 이 방식은 구.. 2025. 5. 27.
[s-market] Redis 재고 시스템에서 사용하는 setQuantity() Redis를 재고 캐싱에 사용하는 경우, 가장 흔하게 구현하는 메서드 중 하나가 setQuantity()입니다. 예를 들어, 다음과 같이 현재 재고를 TTL과 함께 덮어쓰는 방식입니다.public void setQuantity(final Long productId, final Long quantity, final Duration ttl) { redisTemplate.opsForValue().set(getKey(productId), String.valueOf(quantity), ttl);} 이 방식은 직관적으로 간단해 보입니다. 하지만 실제 운영 환경에서 setQuantity()는 심각한 동시성 문제를 유발할 수 있습니다. 문제 시나리오다음과 같은 상황을 생각해봅시다.어떤 상품의 Redis 재고가 3.. 2025. 5. 5.
[s-market] Kafka 중복 메시지 소비로 인한 재고 이중 차감 문제 상황사용자가 “구매하기” 버튼을 빠르게 두 번 클릭할 경우, 동일한 주문에 대해 재고가 두 번 차감되는 현상이 발생했습니다.이는 Redis 재고는 두 번 차감되고, Kafka 이벤트도 두 번 발행되어, Consumer가 중복 처리하면 DB 재고도 과도하게 줄어들 수 있습니다. 원인 분석사용자의 두 번 클릭은 두 개의 동일한 요청으로 처리되고, Redis는 별도의 idempotency 체크 없이 단순히 차감만 수행합니다.Kafka Producer는 중복 메시지를 전송할 수 있고, Kafka Consumer는 별도 방어 로직이 없으면 메시지를 그대로 처리합니다. 해결 방법 : 서비스 계층에서 멱등성 처리서비스 계층에서 중복 요청을 선제적으로 차단하기 위해 아래 로직을 구현했습니다. Redis를 이용.. 2025. 4. 30.
[s-market] Kafka 파티션 키 전략으로 이벤트 순서 보장하기 문제 상황이벤트성 상품은 동시에 수많은 사용자 요청이 몰리며, 같은 상품에 대한 재고 차감 이벤트가 거의 동시에 발생합니다. 이때 순서가 엉키면 다음과 같은 문제가 생깁니다.상품 A에 대해 먼저 주문한 사람보다 나중 주문한 사람의 재고 차감이 먼저 처리됩니다.그 결과, 빠르게 주문한 유저가 실패하고, 느린 유저가 성공하는 역전 현상이 발생할 수 있습니다.이러한 문제를 해결하려면 Kafka 이벤트 처리에서 메시지 순서를 보장해야 합니다. Kafka의 순서 보장 원칙Kafka는 파티션 단위로는 기본적으로 순서를 보장합니다.단위순서 보장 여부전체 토픽보장 안됨파티션 단위보장됨 즉, 파티션 내에서는 FIFO를 보장해줍니다.따라서, 순서 보장을 원하는 경우 같은 파티션에 메시지를 보내야 합니다. 해결 하기아래와.. 2025. 4. 29.
[s-market] Kafka Consumer Redis 복구방식 개선 문제 정의이벤트성 상품 판매 시스템(s-market)에서는 다음 두 가지 문제를 해결해야 합니다. 재고 초과 판매 방지선착순 이벤트에서는 재고 초과가 치명적입니다. (“10개 한정” 상품이 11개 팔려서는 안 됩니다.) Kafka 중복 이벤트 수신Kafka는 at-least-once delivery를 보장하기 때문에, 동일한 메시지가 Consumer에 여러 번 도달할 수 있습니다. 만약 중복 이벤트에 대해 적절한 대응을 하지 않으면 재고를 불필요하게 다시 차감하거나 잘못된 복구 작업으로 재고 데이터가 오염될 수 있습니다. 문제 상황 분석단순한 소비 로직의 한계초기에는 Kafka Consumer에서 StockDeductedEvent를 수신하자마자 DB 차감 시도하고, 이미 처리된 orderId라면 Red.. 2025. 4. 29.
[s-market] Redis 이벤트성 상품 재고 차감 전략 이벤트성 상품의 특징이벤트성 상품(한정판, 선착순 할인 등)은 일반적인 상품과는 다른 특성을 가집니다.재고 정확성이 매우 중요합니다. 예를 들어, “10개 한정”이면 10개 이상 팔려서는 절대 안 됩니다.응답 속도도 매우 중요합니다. 예를 들어, 수만 명이 동시에 접속하는 상황에서 1~2초만 늦어도 구매 실패율, 이탈율이 급격히 올라갑니다.즉, 재고 정확성과 속도 둘 다 포기할 수 없습니다. 재고 차감 처리 방법Redis를 활용한 재고 차감 방식은 Redisson 분산 락, Lua Script, MULTI/EXEC 트랜잭션을 활용한 3가지 방식이 존재합니다.각 방식의 특징은 아래와 같습니다.방법재고 정확성속도특징Redisson 분산 락매우 높음느림Redis 분산 락을 걸고 재고 차감 (TPS 낮음)Red.. 2025. 4. 29.
[s-market] Consumer 재시도 전략 Consumer 재시도시 Exponential Backoff를 적용하면, 장애가 터졌을 때 서버와 DB에 과부하를 방지할 수 있습니다. 사용 이유 장애 발생시, 재시도 폭탄(연속 실패)를 막을 수 있습니다. 예시로, DB가 죽거나 네트워크 끊김으로 인해 장애가 터졌다고 가정을 합니다.이런 상황에 재시도 간격(1초)이 고정이 되는 경우, 아래와 같은 시나리오가 계속 반복됩니다.1초마다 계속 재시도 → 1초 후 실패 해당 시나리오가 장애가 발생한 시스템에 수천, 수만 개의 재시도 요청이 쏟아지게 됩니다.서버나 DB가 다시 살아나려고 해도 과부하 때문에 다시 살아나지 못할 수 있습니다. Exponential Backoff를 사용하는 경우, 초반에는 빠르게 시도하지만, 실패가 반복될수록 간격이 커져서 서버가 버.. 2025. 4. 28.
[s-market] 상품과 재고처리 시나리오 계획 이벤트 상품이벤트 상품은 한정 수량이 있고, 빠른 응답을 요구합니다. 아키텍처Redis → Kafka → Mysql 순으로 진행 목적초고속 재고 차감, 트래픽 폭주 견디기, 데이터 유실 방지 처리 흐름사용자가 구매 요청을 보냅니다.Redis에서 재고를 먼저 차감합니다.성공하는 경우, Kafka에 StockDeductedEvent를 발행합니다.별도 Consumer가 Kafka에서 이벤트를 읽어 DB의 재고를 비동기로 반영합니다.실패하면, Dead Letter Queue로 보내거나 처리합니다. 실패시 사용 전략Kafka Consumer 실패 시 처리 전략 1. Kafka Consumer가 DB 업데이트 도중 실패하면 재고 데이터가 Redis와 DB간 불일치할 수 있습니다. 해결 방향DLT(Dead Lett.. 2025. 4. 28.
[s-market] 프로젝트 구조 s-market 프로젝트 구조에 대해서 소개합니다. 전반적인 프로젝트 구조는 도메인 중심 설계(Domain Driven Design)와 레이어드 아키텍처를 기반으로 구성했습니다.  도메인 중심 설계를 선택한 이유는, 프로젝트 초기부터 비즈니스 중심의 코드 구조를 지향하고, 변화에 유연하게 대응할 수 있는 기반을 마련하기 위해서입니다.핵심 도메인 로직은 domain 계층에 집중시키고, DB 접근, 인증, 메시지 처리 등 기술적인 요소는 infrastructure로 분리하여 관심사의 분리와 계층 간 역할을 명확히 하고자 합니다.또한, 도메인 모델을 VO, Entity, DTO로 구분하고, 비즈니스 유스케이스는 application 계층에서만 다루도록 구성함으로써, 기술 구현과 도메인 로직이 서로 얽히지 않도.. 2025. 3. 31.