메시지 지속성과 생명주기 관리(Durable, Persistent, TTL, Auto-delete)
RabbitMQ 브로커가 재시작되면 큐에 쌓여 있던 메시지는 전부 사라질까, 아니면 살아남을까?
메시지 지속성과 생명주기 관리
왜 메시지 지속성이 중요한가
RabbitMQ에서 메시지 지속성(Persistence)이란 브로커 재시작이나 장애 상황에서도 메시지가 손실되지 않고 보존되는 것 을 의미합니다.
결제, 예약, 주문 처리와 같이 신뢰성이 중요한 비즈니스에서는 하드웨어 장애, 네트워크 문제, 또는 브로커 재시작으로 인한 메시지 손실이 치명적인 결과를 초래합니다. 따라서 메시지의 중요도에 따라 적절한 지속성 정책을 적용하는 것이 필수적입니다.
**핵심 : 메시지 지속성은 Durable(큐/익스체인지 속성)과 Persistent(메시지 속성) ** 두 가지를 모두 설정해야 완전하게 보장됩니다. 이 둘은 서로 다른 대상에 적용되는 별개의 설정입니다.
Durable vs Persistent — 무엇이 다른가
실무에서 가장 많이 혼동하는 부분이 바로 Durable과 Persistent의 차이입니다. 한 문장으로 정리하면 다음과 같습니다.
- Durable = ** 큐/익스체인지 **의 지속성 (컨테이너가 살아남는가)
- Persistent = ** 메시지 **의 지속성 (내용물이 살아남는가)
Durable (큐/익스체인지 지속성)
Durable 속성이 true인 큐 또는 익스체인지는 ** 브로커가 재시작되어도 사라지지 않습니다.** 기본값은 false이므로, 명시적으로 설정해야 합니다.
익스체인지 생성 시 Durable 설정
/**
* @param exchange 익스체인지 이름
* @param type 익스체인지 타입 ("direct", "fanout", "topic", "headers")
* @param durable true이면 브로커 재시작 시에도 익스체인지가 유지됨
*/
exchangeDeclare(String exchange, String type, boolean durable)
큐 생성 시 Durable 설정
/**
* @param queue 큐 이름
* @param durable true이면 브로커 재시작 시에도 큐가 유지됨
* @param exclusive true이면 해당 커넥션에서만 사용 가능
* @param autoDelete true이면 모든 소비자 연결 해제 시 자동 삭제
* @param arguments 기타 큐 옵션 (TTL 등)
*/
queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
Durable을
true로 설정하면 큐 자체는 보존되지만, 큐 안에 저장된 메시지가 보존되는 것은 아닙니다. 메시지까지 보존하려면 Persistent 설정이 별도로 필요합니다.
Persistent (메시지 지속성)
Persistent 속성이 true인 메시지는 ** 디스크에 저장 **되어 브로커 재시작이나 장애 상황에서도 사라지지 않습니다. 기본값은 false(메모리에만 저장)입니다.
메시지 발행 시 Persistent 설정
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.MessageProperties;
// 방법 1: Builder 패턴
AMQP.BasicProperties props = new AMQP.BasicProperties.Builder()
.deliveryMode(MessageProperties.PERSISTENT_TEXT_PLAIN.getDeliveryMode()) // deliveryMode=2
.build();
channel.basicPublish("my_exchange", "my_routing_key", props, "Hello, RabbitMQ!".getBytes("UTF-8"));
// 방법 2: 미리 정의된 상수 사용
channel.basicPublish("", "task_queue",
MessageProperties.PERSISTENT_TEXT_PLAIN, // Persistent 속성 적용
message.getBytes("UTF-8")
);
AMQP.BasicProperties에null을 전달하면 메시지는 기본적으로 비지속성(deliveryMode=1)으로 처리되어 ** 메모리에만 저장 **됩니다.
Durable과 Persistent 조합 가이드
| Durable (큐) | Persistent (메시지) | 브로커 재시작 시 동작 | 적합한 시나리오 |
|---|---|---|---|
true | true | 큐와 메시지 모두 디스크에 보존 (가장 안전) | 결제, 주문 등 신뢰성 필수 |
true | false | 큐는 유지되나 메시지는 유실 | 큐 구조는 유지하되 메시지 손실 허용 |
false | true | 큐 자체가 사라지므로 메시지도 함께 유실 | (비권장) 실질적 효과 없음 |
false | false | 큐와 메시지 모두 유실 | 임시 데이터, 캐시성 메시지 |
** 정리 **: 메시지의 신뢰성을 보장하려면 Durable과 Persistent를 모두
true로 설정 해야 합니다. 한쪽만true여도 장애 상황에서 메시지가 유실될 수 있습니다.
설정 결정 흐름
메시지 손실이 허용되는가?
├─ Yes → Durable=false, Persistent=false (최고 성능)
└─ No → 메시지가 반드시 보존되어야 하는가?
├─ Yes → Durable=true, Persistent=true (최고 안전성)
└─ 큐 구조만 유지하면 됨 → Durable=true, Persistent=false
TTL (Time To Live)
TTL은 메시지 또는 큐에 저장된 데이터의 유효 기간을 제한 하는 기능입니다. 만료된 메시지는 자동으로 삭제되며, DLX가 설정되어 있으면 Dead Letter Queue로 이동합니다.
큐 TTL vs 메시지 TTL
| 비교 항목 | 큐 TTL | 메시지 TTL |
|---|---|---|
| 설정 위치 | 큐 선언 시 x-message-ttl 인자 | 메시지 발행 시 expiration 속성 |
| ** 적용 범위** | 해당 큐에 들어오는 ** 모든 메시지** | ** 개별 메시지** |
| ** 유연성** | 일괄 적용 (큐 단위) | 메시지별 개별 설정 가능 |
| ** 활용 예** | 로그 큐에 1시간 TTL 일괄 적용 | VIP 메시지는 24시간, 일반은 1시간 |
큐 TTL 설정 코드
Map<String, Object> args = new HashMap<>();
args.put("x-message-ttl", 30000); // 30초 (밀리초 단위)
channel.queueDeclare(
"my_queue", // 큐 이름
true, // durable
false, // exclusive
false, // autoDelete
args // arguments (TTL 포함)
);
메시지 TTL 설정 코드
AMQP.BasicProperties props = new AMQP.BasicProperties.Builder()
.deliveryMode(MessageProperties.PERSISTENT_TEXT_PLAIN.getDeliveryMode())
.expiration("10000") // 10초 후 자동 삭제 (문자열로 지정)
.build();
channel.basicPublish("", "task_queue", props, "Hello, RabbitMQ!".getBytes("UTF-8"));
큐 TTL과 메시지 TTL을 동시에 설정한 경우
두 TTL 중 ** 더 짧은 값이 우선 적용 **됩니다.
| 큐 TTL | 메시지 TTL | 적용되는 TTL |
|---|---|---|
| 30초 | 10초 | 10초 (메시지 TTL이 더 짧음) |
| 10초 | 30초 | 10초 (큐 TTL이 더 짧음) |
| 미설정 | 10초 | 10초 (메시지 TTL만 적용) |
| 30초 | 미설정 | 30초 (큐 TTL만 적용) |
따라서 메시지 TTL을 활용하려면 큐 TTL을 메시지 TTL보다 길게 설정하는 것이 좋습니다.
Auto-delete (자동 삭제)
Auto-delete는 ** 큐나 익스체인지가 더 이상 사용되지 않을 때 자동으로 삭제되는 기능 **입니다.
| 대상 | 삭제 조건 |
|---|---|
큐 (autoDelete=true) | 연결된 ** 모든 소비자가 연결을 해제 **했을 때 자동 삭제 |
익스체인지 (autoDelete=true) | 바인딩된 ** 모든 큐가 해제 **되었을 때 자동 삭제 |
** 주의 **: Auto-delete는 임시 큐나 익스체인지에 적합합니다. 중요한 데이터를 처리하는 큐에는
autoDelete=false로 설정하여 예기치 않은 삭제를 방지해야 합니다.
요약
| 속성 | 적용 대상 | 역할 | 기본값 |
|---|---|---|---|
| Durable | 큐, 익스체인지 | 브로커 재시작 시 구조 보존 | false |
| Persistent | 메시지 | 브로커 재시작 시 메시지 보존 | false |
| TTL | 큐 또는 메시지 | 유효 기간 초과 시 자동 삭제 | 무제한 |
| Auto-delete | 큐, 익스체인지 | 사용자 없을 때 자동 삭제 | false |
주의할 점
Durable만 설정하고 Persistent를 빠뜨리는 실수
가장 흔한 실수입니다. 큐를 Durable로 만들어 놓고, 메시지 발행 시 Persistent를 설정하지 않으면 브로커 재시작 후 큐는 남아 있지만 메시지는 전부 사라집니다. 두 설정은 각각 다른 대상(큐 vs 메시지)에 적용되는 별개의 옵션이라는 점을 반드시 기억해야 합니다.
Auto-delete 큐에 중요 데이터를 넣으면 안 된다
Auto-delete가 켜진 큐는 마지막 소비자가 연결을 끊는 순간 자동으로 삭제됩니다. 소비자를 재시작하는 짧은 순간에도 큐 자체가 사라질 수 있으므로, 결제나 주문 같은 중요 데이터에는 절대 사용하면 안 됩니다.
신뢰성이 중요한 시스템에서는 Durable=true + Persistent=true 를 기본으로 설정하고, TTL과 Auto-delete는 비즈니스 요구사항에 맞게 선택적으로 적용하는 것을 권장합니다.