
RabbitMQ는 작년부터 계속 공부해 왔다.(마지막 포스팅을 보니 작년 8월이더라...)
8월부터 약 7개월간 RabbitMQ를 회사 제품에 녹여내기 위해 열심이었는데, 드디어 2026년 3월. RabbitMQ를 포함한 알림 기능을 배포까지 완료했다.
따라서 회고 겸 RabbitMQ 도입기를 작성해 볼까 한다.
RabbitMQ에 관해 자세한 내용이 궁금하다면 여기를 참고하길: Rabbit MQ

메시지 큐 도입을 고려한 이유는 여기저기 알림 기능이 끼어들며 복잡도가 기하급수적으로 늘어났기 때문이었다. 특히 MSA 아키텍쳐를 차용한 새로운 프로젝트에서는 모든 모듈마다 알림 모듈을 호출하기 위한 코드를 길게 길게 작성해야 했다.
그렇다면 알림이 그렇게 중요한 기능일까? 물론 중요하다. 고객사 입장에서 작업이 완료되었는지 체크하기에 메일, 웹, sms 알림만큼 효과적인 것은 없다. 하지만 주요 기능은 아니다. 고로 중요하지만 부수적인 기능에 불과한 것이다. 그런데 각 알림을 처리하기 위해 들어가는 공수가 생각보다 컸다.
기존 알림 로직이 동기 방식인 것도 문제였다. 예를 들어 A 로직 -> A 메일 발송 -> B 로직 -> B 메일 발송으로 구성된 메서드가 있다고 하자. 메일 발송이 동기 방식이기 때문에 메일 발송에서 오류가 나면 B로직으로 넘어가지 않는 현상이 발생한다.
이 모든 문제점을 해결할 수 있는 방법을 계속 찾고 찾다가 발견한 것이 메시지 큐였다.
그때부터 메시지 큐를 알림에 도입할 것을 염두에 두고 공부하기 시작했다.
1. 비동기 방식을 효율적으로 사용할 수 있고,
2. 알림 호출에서 발생하는 결합도를 낮출 수 있기 때문이었다.
나 홀로 메시지 큐를 사용하기로 결심했다고 해서 무작정 도입할 수는 없었다. 팀에서 충분히 상의를 거치고 모두가 메시지 큐를 공부할 필요가 있었다.
그래서 두 달간 퇴근하면 메시지 큐를 중점적으로 깊게 공부하는 시간을 가졌다. 메시지 큐를 공부하고 공부한 내용을 팀에 공유했다.

그렇게 해서 팀 모두가 메시지 큐를 이해하게 되었느냐 하면, ...사실 모르겠다. ㅎㅎ 나만 열심히 공부한 것 같은.. ... 후술하겠지만 결국 메시지 큐는 나 혼자 개발했기 때문이다. 원래 중소 기업에선 제안한 사람이 그걸 도맡아 해야 하는 법이다.
사실 메시지 큐 관련해서 2025년 하반기에 마감하는 것이 목표였으나, 여러 사건 사고로 인해 메시지 큐 도입이 차일피일 미뤄졌다. 결국 하반기에 메시지 큐를 포함하여 배포하는 건 물 건너 갔다.
대신 올해 초 목표에 반드시 제품에 RabbitMQ를 도입하겠다는 목표를 세웠다. 이 상태로 미루고 미루다가는 절대 제품에 편입하지 못할 것 같았다. On-prem 방식 위주인 우리 회사에서 새로운 툴을 도입하는 건 항상 부담으로 작용했다. 그러잖아도 부담스러운데 개발 일정까지 밀린다? 우선 순위에서 제거되기 너무 쉬웠다. 그때부터 추가 근무를 해서라도 Rabbit MQ에 매달리기 시작했다. 들어오는 일도 쳐내고, RabbitMQ도 열심히 했다.
개발하는 것 자체는 어렵지 않았다. 모든 API 호출을 비동기 방식으로 전환하는 것도 아니고, 알림 모듈 호출만 메시지 큐를 이용한 비동기 방식을 사용하는 것이니만큼 영향 범위가 그리 넓지도 않았다. 이후에는 로깅 처리까지 확대되었으나 ㅎㅎ..
그럼에도 아키텍처 부분에서 여러 시행착오를 겪게 되었다.
앞서 말했듯 기능 구현에선 어려울 게 없었다. 문제는 회사의 환경에 맞춰 RabbitMQ를 적합하게 사용할 수 있게 구성하는 것이었다.
우리 회사는 일부 테스트 서버에서 로컬 개발과 알파 테스트를 진행한다. 테스트 서버에 설치된 자원을 공통으로 둔 상태에서 개발도 하고, 주기적으로 개발자들끼리 돌아가며 다른 사람의 기능도 테스트해 보곤 한다.
여기서 문제가 발생했다. RabbitMQ의 메시지는 라운드 로빈 방식으로 소비되는데, 로컬에서 개발하기 위해 메시지를 날리면 알파 테스트 환경의 큐에서 그 메시지를 날름 주워다 소비하는 상황이 반복된 것이다.

이것 때문에 회사 환경 구성을 바꿔달라고 할 수는 없었다. 해결해야만 기능을 배포할 수 있었다.
처음 GPT에게 물어봤을 때 답변으로 제안한 것은 바로 'Fanout Exchange'와 '익명 큐' 사용하기였다. RabbitMQ는 반드시 메시지를 소비할 큐를 지정해야만 한다. 하지만 모든 큐가 같은 메시지를 소비해야 하는 경우 Fanout Exchange를 사용하면 라우팅 키 구분 없이 모든 바인딩된 큐에 메시지를 복제 전달할 수 있따.
어느 환경이든 큐를 소비할 수 있어야 한다는 생각에 도입해 보았다. 하지만 테스트를 한 이후 적합하지 않다는 사실을 깨닫게 된다.
모듈에서 불필요한 메시지 소비가 발생했다.
예를 들어 로그인하면 SMS 알림이 발송되고, 로그인에 n회 이상 실패하면 비밀번호 찾기 메일이 발송된다고 하자. Fanout Exchange와 익명 큐를 사용하자 로그인을 했을 때도 메일이 발송되려고 하고, 비밀번호 찾기 메일이 발송되어야 할 때도 SMS 알림이 발송된다. 모든 메시지를 소비하려고 하기 때문이었다. 기능 분리가 전혀 안 되는 상황이 발생한다.
라운드 로빈으로 하나의 환경이 소비하는 현상 자체는 유지되었다.
내 의도는 특정 환경에서 발송한 메시지는 해당 환경에서만 소비되게 하는 것이었다. 하지만 사용하는 큐가 같으니, 아무리 익명 큐를 사용해 메시지를 발송해도 결국 라운드 로빈으로 빠르게 낚아 챈 모듈만이 메시지를 소비했다.
문제점은 고치지 못하고 그대로 문제 하나를 더 얹은 셈이었다.
지금 현상의 가장 큰 문제점은 '로컬 개발 환경'의 큐와 '테스트 서버 환경'의 큐가 같기 때문에 발생한 일이다. 그렇다면 큐 이름을 다르게 설정하면 해결할 수 있지 않을까!
실제로 개발 환경과 테스트 서버 환경 큐를 구별하기 시작하자 메시지가 정상적으로 소비되기 시작했다. 예전에는 A라는 이름의 공통된 큐로 발송했다면 지금은 A-DEV 큐와 A-TEST 큐로 나누어 발송했다고 생각하면 이해하기 쉬울 것이다.
다만 테스트를 위한 조치였기 때문에 하드코딩 문제가 남아 있었다. 지금처럼 큐 이름을 하드코딩한 상태로 분기 처리하면 확장성이 떨어질 염려가 있었다.
이미 배포 환경 별로 application.yml을 구별해서 사용하는 중이기에 이걸 활용해 보기로 했다. 해당 yml 파일을 이용해서 서버 별로 다음과 같이 설정해 두었다. (보안을 위해 코드 내용은 일부 변경되었다.)
rabbit:
consumer:
notice:
enabled: true
email-queue-name: dev.notice.email.queue
sms-queue-name: dev.notice.sms.queue
이러자 각 환경에서 시행했을 때 각기 다른 큐를 정상적으로 소비하게 되었다.
기능 구현은 완료되었으니 남는 것은 배포였다. 이때만큼 긴장한 적이 없었다.
다른 팀원들은 각자 본인이 해야 하는 업무가 있어서 RabbitMQ만큼은 나 혼자 붙들었기 때문이다. 즉, 문제가 발생한다면 그 책임은 나에게 있는 것과 마찬가지였다.
데모 버전 서버에 배포한 이후 테스트를 했을 때 제대로 작동하지 않자 눈앞이 깜깜해진 적도 있었다.(원래 다른 서버에서는 다 잘 되던 게 특정 서버에서만 작동하지 않을 때만큼 아찔한 상황이 또 없다.) 다행히 해당 서버 속도가 상당히 느렸기 때문에 출력도 느렸을 뿐 기능은 정상적으로 작동했다.
현재는 배포한 이후 로깅이나 필요한 알림 기능을 천천히 추가하며 RabbitMQ 사용을 확대해 나가고 있다.

하나의 신기술을 붙잡고 도입한 경험은 입사 이래 처음이었다.
다른 기술은 이미 개발된 부분을 내가 리팩토링하거나 구조를 수정하는 것 위주였다. 그렇기에 아예 새로운 것을 도입하기 위한 이번 경험은 나에게 새로운 짜릿함을 선물해 주었다. 심지어 내가 처음부터 끝까지 다듬은 것을 온전한 기능으로 배포까지 했으니!
그 과정에서 '신기술을 도입할 때는 여러가지를 미리 고민해야 한다'는 점도 배웠다. 특히 우리 회사는 On-prem 환경도 지원하기 때문에, 해당 환경에 RabbitMQ를 설치 및 도입하는 것도 충분히 고려해야 했다. 그렇기에 팀장님이 지금까지도 다 기억하지 못할 정도로 정말 많은 질문을 하셨는데 그때마다 '이 기술이 정말 우리 팀/제품에 필요한가?'를 충분히 반추할 기회가 되었다. 예전에는 그저 도전하고 싶어서, 라고 답했다면 이제는 정보를 찾아보고 근거를 기반으로 나의 논리를 펼치는 법도 배웠다.