RabbitMQ에서 메시지가 대기열에서 처리할 수 없는 메시지(소비자가 처리할 수 없는 메시지)가 되면 다른 교환으로 재경로되고, 이를 'dead letter 교환'이라고 합니다. 그런 다음 dead letter 교환은 dead letter 큐로 dead letter를 전달합니다.

Dead Letter Queue 그림 설명

Dead Letter Queue 위 그림은 dead letter 생성부터 처리까지의 전체 과정을 설명합니다.

Dead Letter 생성

다음은 dead letter가 생성되는 조건입니다:

  • 메시지가 소비자에의해 명시적으로 거절될 때 (basic.reject / basic.nack)이며 requeue=false.
  • 메시지의 TTL(생존기간)이 만료될 때.
  • 대기열이 최대 길이에 도달했을 때.

Dead Letter Queue 처리 단계

  1. Dead letter 교환을 정의합니다 (이름에 속지 말고, 그냥 보통의 교환입니다, dead letter 처리에 관한 맥락에서만 그렇게 불립니다).
  2. Dead letter 교환에 바인딩할 큐를 정의합니다 (이 큐를 dead letter 큐라고 하며, 또한 보통의 큐입니다).
  3. Dead letter를 소비하기 위한 dead letter consumer를 정의합니다 (이름에 속지 말고, 이 또한 보통의 consumer입니다).
  4. Dead letter 교환을 지정된 큐에 바인딩합니다 (dead letter를 처리해야 하는 큐를 바인딩해야 합니다).

팁: 원칙에 대한 설명은 위의 그림을 참조하세요. 모든 프로그래밍 언어는 비슷한 방식으로 dead letter 큐를 처리합니다.

Golang에서 Dead Letter Queue 처리

1. Dead Letter 교환 정의

보통의 교환처럼 정의합니다.

// 교환을 선언합니다
err = ch.ExchangeDeclare(
    "tizi365.dead",   // 교환 이름
    "topic", // 교환 종류
    true,     // 지속 가능
    false,
    false,
    false,
    nil,
)

2. Dead Letter 큐 정의

보통의 큐처럼 정의합니다.

    // 큐를 선언합니다
    q, err := ch.QueueDeclare(
        "",    // 큐 이름, 무작위로 생성하려면 비워두세요
        false, // 지속 가능한 큐
        false,
        true,
        false,
        nil,
    )

    // 큐를 dead letter 교환에 바인딩합니다
    err = ch.QueueBind(
        q.Name, // 큐 이름
        "#",     // 라우팅 키, #은 모든 라우팅 키와 일치하며, 모든 dead letter 메시지를 수신함을 의미합니다
        "tizi365.dead", // dead letter 교환 이름
        false,
        nil)

팁: dead letter 큐를 보통의 큐로 취급하세요.

3. Dead Letter Consumer 정의

// consumer를 생성합니다
msgs, err := ch.Consume(
    q.Name, // 앞서 정의한 dead letter 큐 이름을 참조합니다
    "",     // consumer 이름, 제공하지 않으면 무작위로 생성됩니다
    true,   // 메시지 처리의 자동 승인
    false, 
    false, 
    false, 
    nil,
)

// dead letter 큐로부터 메시지를 소비하기 위해 루프를 돌립니다
for d := range msgs {
    log.Printf("Received dead letter message=%s", d.Body)
}

4. Dead Letter 교환을 특정 큐에 바인딩하기

	// 큐 속성
	props := make(map[string]interface{})
	// dead letter 교환을 바인딩합니다
	props["x-dead-letter-exchange"] = "tizi365.dead"
	// 선택 사항: dead letter가 dead letter 교환에 전달될 때 라우팅 키를 설정합니다. 설정하지 않으면 원래 메시지의 라우팅 키를 사용합니다.
	// props["x-dead-letter-routing-key"] = "www.tizi365.com"

	q, err := ch.QueueDeclare(
		"tizi365.demo.hello", // 큐 이름
		true,   // 지속 가능
		false, 
		false, 
		false,   
		props,     // 큐 속성 설정
	)

이렇게 하면 tizi365.demo.hello 큐의 메시지가 dead letter가 되면 tizi365.dead dead letter 교환으로 전달됩니다.