개발자
안녕하세요. 현재 백엔드 개발자를 지망하는 대학생입니다.. 예전에 Springboot를 활용해서 개발한 채팅 애플리케이션 프로젝트를 리팩토링하는 과정에서 문제가 발생하여 질문 드립니다. 아래와 같은 아키텍처 애플리케이션을 구현했습니다. - MySQL: 채팅방 정보(채팅방 이름, 참여 인원수 등등), 사용방 정보 데이터 저장. - Redis: 채팅 메시지 데이터 저장 - RabbitMQ: 채팅 메시지를 전송하기 위한 메시지 브로커 STOMP over WebSocket을 활용해서 클라이언트에서 메시지를 pub해서 메시지 브로커인 RabbitMQ를 거쳐서 구독한 클라이언트에게 메시지(채팅)을 전송하도록 구현했습니다. 그런데 문제가 발생하는 로직이 있습니다. [채팅방 가입 로직] 1. @Transactional 내부에서 MySQL에 채팅방 데이터 저장. (해당 유저가 채팅방에 가입한 것을 저장) 2. Redis에 "User가 채팅방에 들어왔습니다."라는 메세지를 저장. 3. 해당 메시지를 RabbitMQ로 전송. (`rabbitTemplate.convertAndSend(...)`) 이런 상황에서 Redis나 RabbitMQ에서 문제가 발생해서 하나라도 정상적으로 완료되지 않으면 문제가 발생합니다. Redis 서버에 문제가 생겨서 채팅 메시지를 정상적으로 저장하지 않더라도 RabbitMQ를 통해 메시지가 전송되고, RabbitMQ 서버에 문제가 생겨서 정상적으로 전송되지 않더라도 Redis에 채팅 메시지가 저장이 됩니다. 이러한 문제를 해결하기 위해서 2PC, SAGA 패턴, Outbox 패턴 등등을 알아봤고, 그 중 가장 괜찮다고 생각했던 패턴이 Outbox 패턴이었습니다. 근데 또 어려움이 생겼는데, Outbox 패턴을 사용하기 위해 Pulling 기법을 사용 하자니 Redis에 무리가 생길 것 같고, 트랜잭션 로그 테일링 패턴을 사용 하기에는 Redis가 이를 제대로 지원하지 않아 구현이 굉장히 어려워진다는 문제가 생겼습니다. 그래서 MySQL을 Outbox 저장소로 사용할까 고민도 해보았는데, MySQL을 사용하면 속도 면에 불리해지지 않을까라는 생각이 또 들었습니다. 이러한 문제를 어떻게 해결하면 좋을까요...? 제가 궁금한점은 다음과 같습니다. 1. Redis를 활용하는 프로젝트에서 MySQL을 Outbox 저장소로 사용하는 것은 좋지 않은 방법일까요? 2. Outbox 패턴이 최선일까요? 현업에서는 이러한 문제를 어떤 식으로 해결하는지 궁금합니다.
답변 1
안녕하세요. 슈퍼코딩에서 커리큘럼을 설계하고 있는 CL입니다. 이 질문을 보면서 ‘진짜 개발자다운 고민’을 하고 계시다는 생각이 먼저 들었습니다. 단순히 기술을 쓰는 것이 아니라, 데이터 정합성과 메시지 일관성까지 고려하고 있다는 점에서 이미 한 단계 높은 수준에 도달하신 것 같습니다. 질문 주신 내용을 기준으로, 아래와 같이 정리해보겠습니다. --- 1. Redis를 활용하는 프로젝트에서 MySQL을 Outbox 저장소로 사용하는 것은 적절한가? 결론부터 말씀드리면, 적절합니다. Outbox 패턴에서 가장 중요한 건 ‘트랜잭션 일관성이 보장되는 저장소’이며, 그 역할을 MySQL이 가장 안정적으로 수행할 수 있습니다. Redis는 트랜잭션 처리나 로그 테일링, 이벤트 드리븐 아키텍처에 필요한 durability 측면에서 지속적인 저장소로 사용되기보다는 속도와 휘발성을 감안한 캐싱 or pub/sub 용도에 가깝습니다. 따라서 메시지를 영속화할 Outbox 저장소로는 MySQL이 현실적인 선택이며, 현업에서도 Redis 기반 프로젝트에서 Outbox 패턴을 구현할 때는 MySQL(or Kafka log DB)을 주로 사용합니다. --- 2. Outbox 패턴이 최선일까요? 현업에서는 이런 문제를 어떻게 해결하나요? 현업에서도 질문자님과 유사한 고민이 반복됩니다. 대부분의 구조는 다음과 같은 방향으로 정리됩니다. [Option A] MySQL 기반 Outbox + Polling Publisher - 채팅 메시지 저장과 동시에 Outbox 테이블에 메시지 저장 - 별도의 Publisher가 일정 주기마다 메시지 읽고 MQ로 전송 - 전송 성공 시 Outbox 상태 `PROCESSED`로 변경 장점: 트랜잭션 보장, 복구 쉬움 단점: 실시간성 다소 떨어짐 (10ms~수초 단위 polling) [Option B] Kafka 기반 로그 테일링 - Debezium 등의 CDC 툴로 MySQL binlog 감지 → MQ 전송 - 비동기 기반의 고성능 처리 가능 단점: Kafka, Debezium 등의 운영 복잡성, Redis에는 적용 어려움 [Option C] Redis Stream 기반 Outbox (실험적) - Redis의 stream 구조를 Outbox queue처럼 사용하는 방식 - 다만 durability 측면에서 안정성 확보가 까다롭고 일반적이지는 않음 --- 정리 드리면 - 현업에서도 MySQL + Outbox 방식은 널리 사용되고 있으며, Redis를 Outbox로 쓰는 경우는 드뭅니다. - 메시징과 저장 간의 트랜잭션 문제를 완전히 해결하려면 DB와 MQ 간의 분리 자체를 줄이는 설계가 핵심입니다. - 처음부터 완벽한 구조보다는, 현재 아키텍처에서 리스크를 컨트롤할 수 있는 구조부터 구현하는 것이 우선입니다. --- 지금 이 고민을 하시는 것 자체가 이미 좋은 개발자로 성장하고 있다는 증거입니다. 이 구조에 대한 기술적 선택뿐만 아니라, "왜 이 구조를 선택했고, 어떤 대안을 고민했는가"를 설명할 수 있다면 그 자체로 포트폴리오에서 매우 강한 인상을 남길 수 있습니다. 응원합니다. 읽어주셔서 감사합니다. — CL@Supercoding Curriculum Lead @Supercoding | Helping You Navigate Career Shifts
익명
작성자
4월 23일
좋은 답변 감사합니다..! 인터넷에서도 이 고민에 대한 해결책을 찾기 어려웠는데, 좋은 답변 남겨주셔서 올바른 방향으로 생각해볼 수 있을 것 같습니다!!
지금 가입하면 모든 질문의 답변을 볼 수 있어요!
현직자들의 명쾌한 답변을 얻을 수 있어요.
이미 회원이신가요?
지금 가입하면 모든 질문의 답변을 볼 수 있어요!