Rabbitmq之發送端事務和確認

官網說明

爲什麼存在確認機制

根據官網翻譯過來:

根據定義,使用消息傳遞代理(如rabbitmq)的系統是分佈式的。由於發送的協議方法(消息)不能保證到達對等方或被對等方成功地處理,因此發佈者和消費者都需要一種傳遞和處理確認的機制。rabbitmq支持的幾個消息傳遞協議提供了這樣的特性。

它們對於從發佈服務器到rabbitmq節點以及從rabbitmq節點到消費者的可靠交付都是必不可少的。換言之,它們對於數據安全至關重要,應用程序和rabbitmq節點一樣負責數據安全。


發送端確認和失敗回調

要確保生產者生產的消息成功到達隊列,有兩個步驟,生產者到交換機,交換機到隊列

發送端確認是要確保生產者生產的消息成功到達交換機

失敗回掉是消息從交換機成功路由到隊列


保證消息成功到達交換機有兩種方式

1.通過AMOP提供的事務機制

保證消息不會丟失的唯一方法是使用事務——使通道具有事務性,然後對每個消息或消息集發佈、提交。在這種情況下,事務是不必要的重量級,並將吞吐量減少250倍。爲了補救這一點,引入了確認機制。它模擬了協議中已經存在的使用者確認機制。

配置類需要開啓聲明式事務,RabbitTemplate設置開啓事務,AMOP事務不能和確認機制同時存在

RabbitTemplate的使用案例(同步),由調用者提供外部事務,在模板中配置了channe-transacted=true。通常是首選,因爲它是非侵入性的(低耦合)

@Configuration
@EnableTransactionManagement
public class RabbitmqConfig {

	@Bean
	public RabbitTransactionManager rabbitTransactionManager(ConnectionFactory connectionFactory){
		RabbitTransactionManager rabbitTransactionManager = new RabbitTransactionManager(connectionFactory);
		return rabbitTransactionManager;
	}

	@Bean
	public ConnectionFactory connectionFactory(){
		CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
		//ip
		connectionFactory.setHost("127.0.0.1");
		connectionFactory.setPort(5672);
		connectionFactory.setUsername("helloWorld");
		connectionFactory.setPassword("helloWorld");
		connectionFactory.setVirtualHost("testHost");

		return connectionFactory;
	}

	@Bean
	public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){
		RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
		//開啓事務
		rabbitTemplate.setChannelTransacted(true);

		
		return rabbitTemplate;
	}

	@Bean
	public DirectExchange  defaultExchange() {
		return new DirectExchange("directExchange");
	}

	@Bean
	public Queue queue() {
		//名字  是否持久化

		return new Queue("testQueue", false);
	}

	@Bean
	public Binding binding() {
		//綁定一個隊列  to: 綁定到哪個交換機上面 with:綁定的路由建(routingKey)
		return BindingBuilder.bind(queue()).to(defaultExchange()).with("direct.key");
	}

}
@Component
public class MessageSender {

	@Autowired
	RabbitTemplate rabbitTemplate;

	@Transactional
	public void send(){

		CorrelationData correlationData = new CorrelationData("訂單ID");
		rabbitTemplate.convertAndSend("directExchange","direct.key","hello",correlationData);
		System.out.println(1/0);
	}
}

 事務開啓的時候,同一個事務中有異常消息不會發送到消息隊列

去掉@Transactionl或者不設置rabbitTemplate中的事務,消息會發送到隊列

 

但是事務的方式官網上不推薦,太影響性能了 

2.開啓確認模式

若要啓用“確認”,客戶端將發送confirm.select方法。根據是否設置了等待,代理可以用確認。一旦在通道使用confirm.select方法,就稱其爲confirm模式。事務通道不能置於確認模式,並且一旦通道處於確認模式,就不能使其成爲事務通道。

@Configuration
public class RabbitmqConfig {


	@Bean
	public ConnectionFactory connectionFactory(){
		CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
		//ip
		connectionFactory.setHost("127.0.0.1");
		connectionFactory.setPort(5672);
		connectionFactory.setUsername("helloWorld");
		connectionFactory.setPassword("helloWorld");
		connectionFactory.setVirtualHost("testHost");

		//發送方確認
		connectionFactory.setPublisherConfirms(true);

		connectionFactory.setPublisherReturns(true);
		return connectionFactory;
	}

	@Bean
	public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){
		RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
		rabbitTemplate.setMandatory(true);

		//確認回調
		rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
			@Override
			public void confirm(CorrelationData correlationData, boolean b, String s) {
				System.out.println(b);
				System.out.println(s);
				System.out.println(correlationData);
			}
		});

        
        //失敗回調
		rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
			@Override
			public void returnedMessage(Message message, int i, String s, String s1, String s2) {
                System.out.println(message);
				System.out.println(s);
				System.out.println(s1);
				System.out.println(s2);
			}
			}
		});



		return rabbitTemplate;
	}

	@Bean
	public DirectExchange  defaultExchange() {
		return new DirectExchange("directExchange");
	}

	@Bean
	public Queue queue() {
		//名字  是否持久化

		return new Queue("testQueue", false);
	}

	@Bean
	public Binding binding() {
		//綁定一個隊列  to: 綁定到哪個交換機上面 with:綁定的路由建(routingKey)
		return BindingBuilder.bind(queue()).to(defaultExchange()).with("direct.key");
	}

}
@Component
public class MessageSender {

	@Autowired
	RabbitTemplate rabbitTemplate;

	public void send(){

		CorrelationData correlationData = new CorrelationData("訂單ID");
		rabbitTemplate.convertAndSend("directExchange","direct.key","hello",correlationData);
	}
}

生產者發送消息後如果消息到達exchange,就會回調confirm方法,ack爲true

如果消息沒有到達exchange,就會回調confirm方法,ack爲false

exchange路由到queue成功就不會回調return方法

exchange路由到queue不成功就會回調return方法

 

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