Todak-Todag

[Troubleshooting] RabbitMQ 비동기 이벤트 구간의 Trace 단절 개선

HS0601 2026. 9. 20. 20:23

문제 정의

Schedule Service에서 CarePlanCompleted 이벤트를 발행하고 CarePlan Service가 이를 소비하는 흐름을 Zipkin으로 추적하던 중, 두 서비스가 하나의 Trace로 연결되지 않는 문제를 발견했다.

Schedule Outbox Relay
        ↓
RabbitMQ
        ↓
CarePlan Consumer

이벤트 전달과 비즈니스 처리는 정상적으로 완료됐지만 Schedule에는 traceId가 존재하는 반면 CarePlan Listener에서는 traceId/spanId가 존재하지 않았고, 이후 CarePlan 작업에서 새로운 Trace가 생성되고 있었다.

이 때문에 이벤트 처리 지연이 발생해도 Schedule 처리, RabbitMQ 전달, CarePlan Consumer 중 어느 구간에서 시간이 소요됐는지 하나의 흐름으로 추적하기 어려웠다.

원인 분석

RabbitMQ 설정을 확인한 결과 RabbitTemplate과 SimpleRabbitListenerContainerFactory는 Spring Boot Auto Configuration을 사용하고 있었지만, Producer와 Consumer의 Micrometer Observation이 활성화되어 있지 않았다.

따라서 RabbitMQ 메시지 자체는 정상 전달되었지만, 서비스 간 Trace Context가 메시징 경계를 넘어 전달되지 않았다.

Feign 호출 역시 초기에는 별도의 Client Span이 보이지 않아 feign-micrometer를 추가해 CarePlan → Schedule 내부 HTTP 호출까지 관측 범위를 확장했다.

해결 방안

검토한 방법은 다음과 같았다.

 

방안 장점  트레이드오프
로그에 traceId 직접 전달 구현 방식이 단순함 Span 관계와 전파 규칙을 직접 관리해야 함
RabbitMQ Header 직접 구성 세밀한 제어 가능 추적 표준을 직접 구현하고 유지해야 함
Listener Factory 직접 구성 세부 설정 가능 기존 Auto Configuration을 재구성해야 함
Micrometer Observation 활성화 기존 Spring Boot 구성을 유지하면서 표준 Trace 전파 가능 관측 데이터 생성에 따른 소량의 오버헤드

 

기존 Auto Configuration을 유지하면서 RabbitMQ Producer/Consumer의 Observation을 활성화하는 방법을 선택했다.

# Schedule
spring:
  rabbitmq:
    template:
      observation-enabled: true
# CarePlan
spring:
  rabbitmq:
    listener:
      simple:
        observation-enabled: true

성과

개선 후 Schedule과 CarePlan Listener에서 동일한 traceId가 유지되었고, Zipkin에서 두 서비스를 하나의 Trace로 확인할 수 있었다.

또한 Services 2, Spans 3으로 연결되면서 다음과 같이 구간별 처리 시간을 분리해 확인할 수 있었다.

 

구간  처리 시간
Schedule Outbox Relay 약 3.16s
RabbitMQ Publish 약 13.19ms
CarePlan Consumer 약 204.94ms

이를 통해 이벤트 처리 전체 시간을 보는 수준에서 벗어나 서비스 간 지연 발생 위치를 Span 단위로 추적할 수 있는 관측 환경을 구축했다.