学习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. ...
随机推荐
- 【原创】MVC+ZTree实现权限树的功能
今天自己采用MVC+ZTree的技术实现权限树的功能,有需要的可以收藏一下. 1.需要引用的JS 文件 <link href="~/Content/ZTree/css/demo.css ...
- C#窗体加载和控件加载不同步导致控件闪烁
窗体加载和控件加载不同步导致的控件闪烁现象:// 代码块加在父窗体中的任意位置,解决窗体加载和控件加载不同步导致的控件闪烁问题 protected override CreatePara ...
- mongodb与spring mvc 整合
1.pom文件添加对mongodb的倚赖 <dependency> <groupId>org.mongodb</groupId> <artifactId> ...
- JVM-Ubuntu18.04.1下编译OpenJDK8
近期开始学习JVM,看的是周老师的<深入理解Java虚拟机>,打算先自己编译个JDK来提升对JVM的兴趣.本文分三部分来描述编译OpenJDK的过程,分别是编译前准备工作.构建编译环境.进 ...
- 构造方法为private与类修饰符为final
构造方法为private的:在这个类外1:不能继承这个类2:不能用new来产生这个类的实例 在这个类内:1:可以继承这个类2:可以用new来产生这个类的实例 类修饰符为final的:在这个类外1:不能 ...
- MySQL5.7: sql script demo
-- MyISAM Foreign Keys显示不了外键,MyISAM此为5.0 以下版本使用 InnoDB 为5.0以上版本使用 drop table IF EXISTS city; CREATE ...
- Django---ORM中的锁和事务
---恢复内容开始--- 一 锁 行级锁 select_for_update(nowait=False,skip_locked=False) #注意必须用在事务里面,至于如何开启事务,往后看 返回一 ...
- 2018-08-24 中文代码之Spring Boot对H2数据库简单查询
续前文: 中文代码之Spring Boot集成H2内存数据库 在词条中添加英文术语域: @Entity public class 词条 { @Id private long id; private S ...
- AI在汽车中的应用:实用深度学习
https://mp.weixin.qq.com/s/NIza8E5clC18eMF_4GMwDw 深度学习的“深度”层面源于输入层和输出层之间实现的隐含层数目,隐含层利用数学方法处理(筛选/卷积)各 ...
- python3 os模块
os模块就是对操作系统进行操作,这个模块提供了一种使用操作系统相关功能的可移植方式.1.系统信息 posix.uname_result(sysname='Linux', nodename='liang ...