Rabbitmq之消費端確認

當消費者從消息隊列中拉取了一條消息,去處理某個業務的時候出現了異常,那這條消息沒有被正確消費的時候我們該怎麼處理呢?

rabbitmq有一個確認機制

首先看一下如果我們不做確認的話是一種什麼情況

public class ConnectionUtil {

	public static String QUEUE_NAME = "testQueue";

	public static String EXCHANGE_NAME = "testExchange";
	public static Connection getConnection() throws Exception{
		ConnectionFactory factory = new ConnectionFactory();

		//設置服務端所在地址
		factory.setHost("127.0.0.1");
		//設置端口號
		factory.setPort(5672);
		//設置用戶名
		factory.setUsername("helloWorld");
		//設置密碼
		factory.setPassword("helloWorld");
		//設置虛擬地址
		factory.setVirtualHost("testHost");

		return factory.newConnection();
	}
}
public class Send {

	public static void main(String[] args) throws Exception{
		//獲取連接
		Connection connection = ConnectionUtil.getConnection();

		Channel channel = connection.createChannel();
		//聲明隊列
		channel.queueDeclare(ConnectionUtil.QUEUE_NAME,false,false,false,null);
		//聲明交換機
		channel.exchangeDeclare(ConnectionUtil.EXCHANGE_NAME,"fanout");
		//交換機和隊列綁定
		channel.queueBind(ConnectionUtil.QUEUE_NAME,ConnectionUtil.EXCHANGE_NAME,"helloWorld");

		channel.basicPublish(ConnectionUtil.EXCHANGE_NAME,"",null,"helloWorld".getBytes());

		System.out.println("發送的信息爲:helloWorld");
		channel.close();
		connection.close();

	}
}
public class Recv {

	public static void main(String[] args) throws Exception{
		Connection connection = ConnectionUtil.getConnection();
		Channel channel = connection.createChannel();
		DefaultConsumer deliverCallback = new DefaultConsumer(channel) {
			@Override
			public void handleDelivery(String consumerTag, Envelope envelope, 
									   AMQP.BasicProperties properties, byte[] body) throws IOException {
				System.out.println(new String(body, "UTF-8"));
			}
		};
         //消費消息,沒有確認
		channel.basicConsume(ConnectionUtil.QUEUE_NAME, deliverCallback);

	}
}

 當發送一條消息的時候,testQueue中有一條消息是ready狀態

然後消費消息的時候,我沒有做確認,消費完這條消息,消息還在這個隊列,只是狀態變成了Unacked

如果消費者不做消息確認的話,在消費端和服務器斷開的時候Unacked狀態的消息又會重回到Ready狀態,

這麼做肯定不行,因爲長時間下來隊列中消息會越來越多,造成消息大量堆積

這裏消息確認有兩種方式

自動確認

自動確認是在消費者一拉去到消息就做了確認,不管消費者有沒有成功消費,來看這個測試

消費者是成功拉去到了消息,但是並沒有正常消費,而消息系統卻刪除了這條消息,顯然是和我們正常業務需求是不相符到

public class Recv {

	public static void main(String[] args) throws Exception{
		Connection connection = ConnectionUtil.getConnection();
		Channel channel = connection.createChannel();
		DefaultConsumer deliverCallback = new DefaultConsumer(channel) {
			@Override
			public void handleDelivery(String consumerTag, Envelope envelope,
									   AMQP.BasicProperties properties, byte[] body) throws IOException {
				System.out.println(1/0);
				System.out.println(new String(body, "UTF-8"));
			}
		};
        //消費消息,並自動確認
		channel.basicConsume(ConnectionUtil.QUEUE_NAME,true, deliverCallback);

	}
}

手動確認

當在確認之前有異常發生,消息沒有被成功消費當時候,隊列中消息的狀態依舊爲Ready狀態,業務上可以在發生異常的時候進行重試幾次

public class Recv {

	public static void main(String[] args) throws Exception{
		Connection connection = ConnectionUtil.getConnection();
		final Channel channel = connection.createChannel();
		DefaultConsumer deliverCallback = new DefaultConsumer(channel) {
			@Override
			public void handleDelivery(String consumerTag, Envelope envelope,
									   AMQP.BasicProperties properties, byte[] body) throws IOException {
				System.out.println(new String(body, "UTF-8"));

				System.out.println(1/0);
				//這裏進行確認,第一個參數爲消息的標識符,第二個參數爲是否批量確認
				channel.basicAck(envelope.getDeliveryTag(),false);
			}
		};
		channel.basicConsume(ConnectionUtil.QUEUE_NAME,false, deliverCallback);

	}
}

當消費者成功消費,手動確認之後

public class Recv {

	public static void main(String[] args) throws Exception{
		Connection connection = ConnectionUtil.getConnection();
		final Channel channel = connection.createChannel();
		DefaultConsumer deliverCallback = new DefaultConsumer(channel) {
			@Override
			public void handleDelivery(String consumerTag, Envelope envelope,
									   AMQP.BasicProperties properties, byte[] body) throws IOException {
				System.out.println(new String(body, "UTF-8"));

				//這裏進行確認,第一個參數爲消息的標識符,第二個參數爲是否批量確認
				channel.basicAck(envelope.getDeliveryTag(),false);
			}
		};
		channel.basicConsume(ConnectionUtil.QUEUE_NAME,false, deliverCallback);

	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章