Skip to content

[RabbitMQ] Message durability(메시지 잃어버리지 않기 : autoAck=false) -1

2012/01/26

Message durability

RabbitMQ 홈페이지의 tutorial 에 따라서 가장 간단한 예제인 Produser -> Queue -> Consumer 를 테스트 해보았다.

테스트 방법

Produser : 1~10000까지 1초에 한번씩 “Hello World”라는 message를 보낸다

Consumer : Queue에 message가 있다면 1개의 message를 화면에 출력하고  3초후에 다음 message를 가져와 화면에 출력하고 없다면 다시 3초를 기다린다

우선 정상적인 상황에서는 Produser에서 1~1000까지 1초에 한번씩 message를 날릴때 해당 Queue를 consuming을 하고 있는 Consumer가 아예 없었다면 Queue에 온전하게 쌓이게 된다.

이를 확인하기 위해서는 rabbitmqctl을 이용하면된며 아래와 같은 결과가 출력된다.

#./rabbitmqctl list_queues
Listing queues ...
 hello   166
...done.

이름이 hello인 queue가 한개 있고 현재 166개의 message가 쌓여 있다는 뜻이며 실제 이때 Produser에서 166개를 보낸 상황이었다.

이때 Consumer가 동작을 시작하면 당연히 0번 message 부터 순차적으로 받게 된다.

하지만 Consumer가 1개의 메시지를 처리 했다고 해도 list_queues 명령어를 통해 queue의 상태를 확인해 보면 아래와 같이 변해있다.

#./rabbitmqctl list_queues
Listing queues ...
 hello   0
...done.

즉, queue에 메시지가 한개도 없게 된다. 그리고 1개만 처리한 상태에서 Consumer를 일부러 죽였더니 나머지 message는 모두 잃어버리게 되었다.

왜 그럴까? 그 이유는 아주 간단했다.

예제에서 다음과 같이 설정하는데..

QueueingConsumer consumer = new QueueingConsumer(channel);
channel.basicConsume(QUEUE_NAME, true, consumer);

basicConsume()에서 두번째 파라미터값인 autoAck=ture로 설정되어 있다.

ture로 되어 있을때는 queue에 message가 들어오면 해당 queue를 바라보고 있는 Consumer에 전달이 되고 이때 Consumer에서 message에 대해 처리 여부(이 테스트에서는 화면에 출력)와 상관없이 자동으로 queue에 받았다는 ack를 리턴하기 때문에 queue에서는 지워지게 된다. 하지만 실제 서비스 상황에서는 위에 테스트 방법 처럼 message가 발생되는 속도 보다 Consumer에서 message를 처리하는 시간이 길어지게 되며 이때 처리하지 못한 message가 queue가 아닌 Consumer에 쌓여 있게되면 Consumer가 갑자기 죽었을때는 message 유실이 생기게 되는 것이다.

그래서 되도록이면 autoAck=false로 바꾸고 message에 대한 처리 완료후 아래의 구문을 추가해서 ack를 명시적으로 보내주는 것이 좋다.

channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);

Tip 1. autoAck=ture 로 하고 다시 명시적으로 basicAck를 호출하면 아래와 같은 에러메시지가 Consumer에서 발생한다.

com.rabbitmq.client.AlreadyClosedException: clean connection shutdown; reason: Attempt to use closed channel
        at com.rabbitmq.client.impl.AMQChannel.ensureIsOpen(AMQChannel.java:190)
        at com.rabbitmq.client.impl.AMQChannel.transmit(AMQChannel.java:291)
        at com.rabbitmq.client.impl.AMQChannel.transmit(AMQChannel.java:285)
        at com.rabbitmq.client.impl.ChannelN.basicAck(ChannelN.java:833)
        at com.kth.nwind.rabbitmq.consumer.Recv.main(Recv.java:69)

Tip 2. autoAck=false로 된 상태에서 Consumer가 처리 완료후 ack를 보내지 못하고 connection이 끊기면 queue는 연결된 다른 Consumer에게 자동으로 그 message를 재전송하고 ack를 기다리며 다른 Consumer가 없다면 timeout 없이 계속 queue에 저장한다. 이후 만약 다시 Consumer가 connection을 맞는 다면 재전송한다.

Tip 3. 재전송되는 message는 랜덤하게 전송된다.

Messages will be redelivered when your client quits (which may look like random redelivery)

Tip 4. ack가 오지 않아 쌓인 message는 다음 명령어를 이용해 확인할 수 있다.

# ./rabbitmqctl list_queues name messages_ready messages_unacknowledged
Listing queues ...
hello2 0 0
...done.
No comments yet

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

%s에 연결하는 중

%d 블로거가 이것을 좋아합니다: