RabbitMQ에서 메시지 스키마 진화: Virtual Hosts를 배포 경계로 사용
Source: Dev.to
예시 시나리오
초기 흐름 (v1)
- 백엔드는 결제 시 결제를 동기식으로 승인한다.
- 승인이 성공하면
PaymentAuthorized이벤트를 발행한다.
{
"paymentId": "p-123",
"authorizedAmount": 100.00,
"currency": "EUR"
}
컨슈머는 이 이벤트를 받아 전체 승인 금액을 캡처한다:
capture(authorizedAmount);
진화된 흐름 (v2)
나중에 일부 상품이 재고가 없을 수 있다. 백엔드는 여전히 결제를 승인하지만, 캡처하기 전에 재고를 확인한다. 이제 실제 캡처 금액을 포함하는 PaymentCaptureRequested 이벤트를 발행한다. 이 금액은 승인 금액보다 낮을 수 있다.
{
"paymentId": "p-123",
"authorizedAmount": 100.00,
"captureAmount": 80.00,
"currency": "EUR"
}
컨슈머는 지정된 금액만 캡처해야 한다:
capture(captureAmount);
버전이 동시에 존재할 때의 실패 모드
- 필드 누락: v1 컨슈머가 v2 메시지를 받으면
captureAmount필드를 알 수 없어 처리 오류나 예측 불가능한 동작이 발생한다. - 필드 무시: v1 컨슈머가
captureAmount를 무시하고authorizedAmount를 사용하면 고객이 과다 청구될 수 있다.
근본 원인은 호환되지 않는 메시지 버전을 동시에 처리하는 것이다.
RabbitMQ Virtual Host를 배포 경계로 사용하기
Virtual host(vhost)는 RabbitMQ 브로커 내에서 격리된 네임스페이스를 제공하여 호환되는 프로듀서/컨슈머 쌍 간의 통신을 제한할 수 있다.
1. Spring Boot에서 vhost와 인증 정보를 외부화하기
spring.rabbitmq.virtualHost=${RABBITMQ_VHOST}
spring.rabbitmq.username=${RABBITMQ_USER}
spring.rabbitmq.password=${RABBITMQ_PASSWORD}
2. 파이프라인에서 버전별 vhost, 사용자 및 권한 프로비저닝하기
# 버전 1.0용 vhost 생성
rabbitmqctl add_vhost payments-v1.0
# 전용 사용자 생성
rabbitmqctl add_user payments-v1.0-app YourStrongPassword
# (선택) 사용자 태그 설정
rabbitmqctl set_user_tags payments-v1.0-app
# 새 vhost에 대한 전체 권한 부여
rabbitmqctl set_permissions -p payments-v1.0 \
payments-v1.0-app \
".*" ".*" ".*"
3. 컨테이너 환경 변수로 설정 전달하기
environment:
RABBITMQ_VHOST: ${RABBITMQ_VHOST}
RABBITMQ_USER: ${RABBITMQ_USER}
RABBITMQ_PASSWORD: ${RABBITMQ_PASSWORD}
command: java -jar ...
4. 새 버전 배포하기
- 새로 만든 vhost를 가리키도록 업데이트된 프로듀서와 컨슈머를 배포한다.
- 모든 노드가 정상인지 확인하기 위해 헬스 체크를 실행한다.
- 이전 버전의 메시지가 모두 소비되었는지 검증한다.
5. 성공적인 전환 후 정리 작업
- 오래된 가상 호스트 삭제:
rabbitmqctl delete_vhost payments-v0.x. - 연관된 사용자 삭제:
rabbitmqctl delete_user payments-v0.x-app.
정리 작업을 통해 오래된 배포 경계가 누적되는 것을 방지한다.
추가 자료
- Spring AMQP RabbitAutoConfiguration Reference – Spring AMQP Docs
- Spring AMQP Reference Documentation – Spring AMQP Docs
Cover photo by Ivan N on Unsplash