- FeignClient에서 Kafka로의 변환 : 좌석 예매 시스템의 성능 병목 해결기1. 도입 배경: FeignClient 기반 구조의 한계초기 티켓팅 시스템은 서비스 간 통신에 FeignClient를 사용하고 있었습니다.구현이 간편하고 직관적이지만 실서비스 시나리오에서 아래와 같은 문제를 마주했습니다:수백 명이 동시에 좌석을 예매할 때 동기 호출의 병목 현상일부 서비스 실패 시 장애 전파 위험서비스 간 결합도가 높아 확장성 제한이러한 문제들을 해결하기 위해 Kafka 기반의 이벤트 처리 구조로 전환을 결정했습니다. 2. Kafka 기반 구조로의 전환Kafka를 도입하면서 서비스 간 통신을 비동기 이벤트 기반으로 재설계하였고 구조는 다음과 같습니다.1. 공통 이벤트 구조 정의모든 메시지를 공통 구조로..
1. 문제 상황 : 좌석 선점 시스템을 Redis로 구현하다가 발생한 문제들 프로젝트에서 좌석 선점 기능을 Redis를 활용해서 구현하고 있었다. 처음에는 다음과 같은 방식으로 간단하게 설계를 했다.사용자가 좌석을 선점하면 Redis에 seat-hold:{sessionId}:{seatId}라는 키를 생성이 키에 사용자 ID를 저장하고, TTL(Time To Live)을 5분 설정동시에, Redisson을 사용해 좌석 락(lock) 을 걸어 선점 중복을 방지더보기처음 설계했던 흐름-> Redisson 락 획득-> Redis에 userid 저장-> Redis에 5분 TTL 설정-> 락 해제이렇게 구성하면 "5분 내에 결제를 완료하지 못하면 좌석이 자동으로 풀리겠지"라고 단순히 생각했다. 하지만... 2. ..
1. 기존 구현 방식기존의 회차별 좌석 조회는 DB + Redis를 조합해서 조회하는 로직이다. 즉, 특정 sessionId 공연 회차의 모든 좌석을 조회하되, 좌석의 상태는 Redis 값을 우선시해서 보여주는 것이다. //해당 회차별 좌석 목록 조회 @Override public List getSeatBySession(UUID sessionId) { SessionId session = new SessionId(sessionId); //DB에서 특정 sessionId에 해당하는 모든 좌석 가져오기 //상태는 DB의 p_seats 테이블에서 가져온 기본 상태 List seats = seatRepository.findAllBySession..
1. Kafka란?Kafka는 분산 스트리밍 플랫폼으로 주로 실시간 데이터 피드의 빅 데이터 처리를 목적으로 사용된다. 또한 메시지 큐와 유사하지만 대용량 데이터 스트림을 저장하고 실시간으로 분석하거나 처리하는 데 중점을 둔다.쉽게 말하자면 많은 데이터를 빠르고 안정적으로 전송하고 저장하는 중간다리 역할을 함! Kafka는 왜 필요할까?예를 들어 주문 서비스에서 주문을 생성하면 재고 서비스, 배달 서비스, 알림 서비스 등 여러 서비스가 주문 정보를 알고 있어야 하는데 이때, 직접 Order -> Stock, Order -> Delivery, Order -> Notification 이런식으로 REST API로 각각 호출을 하게 되면 서비스 간 결합도는 높아지고 실패에 민감해진다.하지만, kafkaf를 쓰..
1. 문제발생이번에 개발한 기능은 Order-Service에서 주문 생성 시 Stock-Service와 연동하여 재고를 차감하고 이후 Delivery-Service에 배송 생성을 요청하는 전체 흐름이다.이 과정에서 예상치 못한 문제가 발생했다. 분명 Stock-Service에서 hubId, price를 잘 반환하고 있는데도 OrderService에서 해당 값이 null, 0으로 들어가는 버그가 발생한 것이다. 디버깅 로그를 찍어보면 다음과 같았다.INFO OrderService - stockResponse.hubId = nullINFO OrderService - totalPrice = 0 하지만 DB에서는 정상적으로 hubId와 price가 존재하는 것을 확인할 수 있었다. 그럼 대체 문제는 어디에 있었..
대규모 트래픽 분산처리 시스템을 MSA 기반으로 개발하던 중 가장 복잡했던 부분은 주문(Order) 생성 시 여러 서비스(재고/배송) 와의 연동 과정에서 발생하는 트랜잭션 처리였다.현재 개발 중인 물류 시스템은 다음과 같은 구조를 가지고 있다.Order-Service: 주문 생성Stock-Service: 재고 확인 및 차감Delivery-Service: 배송 요청 처리 중요한 점은 이 모든 과정을 하나의 트랜잭션처럼 처리하고 싶지만 마이크로서비스 구조(MSA)에서는 분산 트랜잭션을 하나의 DB 트랜잭션처럼 처리할 수 없다는 점이다. Spring Cloud + OpenFeign을 이용해 Order-Service ↔ Stock-Service ↔ Delivery-Service 로직을 연동하고 실패 시 보상 트..
이번 글은 MSA 프로젝트를 진행하면서 겪었던 JPA 트랜잭션 문제와 해결 과정, 그리고 이를 통해 SAGA 패턴과 락(Optimistic Lock & Pessimistic Lock)의 필요성에 대해 깨달은 내용을 공유하고자 한다. 1. 문제 상황 : MSA에서 JPA 트랜잭션이 예상과 다르게 동작Spring Boot 기반 Order Service를 개발하던 중, 주문 생성 과정에서 다음과 같은 오류가 발생하였다. 💥 💥 발생한 오류 (StaleObjectStateException) 💥 💥org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction이 오류는 JPA에서 save() 실행 시 merg..