学习RabbitMQ(三):AMQP事务机制
本文转自:http://m.blog.csdn.net/article/details?id=54315940
在使用RabbitMQ的时候,我们可以通过消息持久化操作来解决因为服务器的异常奔溃导致的消息丢失,除此之外我们还会遇到一个问题,当消息的发布者在将消息发送出去之后,消息到底有没有正确到达broker代理服务器呢?如果不进行特殊配置的话,默认情况下发布操作是不会返回任何信息给生产者的,也就是默认情况下我们的生产者是不知道消息有没有正确到达broker的,如果在消息到达broker之前已经丢失的话,持久化操作也解决不了这个问题,因为消息根本就没到达代理服务器,你怎么进行持久化,那么这个问题该怎么解决呢?
RabbitMQ为我们提供了两种方式:
方式一:通过AMQP事务机制实现,这也是从AMQP协议层面提供的解决方案;
方式二:通过将channel设置成confirm模式来实现;
这篇博客我们讲解AMQP事务机制,下一篇再探讨channel的confirm模式
首先,我们通过实例来看看AMQP的事务模式是怎么使用的:
RabbitMQ中与事务机制有关的方法有三个,分别是Channel里面的txSelect(),txCommit()以及txRollback(),txSelect用于将当前Channel设置成是transaction模式,txCommit用于提交事务,txRollback用于回滚事务,在通过txSelect开启事务之后,我们便可以发布消息给broker代理服务器了,如果txCommit提交成功了,则消息一定是到达broker了,如果在txCommit执行之前broker异常奔溃或者由于其他原因抛出异常,这个时候我们便可以捕获异常通过txRollback回滚事务了;
具体实例:
public class ProducerTest {
public static void main(String[] args) {
String exchangeName = "confirmExchange";
String queueName = "confirmQueue";
String routingKey = "confirmRoutingKey";
String bindingKey = "confirmRoutingKey";
int count = 3; ConnectionFactory factory = new ConnectionFactory();
factory.setHost("172.16.151.74");
factory.setUsername("test");
factory.setPassword("test");
factory.setPort(5672); //创建生产者
Sender producer = new Sender(factory, count, exchangeName, queueName,routingKey,bindingKey);
producer.run();
}
} class Sender
{
private ConnectionFactory factory;
private int count;
private String exchangeName;
private String queueName;
private String routingKey;
private String bindingKey; public Sender(ConnectionFactory factory,int count,String exchangeName,String queueName,String routingKey,String bindingKey) {
this.factory = factory;
this.count = count;
this.exchangeName = exchangeName;
this.queueName = queueName;
this.routingKey = routingKey;
this.bindingKey = bindingKey;
} public void run() {
Channel channel = null;
try {
Connection connection = factory.newConnection();
channel = connection.createChannel();
//创建exchange
channel.exchangeDeclare(exchangeName, "direct", true, false, null);
//创建队列
channel.queueDeclare(queueName, true, false, false, null);
//绑定exchange和queue
channel.queueBind(queueName, exchangeName, bindingKey);
//发送持久化消息
for(int i = 0;i < count;i++)
{
//第一个参数是exchangeName(默认情况下代理服务器端是存在一个""名字的exchange的,
//因此如果不创建exchange的话我们可以直接将该参数设置成"",如果创建了exchange的话
//我们需要将该参数设置成创建的exchange的名字),第二个参数是路由键
//开启事务
channel.txSelect();
channel.basicPublish(exchangeName, routingKey, true, MessageProperties.PERSISTENT_BASIC, ("第"+(i+1)+"条消息").getBytes());
if(i == 1)
{
int result = 1/0;
}
//提交事务
channel.txCommit();
}
} catch (Exception e) {
try {
//回滚操作
channel.txRollback();
} catch (IOException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}
}
}
在第57行通过channel.txSelect方法开启事务,第64行通过channel.txCommit提交事务,为了模拟broker代理服务器异常奔溃或者发布过程中抛出异常,我们通过第61行除以0的操作来模拟(实际中第58行的basicPublish方法是有可能会抛出IOException异常),在捕获到异常之后,第69行调用了channel.txRollback进行事务回滚操作,运行整个程序你会发现在"confirmQueue"这个队列中只存储了一条消息,因为在59行i等于1的时候,抛出了异常,调用了第69行进行了事务回滚操作;在实际应用中,可以在回滚操作之后进行消息重发操作;
我们来通过抓包看看程序执行过程中发出了哪些请求:
1:第一条消息调用channel.txSelect开启事务
2:第一条消息调用channel.txCommit提交事务
3:第二条消息调用channel.txSelect开启事务
4:因为除以0的操作程序抛出异常,执行catch语句中的channel.txRollback回滚事务
从上面的分析中,我们知道使用事务确实能够解决发布者与broker代理服务器之间的消息确认,只有消息成功被broker接收事务提交才能成功,否则我们便可以在捕获异常进行事务回滚操作同时进行消息重发,但是使用事务机制的话会降低RabbitMQ的性能,就拿上面的程序发送1000条消息,使用事务的话需要58244毫秒,而不使用事务的话仅仅需要89毫秒,因此在实际中使用事务会带来很大的性能损失,那么有没有更好的方法既能保证发布者知道消息已经正确到达,又能基本上不带来性能上的损失呢?从AMQP协议的层面看是没有更好的方法的,但是RabbitMQ提供了一个更好的方案,即将channel信道设置成confirm模式,关于confirm的注意点将在下一篇博客介绍;
学习RabbitMQ(三):AMQP事务机制的更多相关文章
- Flink学习(三)状态机制于容错机制,State与CheckPoint
摘自Apache官网 一.State的基本概念 什么叫State?搜了一把叫做状态机制.可以用作以下用途.为了保证 at least once, exactly once,Flink引入了State和 ...
- RabbitMQ AMQP 事务机制
1,在之前的文章中介绍了RabbitMQ的五种队列形式 其中,在工作队列中,为了保证消费者的公平性,采用了channel.basicQos(1),保证了每次只发一条消息给消费者消费,并且使用手动签收的 ...
- MySQL 学习(三)事务学习
事务隔离级别 SQL标准的事务隔离级别包括:读未提交(read uncommitted).读提交(read committed).可重复读(repeatable read)和串行化(seria ...
- RabbitMQ 之消息确认机制(事务+Confirm)
概述 在 Rabbitmq 中我们可以通过持久化来解决因为服务器异常而导致丢失的问题,除此之外我们还会遇到一个问题:生产者将消息发送出去之后,消息到底有没有正确到达 Rabbit 服务器呢?如果不错得 ...
- Kafka设计解析(八)Exactly Once语义与事务机制原理
转载自 技术世界,原文链接 Kafka设计解析(八)- Exactly Once语义与事务机制原理 本文介绍了Kafka实现事务性的几个阶段——正好一次语义与原子操作.之后详细分析了Kafka事务机制 ...
- AMQP学习 & RabbitMQ 与 ActiveMQ、ZeroMQ以及Kafka的比较
之前写了一篇文章关于Active以及消息队列推拉模式的文章,可以参考:link 关于 Active 与 RabbitMQ以及其他的比较,有如下记录: 这篇文章 link 提到: 基本介绍RabbitM ...
- RabbitMQ(四): rabbitmq 的消息确认机制(事务+confirm)
在 rabbitmq 中我们可以通过持久化数据解决 rabbitmq 服务器异常的数据丢失问题. 问题:生产者将消息发送出去之后,消息到底有没有到达 rabbitmq 服务器.默认情况下是不知道的. ...
- Redis学习笔记~Redis事务机制与Lind.DDD.Repositories.Redis事务机制的实现
回到目录 Redis本身支持事务,这就是SQL数据库有Transaction一样,而Redis的驱动也支持事务,这在ServiceStack.Redis就有所体现,它也是目前最受业界认可的Redis ...
- RabbitMQ学习系列三-C#代码接收处理消息
RabbitMQ学习系列三:.net 环境下 C#代码订阅 RabbitMQ 消息并处理 http://www.80iter.com/blog/1438251320680361 http://www. ...
随机推荐
- [转]使用jenkins实现持续集成
本文转自:https://www.cnblogs.com/zishengY/p/7170656.html 一.jenkins 介绍 它是一个自动化的周期性的集成测试过程,从检出代码.编译构建.运行测试 ...
- Android Studio 使用Intent
1.显式Intent Intent intent=new Intent(yzj.this,MainActivity.class);//当前活动的实例,要去的实例 startActivity(inten ...
- spring_03ApplicationContext三种经常用到的实现
1.ClassPathXmlApplicationContext从类路径加载 ApplicationContext ac=new ClassPathXmlApplicationContext(&quo ...
- IDEA插件(Android Studio插件)开发示例代码及bug解决
IDEA插件(Android Studio插件)开发示例代码及bug解决 代码在actionPerformed方法中,有个AnActionEvent e 插件开发就是要求我们复写上述的这个方法即可,在 ...
- 【Spring】27、JPA 实现乐观锁@Version注解的使用
持久层使用jpa时,默认提供了一个注解@Version来实现乐观锁 简单来说就是用一个version字段来充当乐观锁的作用.先来设计实体类 /** * Created by xujingfeng on ...
- SQL多表联合查询(交叉连接,内连接,外连接)
连接查询: 交叉连接: 交叉连接返回的结果是被连接的两个表中所有数据行的笛卡尔积,也就是返回第一个表中符合查询条件的数据航数乘以第二个表中符合,查询条件的数据行数,例如department ...
- Aurelia 创建模板
今天介绍一下Aurelia创建模板的三种方式. 模板既可以作为页面也可以作为组件. 1. View+View Model Aurelia的模板通常由一个html文件和一个同名的ts或js文件组成,文件 ...
- jquery中each中使用break和continue
在jquery中each中直接使用break或者continue会提示:必须在循环中使用.会报错不能直接使用. 但是,是不是就不能用呢,答案是的,但是换种方法可以达到相同的效果: 可以只用return ...
- Socket编程(网络编程)
网络通信的第一要素:IP地址 通过IP地址唯一的定位到互联网的主机 通过 IP+port(端口号) 来确定互联网的主机上的某个软件 InetAddress:位于java.net包下 getHostNa ...
- 转载------35岁开始转变的观念(干了这碗鸡汤再写代码保证没有bug)
作为一个标准的IT男,从一开始的一线开发,做到管理层,又因为喜爱开发,跳槽继续专注coding,一干就是10多年.有时候就想,这样一直学习,coding,如果能干到老也挺不错的! 不过生活的压力是不会 ...